Bug 618572 - Assertion failure: *userbuf.ptr == c, at ../jsscan.cpp:349. r=brendan.
☠☠ backed out by c86a79eb18b9 ☠ ☠
authorNicholas Nethercote <nnethercote@mozilla.com>
Tue, 14 Dec 2010 17:26:01 -0800
changeset 59252 2892db39b022dedc277dcc9970be66182a120742
parent 59251 91092f078223c4164457bc9b102aae95b7ec238f
child 59253 c86a79eb18b95217369d7dc02e0ce3c79a6fdb68
push id1
push usershaver@mozilla.com
push dateTue, 04 Jan 2011 17:58:04 +0000
reviewersbrendan
bugs618572
milestone2.0b8pre
Bug 618572 - Assertion failure: *userbuf.ptr == c, at ../jsscan.cpp:349. r=brendan.
js/src/jsscan.cpp
js/src/jsscan.h
js/src/tests/js1_8_5/regress/jstests.list
js/src/tests/js1_8_5/regress/regress-618572.js
--- a/js/src/jsscan.cpp
+++ b/js/src/jsscan.cpp
@@ -733,38 +733,59 @@ TokenStream::getXMLEntity()
         cx->free(bytes);
     }
     return JS_FALSE;
 }
 
 #endif /* JS_HAS_XML_SUPPORT */
 
 /*
- * We have encountered a '\': check for a Unicode escape sequence after it,
- * returning the character code value if we found a Unicode escape sequence.
- * Otherwise, non-destructively return the original '\'.
+ * We have encountered a '\': check for a Unicode escape sequence after it.
+ * Return 'true' and the character code value (by value) if we found a
+ * Unicode escape sequence.  Otherwise, return 'false'.  In both cases, do not
+ * advance along the buffer.
  */
-int32
-TokenStream::getUnicodeEscape()
+bool
+TokenStream::peekUnicodeEscape(int *result)
 {
     jschar cp[5];
-    int32 c;
 
     if (peekChars(5, cp) && cp[0] == 'u' &&
         JS7_ISHEX(cp[1]) && JS7_ISHEX(cp[2]) &&
         JS7_ISHEX(cp[3]) && JS7_ISHEX(cp[4]))
     {
-        c = (((((JS7_UNHEX(cp[1]) << 4)
+        *result = (((((JS7_UNHEX(cp[1]) << 4)
                 + JS7_UNHEX(cp[2])) << 4)
               + JS7_UNHEX(cp[3])) << 4)
             + JS7_UNHEX(cp[4]);
+        return true;
+    }
+    return false;
+}
+
+bool
+TokenStream::matchUnicodeEscapeIdStart(int32 *cp)
+{
+    peekUnicodeEscape(cp);
+    if (JS_ISIDSTART(*cp)) {
         skipChars(5);
-        return c;
+        return true;
     }
-    return '\\';
+    return false;
+}
+
+bool
+TokenStream::matchUnicodeEscapeIdent(int32 *cp)
+{
+    peekUnicodeEscape(cp);
+    if (JS_ISIDENT(*cp)) {
+        skipChars(5);
+        return true;
+    }
+    return false;
 }
 
 Token *
 TokenStream::newToken(ptrdiff_t adjust)
 {
     cursor = (cursor + 1) & ntokensMask;
     Token *tp = &tokens[cursor];
     tp->ptr = userbuf.ptr + adjust;
@@ -790,17 +811,17 @@ atomize(JSContext *cx, JSCharBuffer &cb)
 
 TokenKind
 TokenStream::getTokenInternal()
 {
     TokenKind tt;
     int c, qc;
     Token *tp;
     JSAtom *atom;
-    JSBool hadUnicodeEscape;
+    bool hadUnicodeEscape;
     const struct keyword *kw;
 #if JS_HAS_XML_SUPPORT
     JSBool inTarget;
     size_t targetLength;
     ptrdiff_t contentIndex;
 #endif
 
 #if JS_HAS_XML_SUPPORT
@@ -988,35 +1009,32 @@ TokenStream::getTokenInternal()
         tt = TOK_EOF;
         goto out;
     }
 
     /*
      * Look for an identifier.
      */
 
-    hadUnicodeEscape = JS_FALSE;
+    hadUnicodeEscape = false;
     if (JS_ISIDSTART(c) ||
-        (c == '\\' &&
-         (qc = getUnicodeEscape(),
-          hadUnicodeEscape = JS_ISIDSTART(qc))))
+        (c == '\\' && (hadUnicodeEscape = matchUnicodeEscapeIdStart(&qc))))
     {
         if (hadUnicodeEscape)
             c = qc;
         tokenbuf.clear();
         for (;;) {
             if (!tokenbuf.append(c))
                 goto error;
             c = getChar();
             if (c == '\\') {
-                qc = getUnicodeEscape();
-                if (!JS_ISIDENT(qc))
+                if (!matchUnicodeEscapeIdent(&qc))
                     break;
                 c = qc;
-                hadUnicodeEscape = JS_TRUE;
+                hadUnicodeEscape = true;
             } else {
                 if (!JS_ISIDENT(c))
                     break;
             }
         }
         ungetChar(c);
 
         /*
--- a/js/src/jsscan.h
+++ b/js/src/jsscan.h
@@ -457,17 +457,19 @@ class TokenStream
 
     TokenKind getTokenInternal();     /* doesn't check for pushback or error flag. */
 
     int32 getChar();
     int32 getCharIgnoreEOL();
     void ungetChar(int32 c);
     void ungetCharIgnoreEOL(int32 c);
     Token *newToken(ptrdiff_t adjust);
-    int32 getUnicodeEscape();
+    bool peekUnicodeEscape(int32 *c);
+    bool matchUnicodeEscapeIdStart(int32 *c);
+    bool matchUnicodeEscapeIdent(int32 *c);
     JSBool peekChars(intN n, jschar *cp);
     JSBool getXMLEntity();
     jschar *findEOL();
 
     JSBool matchChar(int32 expect) {
         int32 c = getChar();
         if (c == expect)
             return JS_TRUE;
--- a/js/src/tests/js1_8_5/regress/jstests.list
+++ b/js/src/tests/js1_8_5/regress/jstests.list
@@ -51,10 +51,11 @@ script regress-600137.js
 script regress-601399.js
 script regress-602621.js
 fails-if(!xulRuntime.shell) script regress-607799.js
 fails-if(!xulRuntime.shell) script regress-607863.js
 script regress-610026.js
 script regress-609617.js
 script regress-617405-1.js
 script regress-617405-2.js
+script regress-618572.js
 skip-if(!xulRuntime.shell) script regress-618576.js  # uses evalcx
 fails-if(!xulRuntime.shell) script regress-618652.js
new file mode 100644
--- /dev/null
+++ b/js/src/tests/js1_8_5/regress/regress-618572.js
@@ -0,0 +1,37 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/licenses/publicdomain/
+ */
+
+//-----------------------------------------------------------------------------
+var BUGNUMBER = 618572;
+var summary = 'Do not assert when ungetting a Unicode char sequence';
+var actual = '';
+var expect = '';
+
+//-----------------------------------------------------------------------------
+test();
+//-----------------------------------------------------------------------------
+
+function test()
+{
+  enterFunc ('test');
+  printBugNumber(BUGNUMBER);
+  printStatus (summary);
+ 
+  expect = 'SyntaxError: illegal character';
+
+  try
+  {
+    eval("var a\\u0346 = 3;");
+  }
+  catch(ex)
+  {
+    actual = ex + '';
+  }
+
+  reportCompare(expect, actual, summary);
+
+  exitFunc ('test');
+}