Title: [184452] releases/WebKitGTK/webkit-2.4
Revision
184452
Author
[email protected]
Date
2015-05-18 03:14:40 -0700 (Mon, 18 May 2015)

Log Message

Merge r175243 - Crash when attempting to perform array iteration on a non-array with numeric keys not initialized.
<https://webkit.org/b/137814>

Reviewed by Geoffrey Garen.

Source/_javascript_Core:

The arrayIteratorNextThunkGenerator() thunk was not checking for the case where
the butterfly may be NULL.  This was the source of the crash, and is now fixed.

In addition, it is also not checking for the case where a property named "length"
may have been set on the iterated object.  The thunk only checks the butterfly's
publicLength for its iteration operation.  Array objects will work fine with this
because it always updates its butterfly's publicLength when its length changes.
In the case of iterable non-Array objects, the "length" property will require a
look up outside of the scope of this thunk.  The fix is simply to limit the fast
case checks in this thunk to Array objects.

* jit/ThunkGenerators.cpp:
(JSC::arrayIteratorNextThunkGenerator):

LayoutTests:

* js/array-length-shortening-expected.txt: Added.
* js/array-length-shortening.html: Added.
* js/for-of-crash-expected.txt: Added.
* js/for-of-crash.html: Added.
* js/script-tests/array-length-shortening.js: Added.
(testLengthShortening):
(denseInt32Elements):
(denseDoubleElements):
(denseObjectElements):
(holeyInt32Elements):
(holeyDoubleElements):
(holeyObjectElements):
(arrayStorageInt32Elements):
(arrayStorageDoubleElements):
(arrayStorageObjectElements):
(sparseInt32Elements):
(sparseDoubleElements):
(sparseObjectElements):
* js/script-tests/for-of-crash.js: Added.
(foo):

Modified Paths

Added Paths

Diff

Modified: releases/WebKitGTK/webkit-2.4/LayoutTests/ChangeLog (184451 => 184452)


--- releases/WebKitGTK/webkit-2.4/LayoutTests/ChangeLog	2015-05-18 10:04:34 UTC (rev 184451)
+++ releases/WebKitGTK/webkit-2.4/LayoutTests/ChangeLog	2015-05-18 10:14:40 UTC (rev 184452)
@@ -1,3 +1,31 @@
+2014-10-27  Mark Lam  <[email protected]>
+
+        Crash when attempting to perform array iteration on a non-array with numeric keys not initialized.
+        <https://webkit.org/b/137814>
+
+        Reviewed by Geoffrey Garen.
+
+        * js/array-length-shortening-expected.txt: Added.
+        * js/array-length-shortening.html: Added.
+        * js/for-of-crash-expected.txt: Added.
+        * js/for-of-crash.html: Added.
+        * js/script-tests/array-length-shortening.js: Added.
+        (testLengthShortening):
+        (denseInt32Elements):
+        (denseDoubleElements):
+        (denseObjectElements):
+        (holeyInt32Elements):
+        (holeyDoubleElements):
+        (holeyObjectElements):
+        (arrayStorageInt32Elements):
+        (arrayStorageDoubleElements):
+        (arrayStorageObjectElements):
+        (sparseInt32Elements):
+        (sparseDoubleElements):
+        (sparseObjectElements):
+        * js/script-tests/for-of-crash.js: Added.
+        (foo):
+
 2014-10-22  Byungseon Shin  <[email protected]>
 
         String(new Date(Mar 30 2014 01:00:00)) is wrong in CET

Added: releases/WebKitGTK/webkit-2.4/LayoutTests/js/array-length-shortening-expected.txt (0 => 184452)


--- releases/WebKitGTK/webkit-2.4/LayoutTests/js/array-length-shortening-expected.txt	                        (rev 0)
+++ releases/WebKitGTK/webkit-2.4/LayoutTests/js/array-length-shortening-expected.txt	2015-05-18 10:14:40 UTC (rev 184452)
@@ -0,0 +1,33 @@
+Tests array length shortening.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS count is 1
+PASS count is 1
+PASS count is 1
+PASS count is 1
+PASS count is 1
+PASS count is 1
+PASS count is 1
+PASS count is 1
+PASS count is 1
+PASS count is 1
+PASS count is 1
+PASS count is 1
+PASS count is 1
+PASS count is 1
+PASS count is 1
+PASS count is 1
+PASS count is 1
+PASS count is 1
+PASS count is 1
+PASS count is 1
+PASS count is 1
+PASS count is 1
+PASS count is 1
+PASS count is 1
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: releases/WebKitGTK/webkit-2.4/LayoutTests/js/array-length-shortening.html (0 => 184452)


--- releases/WebKitGTK/webkit-2.4/LayoutTests/js/array-length-shortening.html	                        (rev 0)
+++ releases/WebKitGTK/webkit-2.4/LayoutTests/js/array-length-shortening.html	2015-05-18 10:14:40 UTC (rev 184452)
@@ -0,0 +1,10 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src=""
+</head>
+<body>
+<script src=""
+<script src=""
+</body>
+</html>

Added: releases/WebKitGTK/webkit-2.4/LayoutTests/js/for-of-crash-expected.txt (0 => 184452)


--- releases/WebKitGTK/webkit-2.4/LayoutTests/js/for-of-crash-expected.txt	                        (rev 0)
+++ releases/WebKitGTK/webkit-2.4/LayoutTests/js/for-of-crash-expected.txt	2015-05-18 10:14:40 UTC (rev 184452)
@@ -0,0 +1,9 @@
+Tests that for-of iteration does not crashes.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: releases/WebKitGTK/webkit-2.4/LayoutTests/js/for-of-crash.html (0 => 184452)


--- releases/WebKitGTK/webkit-2.4/LayoutTests/js/for-of-crash.html	                        (rev 0)
+++ releases/WebKitGTK/webkit-2.4/LayoutTests/js/for-of-crash.html	2015-05-18 10:14:40 UTC (rev 184452)
@@ -0,0 +1,10 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src=""
+</head>
+<body>
+<script src=""
+<script src=""
+</body>
+</html>

Added: releases/WebKitGTK/webkit-2.4/LayoutTests/js/script-tests/array-length-shortening.js (0 => 184452)


--- releases/WebKitGTK/webkit-2.4/LayoutTests/js/script-tests/array-length-shortening.js	                        (rev 0)
+++ releases/WebKitGTK/webkit-2.4/LayoutTests/js/script-tests/array-length-shortening.js	2015-05-18 10:14:40 UTC (rev 184452)
@@ -0,0 +1,126 @@
+description(
+"Tests array length shortening."
+);
+
+var count;
+
+function testLengthShortening(array) {
+    array.length = 1;
+    count = 0;
+    for (var x of array) {
+        count++;
+    }
+
+    shouldBe("count", "1");
+}
+
+var arr;
+
+// Test Objects with densely packed indexed properties:
+function denseInt32Elements(arr) {
+    arr[0] = 1;
+    arr[1] = 2;
+    return arr;
+}
+testLengthShortening(denseInt32Elements(Object.create(Array.prototype)));
+testLengthShortening(denseInt32Elements([]));
+
+function denseDoubleElements(arr) {
+    arr[0] = 1.5;
+    arr[1] = 2.5;
+    return arr;
+}
+testLengthShortening(denseDoubleElements(Object.create(Array.prototype)));
+testLengthShortening(denseDoubleElements([]));
+
+function denseObjectElements(arr) {
+    arr[0] = {};
+    arr[1] = {};
+    return arr;
+}
+testLengthShortening(denseObjectElements(Object.create(Array.prototype)));
+testLengthShortening(denseObjectElements([]));
+
+// Test Objects with hole-y indexed properties:
+function holeyInt32Elements(arr) {
+    arr[0] = 1;
+    arr[1] = 2;
+    arr[4] = 4;
+    return arr;
+}
+testLengthShortening(holeyInt32Elements(Object.create(Array.prototype)));
+testLengthShortening(holeyInt32Elements([]));
+
+function holeyDoubleElements(arr) {
+    arr[0] = 1.5;
+    arr[1] = 2.5;
+    arr[4] = 4.5;
+    return arr;
+}
+testLengthShortening(holeyDoubleElements(Object.create(Array.prototype)));
+testLengthShortening(holeyDoubleElements([]));
+
+function holeyObjectElements(arr) {
+    arr[0] = {};
+    arr[1] = {};
+    arr[4] = {};
+    return arr;
+}
+testLengthShortening(holeyObjectElements(Object.create(Array.prototype)));
+testLengthShortening(holeyObjectElements([]));
+
+// Test Objects with ArrayStorage indexed properties:
+function arrayStorageInt32Elements(arr) {
+    arr[0] = 1;
+    arr[1] = 2;
+    arr.unshift(100); // Force conversion to using ArrayStorage.
+    return arr;
+}
+testLengthShortening(arrayStorageInt32Elements(Object.create(Array.prototype)));
+testLengthShortening(arrayStorageInt32Elements([]));
+
+function arrayStorageDoubleElements(arr) {
+    arr[0] = 1.5;
+    arr[1] = 2.5;
+    arr.unshift(100.5); // Force conversion to using ArrayStorage.
+    return arr;
+}
+testLengthShortening(arrayStorageDoubleElements(Object.create(Array.prototype)));
+testLengthShortening(arrayStorageDoubleElements([]));
+
+function arrayStorageObjectElements(arr) {
+    arr[0] = {};
+    arr[1] = {};
+    arr.unshift({}); // Force conversion to using ArrayStorage.
+    return arr;
+}
+testLengthShortening(arrayStorageObjectElements(Object.create(Array.prototype)));
+testLengthShortening(arrayStorageObjectElements([]));
+
+// Test Objects with sparse indexed properties:
+function sparseInt32Elements(arr) {
+    arr[0] = 1;
+    arr[1] = 2;
+    arr[100000] = 100;
+    return arr;
+}
+testLengthShortening(sparseInt32Elements(Object.create(Array.prototype)));
+testLengthShortening(sparseInt32Elements([]));
+
+function sparseDoubleElements(arr) {
+    arr[0] = 1.5;
+    arr[1] = 2.5;
+    arr[100000] = 100.5;
+    return arr;
+}
+testLengthShortening(sparseDoubleElements(Object.create(Array.prototype)));
+testLengthShortening(sparseDoubleElements([]));
+
+function sparseObjectElements(arr) {
+    arr[0] = {};
+    arr[1] = {};
+    arr[100000] = {};
+    return arr;
+}
+testLengthShortening(sparseObjectElements(Object.create(Array.prototype)));
+testLengthShortening(sparseObjectElements([]));

Added: releases/WebKitGTK/webkit-2.4/LayoutTests/js/script-tests/for-of-crash.js (0 => 184452)


--- releases/WebKitGTK/webkit-2.4/LayoutTests/js/script-tests/for-of-crash.js	                        (rev 0)
+++ releases/WebKitGTK/webkit-2.4/LayoutTests/js/script-tests/for-of-crash.js	2015-05-18 10:14:40 UTC (rev 184452)
@@ -0,0 +1,10 @@
+description(
+"Tests that for-of iteration does not crashes."
+);
+
+function foo() {
+    var o = Object.create(Array.prototype);
+    for (var x of o) {
+    }
+}
+foo();

Modified: releases/WebKitGTK/webkit-2.4/Source/_javascript_Core/ChangeLog (184451 => 184452)


--- releases/WebKitGTK/webkit-2.4/Source/_javascript_Core/ChangeLog	2015-05-18 10:04:34 UTC (rev 184451)
+++ releases/WebKitGTK/webkit-2.4/Source/_javascript_Core/ChangeLog	2015-05-18 10:14:40 UTC (rev 184452)
@@ -1,3 +1,24 @@
+2014-10-27  Mark Lam  <[email protected]>
+
+        Crash when attempting to perform array iteration on a non-array with numeric keys not initialized.
+        <https://webkit.org/b/137814>
+
+        Reviewed by Geoffrey Garen.
+
+        The arrayIteratorNextThunkGenerator() thunk was not checking for the case where
+        the butterfly may be NULL.  This was the source of the crash, and is now fixed.
+
+        In addition, it is also not checking for the case where a property named "length"
+        may have been set on the iterated object.  The thunk only checks the butterfly's
+        publicLength for its iteration operation.  Array objects will work fine with this
+        because it always updates its butterfly's publicLength when its length changes.
+        In the case of iterable non-Array objects, the "length" property will require a
+        look up outside of the scope of this thunk.  The fix is simply to limit the fast
+        case checks in this thunk to Array objects.
+
+        * jit/ThunkGenerators.cpp:
+        (JSC::arrayIteratorNextThunkGenerator):
+
 2014-10-22  Byungseon Shin  <[email protected]>
 
         String(new Date(Mar 30 2014 01:00:00)) is wrong in CET

Modified: releases/WebKitGTK/webkit-2.4/Source/_javascript_Core/jit/ThunkGenerators.cpp (184451 => 184452)


--- releases/WebKitGTK/webkit-2.4/Source/_javascript_Core/jit/ThunkGenerators.cpp	2015-05-18 10:04:34 UTC (rev 184451)
+++ releases/WebKitGTK/webkit-2.4/Source/_javascript_Core/jit/ThunkGenerators.cpp	2015-05-18 10:14:40 UTC (rev 184452)
@@ -972,10 +972,12 @@
     
     jit.load8(Address(SpecializedThunkJIT::regT2, Structure::indexingTypeOffset()), SpecializedThunkJIT::regT3);
     jit.loadPtr(Address(SpecializedThunkJIT::regT0, JSObject::butterflyOffset()), SpecializedThunkJIT::regT2);
+    Jump nullButterfly = jit.branchTestPtr(SpecializedThunkJIT::Zero, SpecializedThunkJIT::regT2);
     
-    jit.and32(TrustedImm32(IndexingShapeMask), SpecializedThunkJIT::regT3);
+    Jump notDone = jit.branch32(SpecializedThunkJIT::Below, SpecializedThunkJIT::regT1, Address(SpecializedThunkJIT::regT2, Butterfly::offsetOfPublicLength()));
 
-    Jump notDone = jit.branch32(SpecializedThunkJIT::Below, SpecializedThunkJIT::regT1, Address(SpecializedThunkJIT::regT2, Butterfly::offsetOfPublicLength()));
+    nullButterfly.link(&jit);
+
     // Return the termination signal to indicate that we've finished
     jit.move(TrustedImmPtr(vm->iterationTerminator.get()), SpecializedThunkJIT::regT0);
     jit.returnJSCell(SpecializedThunkJIT::regT0);
@@ -994,8 +996,8 @@
     jit.appendFailure(jit.branch32(SpecializedThunkJIT::AboveOrEqual, SpecializedThunkJIT::regT1, Address(SpecializedThunkJIT::regT2, Butterfly::offsetOfVectorLength())));
     
     // So now we perform inline loads for int32, value/undecided, and double storage
-    Jump undecidedStorage = jit.branch32(SpecializedThunkJIT::Equal, SpecializedThunkJIT::regT3, TrustedImm32(UndecidedShape));
-    Jump notContiguousStorage = jit.branch32(SpecializedThunkJIT::NotEqual, SpecializedThunkJIT::regT3, TrustedImm32(ContiguousShape));
+    Jump undecidedStorage = jit.branch32(SpecializedThunkJIT::Equal, SpecializedThunkJIT::regT3, TrustedImm32(ArrayWithUndecided));
+    Jump notContiguousStorage = jit.branch32(SpecializedThunkJIT::NotEqual, SpecializedThunkJIT::regT3, TrustedImm32(ArrayWithContiguous));
     
     undecidedStorage.link(&jit);
     
@@ -1023,14 +1025,14 @@
 #endif
     notContiguousStorage.link(&jit);
     
-    Jump notInt32Storage = jit.branch32(SpecializedThunkJIT::NotEqual, SpecializedThunkJIT::regT3, TrustedImm32(Int32Shape));
+    Jump notInt32Storage = jit.branch32(SpecializedThunkJIT::NotEqual, SpecializedThunkJIT::regT3, TrustedImm32(ArrayWithInt32));
     jit.loadPtr(Address(SpecializedThunkJIT::regT0, JSObject::butterflyOffset()), SpecializedThunkJIT::regT2);
     jit.load32(BaseIndex(SpecializedThunkJIT::regT2, SpecializedThunkJIT::regT1, SpecializedThunkJIT::TimesEight, JSValue::offsetOfPayload()), SpecializedThunkJIT::regT0);
     jit.add32(TrustedImm32(1), Address(SpecializedThunkJIT::regT4, JSArrayIterator::offsetOfNextIndex()));
     jit.returnInt32(SpecializedThunkJIT::regT0);
     notInt32Storage.link(&jit);
     
-    jit.appendFailure(jit.branch32(SpecializedThunkJIT::NotEqual, SpecializedThunkJIT::regT3, TrustedImm32(DoubleShape)));
+    jit.appendFailure(jit.branch32(SpecializedThunkJIT::NotEqual, SpecializedThunkJIT::regT3, TrustedImm32(ArrayWithDouble)));
     jit.loadPtr(Address(SpecializedThunkJIT::regT0, JSObject::butterflyOffset()), SpecializedThunkJIT::regT2);
     jit.loadDouble(BaseIndex(SpecializedThunkJIT::regT2, SpecializedThunkJIT::regT1, SpecializedThunkJIT::TimesEight), SpecializedThunkJIT::fpRegT0);
     jit.add32(TrustedImm32(1), Address(SpecializedThunkJIT::regT4, JSArrayIterator::offsetOfNextIndex()));
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to