# HG changeset patch # User Jeff Walden # Date 1527288030 25200 # Node ID 1a85fc556cd30b3f5c16fc33f595aeacb5abd11a # Parent a3e7bc5d0f02bf17958ac6d3007bfb2bfcafd46b Bug 1435828 - Allow U+2028 LINE SEPARATOR and U+2029 PARAGRAPH SEPARATOR, encoding those literal code points, inside string literals. r=anba diff --git a/js/src/builtin/Eval.cpp b/js/src/builtin/Eval.cpp --- a/js/src/builtin/Eval.cpp +++ b/js/src/builtin/Eval.cpp @@ -133,45 +133,39 @@ enum EvalJSONResult { EvalJSON_Success, EvalJSON_NotJSON }; template static bool EvalStringMightBeJSON(const mozilla::Range chars) { - // If the eval string starts with '(' or '[' and ends with ')' or ']', it may be JSON. - // Try the JSON parser first because it's much faster. If the eval string - // isn't JSON, JSON parsing will probably fail quickly, so little time - // will be lost. + // If the eval string starts with '(' or '[' and ends with ')' or ']', it + // may be JSON. Try the JSON parser first because it's much faster. If + // the eval string isn't JSON, JSON parsing will probably fail quickly, so + // little time will be lost. size_t length = chars.length(); - if (length > 2 && - ((chars[0] == '[' && chars[length - 1] == ']') || - (chars[0] == '(' && chars[length - 1] == ')'))) - { - // Remarkably, JavaScript syntax is not a superset of JSON syntax: - // strings in JavaScript cannot contain the Unicode line and paragraph - // terminator characters U+2028 and U+2029, but strings in JSON can. - // Rather than force the JSON parser to handle this quirk when used by - // eval, we simply don't use the JSON parser when either character - // appears in the provided string. See bug 657367. - if (sizeof(CharT) > 1) { - for (RangedPtr cp = chars.begin() + 1, end = chars.end() - 1; - cp < end; - cp++) - { - char16_t c = *cp; - if (c == 0x2028 || c == 0x2029) - return false; - } - } + if (length < 2) + return false; - return true; - } - return false; + // It used to be that strings in JavaScript forbid U+2028 LINE SEPARATOR + // and U+2029 PARAGRAPH SEPARATOR, so something like + // + // eval("['" + "\u2028" + "']"); + // + // i.e. an array containing a string with a line separator in it, *would* + // be JSON but *would not* be valid JavaScript. Handing such a string to + // the JSON parser would then fail to recognize a syntax error. As of + // JavaScript strings may + // contain these two code points, so it's safe to JSON-parse eval strings + // that contain them. + + CharT first = chars[0], last = chars[length - 1]; + return (first == '[' && last == ']') || + (first == '(' && last == ')'); } template static EvalJSONResult ParseEvalStringAsJSON(JSContext* cx, const mozilla::Range chars, MutableHandleValue rval) { size_t len = chars.length(); MOZ_ASSERT((chars[0] == '(' && chars[len - 1] == ')') || diff --git a/js/src/frontend/TokenStream.cpp b/js/src/frontend/TokenStream.cpp --- a/js/src/frontend/TokenStream.cpp +++ b/js/src/frontend/TokenStream.cpp @@ -652,16 +652,20 @@ TokenStreamCharsBase::TokenBuf::f size_t n = 0; while (true) { if (p >= limit_) break; if (n >= max) break; n++; + + // This stops at U+2028 LINE SEPARATOR or U+2029 PARAGRAPH SEPARATOR in + // string and template literals. These code points do affect line and + // column coordinates, even as they encode their literal values. if (TokenBuf::isRawEOLChar(*p++)) break; } return start + n; } template bool @@ -2343,33 +2347,43 @@ TokenStreamSpecific, that is)"; print(BUGNUMBER + ": " + summary); /************** * BEGIN TEST * **************/ -function esc(s) -{ - return s.split("").map(function(v) - { - var code = - ("000" + v.charCodeAt(0).toString(16)).slice(-4); - return "\\u" + code; - }).join(""); -} - -try -{ - var r = eval('"\u2028"'); - throw new Error("\"\\u2028\" didn't throw, returned " + esc(r)); -} -catch (e) -{ - assertEq(e instanceof SyntaxError, true, - "U+2028 is not a valid string character"); -} - -try -{ - var r = eval('("\u2028")'); - throw new Error("(\"\\u2028\") didn't throw, returned " + esc(r)); -} -catch (e) -{ - assertEq(e instanceof SyntaxError, true, - "U+2028 is not a valid string character"); -} - -try -{ - var r = eval('"\u2029"'); - throw new Error("\"\\u2029\" didn't throw, returned " + esc(r)); -} -catch (e) -{ - assertEq(e instanceof SyntaxError, true, - "U+2029 is not a valid string character"); -} - -try -{ - var r = eval('("\u2029")'); - throw new Error("(\"\\u2029\") didn't throw, returned " + esc(r)); -} -catch (e) -{ - assertEq(e instanceof SyntaxError, true, - "U+2029 is not a valid string character"); -} +assertEq(eval('("\u2028")'), "\u2028"); +assertEq(eval('("\u2029")'), "\u2029"); /******************************************************************************/ if (typeof reportCompare === "function") reportCompare(true, true); print("Tests complete!");