Bug 1240416 Disallow setting GC mark stack size to zero, and assert on attempt to realloc() zero bytes r=terrence
authorJon Coppeard <jcoppeard@mozilla.com>
Wed, 20 Jan 2016 10:13:14 +0000
changeset 317734 16c99d1a006f21da97aa61377a164b49e18ea1d1
parent 317733 05d2f38a2544d792c0a4cf59f73f05778251e248
child 317735 14854a8f77dc201da02d4a7fad88f68032ba58b2
push id1079
push userjlund@mozilla.com
push dateFri, 15 Apr 2016 21:02:33 +0000
treeherdermozilla-release@575fbf6786d5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersterrence
bugs1240416
milestone46.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1240416 Disallow setting GC mark stack size to zero, and assert on attempt to realloc() zero bytes r=terrence
js/public/Utility.h
js/src/gc/Marking.cpp
js/src/jit-test/tests/gc/bug-1240416.js
js/src/jsgc.cpp
--- a/js/public/Utility.h
+++ b/js/public/Utility.h
@@ -230,16 +230,21 @@ static inline void* js_calloc(size_t byt
 static inline void* js_calloc(size_t nmemb, size_t size)
 {
     JS_OOM_POSSIBLY_FAIL();
     return calloc(nmemb, size);
 }
 
 static inline void* js_realloc(void* p, size_t bytes)
 {
+    // realloc() with zero size is not portable, as some implementations may
+    // return nullptr on success and free |p| for this.  We assume nullptr
+    // indicates failure and that |p| is still valid.
+    MOZ_ASSERT(bytes != 0);
+
     JS_OOM_POSSIBLY_FAIL();
     return realloc(p, bytes);
 }
 
 static inline void js_free(void* p)
 {
     free(p);
 }
--- a/js/src/gc/Marking.cpp
+++ b/js/src/gc/Marking.cpp
@@ -1684,16 +1684,17 @@ MarkStack::setBaseCapacity(JSGCMode mode
 
     if (baseCapacity_ > maxCapacity_)
         baseCapacity_ = maxCapacity_;
 }
 
 void
 MarkStack::setMaxCapacity(size_t maxCapacity)
 {
+    MOZ_ASSERT(maxCapacity != 0);
     MOZ_ASSERT(isEmpty());
     maxCapacity_ = maxCapacity;
     if (baseCapacity_ > maxCapacity_)
         baseCapacity_ = maxCapacity_;
 
     reset();
 }
 
@@ -1701,16 +1702,17 @@ void
 MarkStack::reset()
 {
     if (capacity() == baseCapacity_) {
         // No size change; keep the current stack.
         setStack(stack_, 0, baseCapacity_);
         return;
     }
 
+    MOZ_ASSERT(baseCapacity_ != 0);
     uintptr_t* newStack = (uintptr_t*)js_realloc(stack_, sizeof(uintptr_t) * baseCapacity_);
     if (!newStack) {
         // If the realloc fails, just keep using the existing stack; it's
         // not ideal but better than failing.
         newStack = stack_;
         baseCapacity_ = capacity();
     }
     setStack(newStack, 0, baseCapacity_);
@@ -1720,16 +1722,17 @@ bool
 MarkStack::enlarge(unsigned count)
 {
     size_t newCapacity = Min(maxCapacity_, capacity() * 2);
     if (newCapacity < capacity() + count)
         return false;
 
     size_t tosIndex = position();
 
+    MOZ_ASSERT(newCapacity != 0);
     uintptr_t* newStack = (uintptr_t*)js_realloc(stack_, sizeof(uintptr_t) * newCapacity);
     if (!newStack)
         return false;
 
     setStack(newStack, tosIndex, newCapacity);
     return true;
 }
 
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/gc/bug-1240416.js
@@ -0,0 +1,2 @@
+// |jit-test| error: Error
+gcparam('markStackLimit', 0);
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -1409,16 +1409,18 @@ GCRuntime::setParameter(JSGCParamKey key
         setMaxMallocBytes(value);
         for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next())
             zone->setGCMaxMallocBytes(maxMallocBytesAllocated() * 0.9);
         break;
       case JSGC_SLICE_TIME_BUDGET:
         defaultTimeBudget_ = value ? value : SliceBudget::UnlimitedTimeBudget;
         break;
       case JSGC_MARK_STACK_LIMIT:
+        if (value == 0)
+            return false;
         setMarkStackLimit(value, lock);
         break;
       case JSGC_DECOMMIT_THRESHOLD:
         decommitThreshold = (uint64_t)value * 1024 * 1024;
         break;
       case JSGC_MODE:
         if (mode != JSGC_MODE_GLOBAL &&
             mode != JSGC_MODE_COMPARTMENT &&