Title: [183694] trunk
Revision
183694
Author
[email protected]
Date
2015-05-01 15:44:30 -0700 (Fri, 01 May 2015)

Log Message

String#startsWith/endsWith/includes don't handle Infinity position/endPosition args correctly
https://bugs.webkit.org/show_bug.cgi?id=144314

Patch by Jordan Harband <[email protected]> on 2015-05-01
Reviewed by Darin Adler.

Source/_javascript_Core:

Fixing handling of Infinity position args, per
https://people.mozilla.org/~jorendorff/es6-draft.html#sec-string.prototype.includes
https://people.mozilla.org/~jorendorff/es6-draft.html#sec-string.prototype.startswith
https://people.mozilla.org/~jorendorff/es6-draft.html#sec-string.prototype.endswith

* runtime/StringPrototype.cpp:
(JSC::clampInt32):
(JSC::stringProtoFuncStartsWith):
(JSC::stringProtoFuncEndsWith):
(JSC::stringProtoFuncIncludes):

LayoutTests:

* js/script-tests/string-includes.js:
* js/string-includes-expected.txt:

Modified Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (183693 => 183694)


--- trunk/LayoutTests/ChangeLog	2015-05-01 22:38:02 UTC (rev 183693)
+++ trunk/LayoutTests/ChangeLog	2015-05-01 22:44:30 UTC (rev 183694)
@@ -1,3 +1,13 @@
+2015-05-01  Jordan Harband  <[email protected]>
+
+        String#startsWith/endsWith/includes don't handle Infinity position/endPosition args correctly
+        https://bugs.webkit.org/show_bug.cgi?id=144314
+
+        Reviewed by Darin Adler.
+
+        * js/script-tests/string-includes.js:
+        * js/string-includes-expected.txt:
+
 2015-05-01  Martin Robinson  <[email protected]>
 
         Unreviewed gardening for GTK+.

Modified: trunk/LayoutTests/js/script-tests/string-includes.js (183693 => 183694)


--- trunk/LayoutTests/js/script-tests/string-includes.js	2015-05-01 22:38:02 UTC (rev 183693)
+++ trunk/LayoutTests/js/script-tests/string-includes.js	2015-05-01 22:44:30 UTC (rev 183694)
@@ -1,6 +1,7 @@
-description("This test checks the ES6 string functions startsWith(), endsWith() and includes().");
+description("This test checks the ES6 string functions startsWith(), endsWith(), and includes().");
 
 // Test includes
+shouldBe("String.prototype.includes.name", "'includes'");
 shouldBe("String.prototype.includes.length", "1");
 shouldBe("'foo bar'.includes('bar')", "true");
 shouldBe("'foo bar'.includes('bar', 4)", "true");
@@ -30,8 +31,16 @@
 shouldBe("'foo 1e100 bar'.includes(1e100)", "false");
 shouldBe("'フーバー'.includes('ーバ')", "true");
 shouldBe("'フーバー'.includes('クー')", "false");
+shouldBeFalse("'abc'.includes('a', 'abc'.length)");
+shouldBeFalse("'abc'.includes('a', Math.pow(2, 33))");
+shouldBeFalse("'abc'.includes('a', Infinity)");
+shouldBeTrue("'abc'.includes('ab', -Infinity)");
+shouldBeFalse("'abc'.includes('cd', -Infinity)");
+shouldBeTrue("'abc'.includes('ab', 0)");
+shouldBeFalse("'abc'.includes('cd', 0)");
 
 // Test startsWith
+shouldBe("String.prototype.startsWith.name", "'startsWith'");
 shouldBe("String.prototype.startsWith.length", "1");
 shouldBe("'foo bar'.startsWith('foo')", "true");
 shouldBe("'foo bar'.startsWith('foo', 0)", "true");
@@ -60,8 +69,15 @@
 shouldBe("'フーバー'.startsWith('abc', 1)", "false");
 shouldBe("'foo bar'.startsWith('フー')", "false");
 shouldBe("'foo bar'.startsWith('フー', 1)", "false");
+shouldBeFalse("'abc'.startsWith('a', Infinity)");
+shouldBeFalse("'abc'.startsWith('a', 1)");
+shouldBeTrue("'abc'.startsWith('b', 1)");
+shouldBeFalse("'abc'.startsWith('b', 2)");
+shouldBeTrue("'abc'.startsWith('c', 2)");
+shouldBeFalse("'abc'.startsWith('a', Math.pow(2, 33))");
 
 // Test endsWith
+shouldBe("String.prototype.endsWith.name", "'endsWith'");
 shouldBe("String.prototype.endsWith.length", "1");
 shouldBe("'foo bar'.endsWith('bar')", "true");
 shouldBe("'foo bar'.endsWith('ba', 6)", "true");
@@ -93,6 +109,14 @@
 shouldBe("'フーバー'.endsWith('abc')", "false");
 shouldBe("'foo bar'.endsWith('フー')", "false");
 shouldBe("'foo bar'.endsWith('フー', 3)", "false");
+shouldBeTrue("'abc'.endsWith('bc', Infinity)");
+shouldBeTrue("'abc'.endsWith('bc', Math.pow(2, 33))");
+shouldBeFalse("'abc'.endsWith('a', 0)");
+shouldBeTrue("'abc'.endsWith('a', 1)");
+shouldBeFalse("'abc'.endsWith('b', 1)");
+shouldBeTrue("'abc'.endsWith('b', 2)");
+shouldBeFalse("'abc'.endsWith('bc', 2)");
+shouldBeTrue("'abc'.endsWith('bc', 3)");
 
 // Call functions with an environment record as 'this'.
 shouldThrow("(function() { var f = String.prototype.startsWith; (function() { f('a'); })(); })()");

Modified: trunk/LayoutTests/js/string-includes-expected.txt (183693 => 183694)


--- trunk/LayoutTests/js/string-includes-expected.txt	2015-05-01 22:38:02 UTC (rev 183693)
+++ trunk/LayoutTests/js/string-includes-expected.txt	2015-05-01 22:44:30 UTC (rev 183694)
@@ -1,8 +1,9 @@
-This test checks the ES6 string functions startsWith(), endsWith() and includes().
+This test checks the ES6 string functions startsWith(), endsWith(), and includes().
 
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
 
 
+PASS String.prototype.includes.name is 'includes'
 PASS String.prototype.includes.length is 1
 PASS 'foo bar'.includes('bar') is true
 PASS 'foo bar'.includes('bar', 4) is true
@@ -32,6 +33,14 @@
 PASS 'foo 1e100 bar'.includes(1e100) is false
 PASS 'フーバー'.includes('ーバ') is true
 PASS 'フーバー'.includes('クー') is false
+PASS 'abc'.includes('a', 'abc'.length) is false
+PASS 'abc'.includes('a', Math.pow(2, 33)) is false
+PASS 'abc'.includes('a', Infinity) is false
+PASS 'abc'.includes('ab', -Infinity) is true
+PASS 'abc'.includes('cd', -Infinity) is false
+PASS 'abc'.includes('ab', 0) is true
+PASS 'abc'.includes('cd', 0) is false
+PASS String.prototype.startsWith.name is 'startsWith'
 PASS String.prototype.startsWith.length is 1
 PASS 'foo bar'.startsWith('foo') is true
 PASS 'foo bar'.startsWith('foo', 0) is true
@@ -60,6 +69,13 @@
 PASS 'フーバー'.startsWith('abc', 1) is false
 PASS 'foo bar'.startsWith('フー') is false
 PASS 'foo bar'.startsWith('フー', 1) is false
+PASS 'abc'.startsWith('a', Infinity) is false
+PASS 'abc'.startsWith('a', 1) is false
+PASS 'abc'.startsWith('b', 1) is true
+PASS 'abc'.startsWith('b', 2) is false
+PASS 'abc'.startsWith('c', 2) is true
+PASS 'abc'.startsWith('a', Math.pow(2, 33)) is false
+PASS String.prototype.endsWith.name is 'endsWith'
 PASS String.prototype.endsWith.length is 1
 PASS 'foo bar'.endsWith('bar') is true
 PASS 'foo bar'.endsWith('ba', 6) is true
@@ -91,6 +107,14 @@
 PASS 'フーバー'.endsWith('abc') is false
 PASS 'foo bar'.endsWith('フー') is false
 PASS 'foo bar'.endsWith('フー', 3) is false
+PASS 'abc'.endsWith('bc', Infinity) is true
+PASS 'abc'.endsWith('bc', Math.pow(2, 33)) is true
+PASS 'abc'.endsWith('a', 0) is false
+PASS 'abc'.endsWith('a', 1) is true
+PASS 'abc'.endsWith('b', 1) is false
+PASS 'abc'.endsWith('b', 2) is true
+PASS 'abc'.endsWith('bc', 2) is false
+PASS 'abc'.endsWith('bc', 3) is true
 PASS (function() { var f = String.prototype.startsWith; (function() { f('a'); })(); })() threw exception TypeError: Type error.
 PASS (function() { var f = String.prototype.endsWith; (function() { f('a'); })(); })() threw exception TypeError: Type error.
 PASS (function() { var f = String.prototype.includes; (function() { f('a'); })(); })() threw exception TypeError: Type error.

Modified: trunk/Source/_javascript_Core/ChangeLog (183693 => 183694)


--- trunk/Source/_javascript_Core/ChangeLog	2015-05-01 22:38:02 UTC (rev 183693)
+++ trunk/Source/_javascript_Core/ChangeLog	2015-05-01 22:44:30 UTC (rev 183694)
@@ -1,3 +1,21 @@
+2015-05-01  Jordan Harband  <[email protected]>
+
+        String#startsWith/endsWith/includes don't handle Infinity position/endPosition args correctly
+        https://bugs.webkit.org/show_bug.cgi?id=144314
+
+        Reviewed by Darin Adler.
+
+        Fixing handling of Infinity position args, per
+        https://people.mozilla.org/~jorendorff/es6-draft.html#sec-string.prototype.includes
+        https://people.mozilla.org/~jorendorff/es6-draft.html#sec-string.prototype.startswith
+        https://people.mozilla.org/~jorendorff/es6-draft.html#sec-string.prototype.endswith
+
+        * runtime/StringPrototype.cpp:
+        (JSC::clampInt32):
+        (JSC::stringProtoFuncStartsWith):
+        (JSC::stringProtoFuncEndsWith):
+        (JSC::stringProtoFuncIncludes):
+
 2015-05-01  Basile Clement  <[email protected]>
 
         Math.abs() returns negative

Modified: trunk/Source/_javascript_Core/runtime/StringPrototype.cpp (183693 => 183694)


--- trunk/Source/_javascript_Core/runtime/StringPrototype.cpp	2015-05-01 22:38:02 UTC (rev 183693)
+++ trunk/Source/_javascript_Core/runtime/StringPrototype.cpp	2015-05-01 22:44:30 UTC (rev 183694)
@@ -1669,6 +1669,15 @@
     return JSValue::encode(trimString(exec, thisValue, TrimRight));
 }
 
+static inline unsigned clampAndTruncateToUnsigned(double value, unsigned min, unsigned max)
+{
+    if (value < min)
+        return min;
+    if (value > max)
+        return max;
+    return static_cast<unsigned>(value);
+}
+
 EncodedJSValue JSC_HOST_CALL stringProtoFuncStartsWith(ExecState* exec)
 {
     JSValue thisValue = exec->thisValue();
@@ -1687,9 +1696,16 @@
     if (exec->hadException())
         return JSValue::encode(jsUndefined());
 
-    unsigned start = std::max(0, exec->argument(1).toInt32(exec));
-    if (exec->hadException())
-        return JSValue::encode(jsUndefined());
+    JSValue positionArg = exec->argument(1);
+    unsigned start = 0;
+    if (positionArg.isInt32())
+        start = std::max(0, positionArg.asInt32());
+    else {
+        unsigned length = stringToSearchIn.length();
+        start = clampAndTruncateToUnsigned(positionArg.toInteger(exec), 0, length);
+        if (exec->hadException())
+            return JSValue::encode(jsUndefined());
+    }
 
     return JSValue::encode(jsBoolean(stringToSearchIn.hasInfixStartingAt(searchString, start)));
 }
@@ -1713,13 +1729,18 @@
         return JSValue::encode(jsUndefined());
 
     unsigned length = stringToSearchIn.length();
-    JSValue a1 = exec->argument(1);
-    int pos = a1.isUndefined() ? length : a1.toInt32(exec);
-    if (exec->hadException())
-        return JSValue::encode(jsUndefined());
-    unsigned end = std::min<unsigned>(std::max(pos, 0), length);
 
-    return JSValue::encode(jsBoolean(stringToSearchIn.hasInfixEndingAt(searchString, end)));
+    JSValue endPositionArg = exec->argument(1);
+    unsigned end = length;
+    if (endPositionArg.isInt32())
+        end = std::max(0, endPositionArg.asInt32());
+    else if (!endPositionArg.isUndefined()) {
+        end = clampAndTruncateToUnsigned(endPositionArg.toInteger(exec), 0, length);
+        if (exec->hadException())
+            return JSValue::encode(jsUndefined());
+    }
+
+    return JSValue::encode(jsBoolean(stringToSearchIn.hasInfixEndingAt(searchString, std::min(end, length))));
 }
 
 EncodedJSValue JSC_HOST_CALL stringProtoFuncIncludes(ExecState* exec)
@@ -1740,9 +1761,16 @@
     if (exec->hadException())
         return JSValue::encode(jsUndefined());
 
-    unsigned start = std::max(0, exec->argument(1).toInt32(exec));
-    if (exec->hadException())
-        return JSValue::encode(jsUndefined());
+    JSValue positionArg = exec->argument(1);
+    unsigned start = 0;
+    if (positionArg.isInt32())
+        start = std::max(0, positionArg.asInt32());
+    else {
+        unsigned length = stringToSearchIn.length();
+        start = clampAndTruncateToUnsigned(positionArg.toInteger(exec), 0, length);
+        if (exec->hadException())
+            return JSValue::encode(jsUndefined());
+    }
 
     return JSValue::encode(jsBoolean(stringToSearchIn.contains(searchString, true, start)));
 }
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to