Bug 1302682 - Crash [@ __memcpy_sse2_unaligned] with TypedArray. r=jonco
☠☠ backed out by 94812daa91cf ☠ ☠
authorSander Mathijs van Veen <sander@leaningtech.com>
Tue, 11 Oct 2016 18:21:26 +0300
changeset 360389 65b43a0e62b8ab0f6652fd2f8d3486422eb789e3
parent 360388 7eeb973656fa9465e1ed749a6fecdb388e9471cb
child 360390 b7d24b27dd3ddf11475824bc8213601ab416f916
push id6795
push userjlund@mozilla.com
push dateMon, 23 Jan 2017 14:19:46 +0000
treeherdermozilla-beta@76101b503191 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjonco
bugs1302682
milestone52.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 1302682 - Crash [@ __memcpy_sse2_unaligned] with TypedArray. r=jonco
js/src/jit-test/tests/basic/bug1302682.js
js/src/jsobj.cpp
js/src/vm/TypedArrayObject.cpp
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/bug1302682.js
@@ -0,0 +1,6 @@
+for (var i = 0; i < 30000; i++) {
+    var a = inIon() ? 7 : 300;
+    var buf = new Uint8ClampedArray(a);
+    (function() {}) * this;
+    try {} catch (e) {}
+}
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -3674,19 +3674,19 @@ JSObject::allocKindForTenure(const js::N
         return as<JSFunction>().getAllocKind();
 
     /*
      * Typed arrays in the nursery may have a lazily allocated buffer, make
      * sure there is room for the array's fixed data when moving the array.
      */
     if (is<TypedArrayObject>() && !as<TypedArrayObject>().hasBuffer()) {
         size_t nbytes = as<TypedArrayObject>().byteLength();
-        if (nbytes >= TypedArrayObject::INLINE_BUFFER_LIMIT)
-            return GetGCObjectKind(getClass());
-        return GetBackgroundAllocKind(TypedArrayObject::AllocKindForLazyBuffer(nbytes));
+        if (as<TypedArrayObject>().hasInlineElements())
+            return GetBackgroundAllocKind(TypedArrayObject::AllocKindForLazyBuffer(nbytes));
+        return GetGCObjectKind(getClass());
     }
 
     // Proxies that are CrossCompartmentWrappers may be nursery allocated.
     if (IsProxy(this))
         return as<ProxyObject>().allocKindForTenure();
 
     // Unboxed plain objects are sized according to the data they store.
     if (is<UnboxedPlainObject>()) {
--- a/js/src/vm/TypedArrayObject.cpp
+++ b/js/src/vm/TypedArrayObject.cpp
@@ -205,19 +205,22 @@ TypedArrayObject::objectMovedDuringMinor
         nbytes = oldObj->length() * sizeof(T); \
         break;
 JS_FOR_EACH_TYPED_ARRAY(OBJECT_MOVED_TYPED_ARRAY)
 #undef OBJECT_MOVED_TYPED_ARRAY
       default:
         MOZ_CRASH("Unsupported TypedArray type");
     }
 
-    if (dataOffset() + nbytes <= GetGCKindBytes(newAllocKind)) {
+    size_t headerSize = dataOffset() + sizeof(HeapSlot);
+    if (headerSize + nbytes <= GetGCKindBytes(newAllocKind)) {
+        MOZ_ASSERT(oldObj->hasInlineElements());
         newObj->setInlineElements();
     } else {
+        MOZ_ASSERT(!oldObj->hasInlineElements());
         AutoEnterOOMUnsafeRegion oomUnsafe;
         nbytes = JS_ROUNDUP(nbytes, sizeof(Value));
         void* data = newObj->zone()->pod_malloc<uint8_t>(nbytes);
         if (!data)
             oomUnsafe.crash("Failed to allocate typed array elements while tenuring.");
         MOZ_ASSERT(!nursery.isInside(data));
         newObj->initPrivate(data);
     }
@@ -230,17 +233,18 @@ JS_FOR_EACH_TYPED_ARRAY(OBJECT_MOVED_TYP
                                       /* direct = */nbytes >= sizeof(uintptr_t));
 
     return newObj->hasInlineElements() ? 0 : nbytes;
 }
 
 bool
 TypedArrayObject::hasInlineElements() const
 {
-    return elements() == this->fixedData(TypedArrayObject::FIXED_DATA_START);
+    return elements() == this->fixedData(TypedArrayObject::FIXED_DATA_START) &&
+        byteLength() <= TypedArrayObject::INLINE_BUFFER_LIMIT;
 }
 
 void
 TypedArrayObject::setInlineElements()
 {
     char* dataSlot = reinterpret_cast<char*>(this) + this->dataOffset();
     *reinterpret_cast<void**>(dataSlot) = this->fixedData(TypedArrayObject::FIXED_DATA_START);
 }
@@ -578,37 +582,42 @@ class TypedArrayObjectTemplate : public 
             return nullptr;
         if (script && !ObjectGroup::setAllocationSiteObjectGroup(cx, script, pc, tmp,
                                                                  newKind == SingletonObject))
         {
             return nullptr;
         }
 
         TypedArrayObject* tarray = &tmp->as<TypedArrayObject>();
+        initTypedArraySlots(cx, tarray, len);
+
         // Template objects do not need memory for its elements, since there
-        // won't be any elements to store. Therefore, we set the pointer to the
-        // inline data and avoid allocating memory that will never be used.
-        void* buf = tarray->fixedData(FIXED_DATA_START);
-        initTypedArraySlots(cx, tarray, len, buf, allocKind);
+        // won't be any elements to store. Therefore, we set the pointer to
+        // nullptr and avoid allocating memory that will never be used.
+        tarray->initPrivate(nullptr);
 
         return tarray;
     }
 
     static void
-    initTypedArraySlots(JSContext* cx, TypedArrayObject* tarray, int32_t len,
-                        void* buf, AllocKind allocKind)
+    initTypedArraySlots(JSContext* cx, TypedArrayObject* tarray, int32_t len)
     {
         MOZ_ASSERT(len >= 0);
         tarray->setFixedSlot(TypedArrayObject::BUFFER_SLOT, NullValue());
         tarray->setFixedSlot(TypedArrayObject::LENGTH_SLOT, Int32Value(AssertedCast<int32_t>(len)));
         tarray->setFixedSlot(TypedArrayObject::BYTEOFFSET_SLOT, Int32Value(0));
 
         // Verify that the private slot is at the expected place.
         MOZ_ASSERT(tarray->numFixedSlots() == TypedArrayObject::DATA_SLOT);
-
+    }
+
+    static void
+    initTypedArrayData(JSContext* cx, TypedArrayObject* tarray, int32_t len,
+                       void* buf, AllocKind allocKind)
+    {
         if (buf) {
 #ifdef DEBUG
             Nursery& nursery = cx->runtime()->gc.nursery;
             MOZ_ASSERT_IF(!nursery.isInside(buf) && !tarray->hasInlineElements(),
                           tarray->isTenured());
 #endif
             tarray->initPrivate(buf);
         } else {
@@ -659,17 +668,18 @@ class TypedArrayObjectTemplate : public 
             memset(buf, 0, nbytes);
          }
 
         RootedObject tmp(cx, NewObjectWithGroup<TypedArrayObject>(cx, group, allocKind, newKind));
         if (!tmp)
             return nullptr;
 
         TypedArrayObject* obj = &tmp->as<TypedArrayObject>();
-        initTypedArraySlots(cx, obj, len, buf.forget(), allocKind);
+        initTypedArraySlots(cx, obj, len);
+        initTypedArrayData(cx, obj, len, buf.forget(), allocKind);
 
         return obj;
     }
 
     /*
      * new [Type]Array(length)
      * new [Type]Array(otherTypedArray)
      * new [Type]Array(JSArray)