Fix exception scope verification failures in JSArray* files.
authormark.lam@apple.com <mark.lam@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 28 Nov 2016 23:50:16 +0000 (23:50 +0000)
committermark.lam@apple.com <mark.lam@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 28 Nov 2016 23:50:16 +0000 (23:50 +0000)
https://bugs.webkit.org/show_bug.cgi?id=165016

Reviewed by Saam Barati.

* runtime/JSArray.cpp:
(JSC::JSArray::defineOwnProperty):
(JSC::JSArray::put):
(JSC::JSArray::setLength):
(JSC::JSArray::pop):
(JSC::JSArray::push):
(JSC::JSArray::unshiftCountWithAnyIndexingType):
* runtime/JSArrayBuffer.cpp:
(JSC::JSArrayBuffer::put):
(JSC::JSArrayBuffer::defineOwnProperty):
* runtime/JSArrayInlines.h:
(JSC::getLength):
(JSC::toLength):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@209036 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/runtime/JSArray.cpp
Source/JavaScriptCore/runtime/JSArrayBuffer.cpp
Source/JavaScriptCore/runtime/JSArrayInlines.h

index 86f66ce16e08129794ed943313e630966b97d07a..8396618369d6f3dc9a845b14c1a68d97b7c6fc75 100644 (file)
@@ -1,3 +1,24 @@
+2016-11-28  Mark Lam  <mark.lam@apple.com>
+
+        Fix exception scope verification failures in JSArray* files.
+        https://bugs.webkit.org/show_bug.cgi?id=165016
+
+        Reviewed by Saam Barati.
+
+        * runtime/JSArray.cpp:
+        (JSC::JSArray::defineOwnProperty):
+        (JSC::JSArray::put):
+        (JSC::JSArray::setLength):
+        (JSC::JSArray::pop):
+        (JSC::JSArray::push):
+        (JSC::JSArray::unshiftCountWithAnyIndexingType):
+        * runtime/JSArrayBuffer.cpp:
+        (JSC::JSArrayBuffer::put):
+        (JSC::JSArrayBuffer::defineOwnProperty):
+        * runtime/JSArrayInlines.h:
+        (JSC::getLength):
+        (JSC::toLength):
+
 2016-11-28  Mark Lam  <mark.lam@apple.com>
 
         Fix exception scope verification failures in JSDataView.cpp.
index 518722692d2082de843a7ea9f9bcc5b201ad733f..3e0de4996feafa48d8a20b7cc23d8f054bc81b53 100644 (file)
@@ -186,7 +186,9 @@ bool JSArray::defineOwnProperty(JSObject* object, ExecState* exec, PropertyName
         // l.i. Set oldLen to oldLen – 1.
         // l.ii. Let deleteSucceeded be the result of calling the [[Delete]] internal method of A passing ToString(oldLen) and false as arguments.
         // l.iii. If deleteSucceeded is false, then
-        if (!array->setLength(exec, newLen, throwException)) {
+        bool success = array->setLength(exec, newLen, throwException);
+        ASSERT(!scope.exception() || !success);
+        if (!success) {
             // 1. Set newLenDesc.[[Value] to oldLen+1.
             // 2. If newWritable is false, set newLenDesc.[[Writable] to false.
             // 3. Call the default [[DefineOwnProperty]] internal method (8.12.9) on A passing "length", newLenDesc, and false as arguments.
@@ -220,9 +222,11 @@ bool JSArray::defineOwnProperty(JSObject* object, ExecState* exec, PropertyName
         // e.i. Set oldLenDesc.[[Value]] to index + 1.
         // e.ii. Call the default [[DefineOwnProperty]] internal method (8.12.9) on A passing "length", oldLenDesc, and false as arguments. This call will always return true.
         // f. Return true.
+        scope.release();
         return array->defineOwnIndexedProperty(exec, index, descriptor, throwException);
     }
 
+    scope.release();
     return array->JSObject::defineOwnNonIndexProperty(exec, propertyName, descriptor, throwException);
 }
 
@@ -246,18 +250,23 @@ bool JSArray::put(JSCell* cell, ExecState* exec, PropertyName propertyName, JSVa
 
     JSArray* thisObject = jsCast<JSArray*>(cell);
 
-    if (UNLIKELY(isThisValueAltered(slot, thisObject)))
+    if (UNLIKELY(isThisValueAltered(slot, thisObject))) {
+        scope.release();
         return ordinarySetSlow(exec, thisObject, propertyName, value, slot.thisValue(), slot.isStrictMode());
+    }
 
     if (propertyName == exec->propertyNames().length) {
         unsigned newLength = value.toUInt32(exec);
+        RETURN_IF_EXCEPTION(scope, false);
         if (value.toNumber(exec) != static_cast<double>(newLength)) {
             throwException(exec, scope, createRangeError(exec, ASCIILiteral("Invalid array length")));
             return false;
         }
+        scope.release();
         return thisObject->setLength(exec, newLength, slot.isStrictMode());
     }
 
+    scope.release();
     return JSObject::put(thisObject, exec, propertyName, value, slot);
 }
 
@@ -517,6 +526,7 @@ bool JSArray::setLength(ExecState* exec, unsigned newLength, bool throwException
         if (!newLength)
             return true;
         if (newLength >= MIN_SPARSE_ARRAY_INDEX) {
+            scope.release();
             return setLengthWithArrayStorage(
                 exec, newLength, throwException,
                 ensureArrayStorage(vm));
@@ -533,6 +543,7 @@ bool JSArray::setLength(ExecState* exec, unsigned newLength, bool throwException
         if (newLength >= MAX_ARRAY_INDEX // This case ensures that we can do fast push.
             || (newLength >= MIN_SPARSE_ARRAY_INDEX
                 && !isDenseEnoughForVector(newLength, countElements()))) {
+            scope.release();
             return setLengthWithArrayStorage(
                 exec, newLength, throwException,
                 ensureArrayStorage(vm));
@@ -565,6 +576,7 @@ bool JSArray::setLength(ExecState* exec, unsigned newLength, bool throwException
         
     case ArrayWithArrayStorage:
     case ArrayWithSlowPutArrayStorage:
+        scope.release();
         return setLengthWithArrayStorage(exec, newLength, throwException, arrayStorage());
         
     default:
@@ -659,11 +671,14 @@ JSValue JSArray::pop(ExecState* exec)
     JSValue element = get(exec, index);
     RETURN_IF_EXCEPTION(scope, JSValue());
     // Call the [[Delete]] internal method of O with arguments indx and true.
-    if (!deletePropertyByIndex(this, exec, index)) {
+    bool success = deletePropertyByIndex(this, exec, index);
+    RETURN_IF_EXCEPTION(scope, JSValue());
+    if (!success) {
         throwTypeError(exec, scope, ASCIILiteral(UnableToDeletePropertyError));
         return jsUndefined();
     }
     // Call the [[Put]] internal method of O with arguments "length", indx, and true.
+    scope.release();
     setLength(exec, index, true);
     // Return element.
     return element;
@@ -687,6 +702,7 @@ void JSArray::push(ExecState* exec, JSValue value)
         
     case ArrayWithUndecided: {
         convertUndecidedForValue(vm, value);
+        scope.release();
         push(exec, value);
         return;
     }
@@ -694,6 +710,7 @@ void JSArray::push(ExecState* exec, JSValue value)
     case ArrayWithInt32: {
         if (!value.isInt32()) {
             convertInt32ForValue(vm, value);
+            scope.release();
             push(exec, value);
             return;
         }
@@ -706,13 +723,14 @@ void JSArray::push(ExecState* exec, JSValue value)
             return;
         }
         
-        if (length > MAX_ARRAY_INDEX) {
+        if (UNLIKELY(length > MAX_ARRAY_INDEX)) {
             methodTable(vm)->putByIndex(this, exec, length, value, true);
             if (!scope.exception())
                 throwException(exec, scope, createRangeError(exec, ASCIILiteral("Invalid array length")));
             return;
         }
-        
+
+        scope.release();
         putByIndexBeyondVectorLengthWithoutAttributes<Int32Shape>(exec, length, value);
         return;
     }
@@ -726,13 +744,14 @@ void JSArray::push(ExecState* exec, JSValue value)
             return;
         }
         
-        if (length > MAX_ARRAY_INDEX) {
+        if (UNLIKELY(length > MAX_ARRAY_INDEX)) {
             methodTable(vm)->putByIndex(this, exec, length, value, true);
             if (!scope.exception())
                 throwException(exec, scope, createRangeError(exec, ASCIILiteral("Invalid array length")));
             return;
         }
-        
+
+        scope.release();
         putByIndexBeyondVectorLengthWithoutAttributes<ContiguousShape>(exec, length, value);
         return;
     }
@@ -740,12 +759,14 @@ void JSArray::push(ExecState* exec, JSValue value)
     case ArrayWithDouble: {
         if (!value.isNumber()) {
             convertDoubleToContiguous(vm);
+            scope.release();
             push(exec, value);
             return;
         }
         double valueAsDouble = value.asNumber();
         if (valueAsDouble != valueAsDouble) {
             convertDoubleToContiguous(vm);
+            scope.release();
             push(exec, value);
             return;
         }
@@ -758,23 +779,26 @@ void JSArray::push(ExecState* exec, JSValue value)
             return;
         }
         
-        if (length > MAX_ARRAY_INDEX) {
+        if (UNLIKELY(length > MAX_ARRAY_INDEX)) {
             methodTable(vm)->putByIndex(this, exec, length, value, true);
             if (!scope.exception())
                 throwException(exec, scope, createRangeError(exec, ASCIILiteral("Invalid array length")));
             return;
         }
-        
+
+        scope.release();
         putByIndexBeyondVectorLengthWithoutAttributes<DoubleShape>(exec, length, value);
-        break;
+        return;
     }
         
     case ArrayWithSlowPutArrayStorage: {
         unsigned oldLength = length();
         bool putResult = false;
         if (attemptToInterceptPutByIndexOnHole(exec, oldLength, value, true, putResult)) {
-            if (!scope.exception() && oldLength < 0xFFFFFFFFu)
+            if (!scope.exception() && oldLength < 0xFFFFFFFFu) {
+                scope.release();
                 setLength(exec, oldLength + 1, true);
+            }
             return;
         }
         FALLTHROUGH;
@@ -793,7 +817,7 @@ void JSArray::push(ExecState* exec, JSValue value)
         }
 
         // Pushing to an array of invalid length (2^31-1) stores the property, but throws a range error.
-        if (storage->length() > MAX_ARRAY_INDEX) {
+        if (UNLIKELY(storage->length() > MAX_ARRAY_INDEX)) {
             methodTable(vm)->putByIndex(this, exec, storage->length(), value, true);
             // Per ES5.1 15.4.4.7 step 6 & 15.4.5.1 step 3.d.
             if (!scope.exception())
@@ -802,8 +826,9 @@ void JSArray::push(ExecState* exec, JSValue value)
         }
 
         // Handled the same as putIndex.
+        scope.release();
         putByIndexBeyondVectorLengthWithArrayStorage(exec, storage->length(), value, true, storage);
-        break;
+        return;
     }
         
     default:
@@ -1117,8 +1142,10 @@ bool JSArray::unshiftCountWithAnyIndexingType(ExecState* exec, unsigned startInd
         
         // We may have to walk the entire array to do the unshift. We're willing to do so
         // only if it's not horribly slow.
-        if (oldLength - startIndex >= MIN_SPARSE_ARRAY_INDEX)
+        if (oldLength - startIndex >= MIN_SPARSE_ARRAY_INDEX) {
+            scope.release();
             return unshiftCountWithArrayStorage(exec, startIndex, count, ensureArrayStorage(vm));
+        }
         
         if (!ensureLength(vm, oldLength + count)) {
             throwOutOfMemoryError(exec, scope);
@@ -1130,8 +1157,10 @@ bool JSArray::unshiftCountWithAnyIndexingType(ExecState* exec, unsigned startInd
         // through shifting and then realize we should have been in ArrayStorage mode.
         for (unsigned i = oldLength; i-- > startIndex;) {
             JSValue v = butterfly->contiguous()[i].get();
-            if (UNLIKELY(!v))
+            if (UNLIKELY(!v)) {
+                scope.release();
                 return unshiftCountWithArrayStorage(exec, startIndex, count, ensureArrayStorage(vm));
+            }
         }
 
         for (unsigned i = oldLength; i-- > startIndex;) {
@@ -1153,8 +1182,10 @@ bool JSArray::unshiftCountWithAnyIndexingType(ExecState* exec, unsigned startInd
         
         // We may have to walk the entire array to do the unshift. We're willing to do so
         // only if it's not horribly slow.
-        if (oldLength - startIndex >= MIN_SPARSE_ARRAY_INDEX)
+        if (oldLength - startIndex >= MIN_SPARSE_ARRAY_INDEX) {
+            scope.release();
             return unshiftCountWithArrayStorage(exec, startIndex, count, ensureArrayStorage(vm));
+        }
         
         if (!ensureLength(vm, oldLength + count)) {
             throwOutOfMemoryError(exec, scope);
@@ -1166,8 +1197,10 @@ bool JSArray::unshiftCountWithAnyIndexingType(ExecState* exec, unsigned startInd
         // through shifting and then realize we should have been in ArrayStorage mode.
         for (unsigned i = oldLength; i-- > startIndex;) {
             double v = butterfly->contiguousDouble()[i];
-            if (UNLIKELY(v != v))
+            if (UNLIKELY(v != v)) {
+                scope.release();
                 return unshiftCountWithArrayStorage(exec, startIndex, count, ensureArrayStorage(vm));
+            }
         }
 
         for (unsigned i = oldLength; i-- > startIndex;) {
@@ -1186,6 +1219,7 @@ bool JSArray::unshiftCountWithAnyIndexingType(ExecState* exec, unsigned startInd
         
     case ArrayWithArrayStorage:
     case ArrayWithSlowPutArrayStorage:
+        scope.release();
         return unshiftCountWithArrayStorage(exec, startIndex, count, arrayStorage());
         
     default:
index 38c0d0648a6d11df6a18f29ca2fd5c57cd585480..23540da0a96c648f0e6186d5df4392a39ebeb74f 100644 (file)
@@ -106,12 +106,15 @@ bool JSArrayBuffer::put(
     auto scope = DECLARE_THROW_SCOPE(vm);
     JSArrayBuffer* thisObject = jsCast<JSArrayBuffer*>(cell);
 
-    if (UNLIKELY(isThisValueAltered(slot, thisObject)))
+    if (UNLIKELY(isThisValueAltered(slot, thisObject))) {
+        scope.release();
         return ordinarySetSlow(exec, thisObject, propertyName, value, slot.thisValue(), slot.isStrictMode());
+    }
     
     if (propertyName == vm.propertyNames->byteLength)
         return typeError(exec, scope, slot.isStrictMode(), ASCIILiteral("Attempting to write to a read-only array buffer property."));
-    
+
+    scope.release();
     return Base::put(thisObject, exec, propertyName, value, slot);
 }
 
@@ -125,7 +128,8 @@ bool JSArrayBuffer::defineOwnProperty(
     
     if (propertyName == vm.propertyNames->byteLength)
         return typeError(exec, scope, shouldThrow, ASCIILiteral("Attempting to define read-only array buffer property."));
-    
+
+    scope.release();
     return Base::defineOwnProperty(thisObject, exec, propertyName, descriptor, shouldThrow);
 }
 
index 0b0e71f32fdecb88d354f07d619617d87d46344c..8465177b0e2c43a2ed45a655648fa70baed6dba0 100644 (file)
@@ -76,6 +76,7 @@ ALWAYS_INLINE unsigned getLength(ExecState* exec, JSObject* obj)
 
     JSValue lengthValue = obj->get(exec, vm.propertyNames->length);
     RETURN_IF_EXCEPTION(scope, UINT_MAX);
+    scope.release();
     return lengthValue.toUInt32(exec);
 }
 
@@ -88,6 +89,7 @@ ALWAYS_INLINE double toLength(ExecState* exec, JSObject* obj)
 
     JSValue lengthValue = obj->get(exec, vm.propertyNames->length);
     RETURN_IF_EXCEPTION(scope, PNaN);
+    scope.release();
     return lengthValue.toLength(exec);
 }