Bug 635389 - Check for overrecursion in functions that might need it. r=jorendorff
authorJeff Walden <jwalden@mit.edu>
Mon, 18 Apr 2011 16:50:46 -0400
changeset 68870 a7b220e7425ac1f2b4b8619c4008b2cd71f50482
parent 68869 8f7cf9d0b63686882e6e1114e7a6ff2a37a2e58a
child 68871 f1751a93f6651d00485288b47910902d48a5966f
push id19787
push usercleary@mozilla.com
push dateMon, 02 May 2011 22:49:43 +0000
treeherdermozilla-central@e089a54230bf [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjorendorff
bugs635389
milestone6.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 635389 - Check for overrecursion in functions that might need it. r=jorendorff
js/src/jsarray.cpp
js/src/tests/ecma_5/extensions/array-toString-recursion.js
js/src/tests/ecma_5/extensions/jstests.list
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -1307,18 +1307,16 @@ class AutoArrayCycleDetector
 
   protected:
 };
 
 static JSBool
 array_toString_sub(JSContext *cx, JSObject *obj, JSBool locale,
                    JSString *sepstr, Value *rval)
 {
-    JS_CHECK_RECURSION(cx, return false);
-
     static const jschar comma = ',';
     const jschar *sep;
     size_t seplen;
     if (sepstr) {
         seplen = sepstr->length();
         sep = sepstr->getChars(cx);
         if (!sep)
             return false;
@@ -1390,16 +1388,18 @@ array_toString_sub(JSContext *cx, JSObje
     rval->setString(str);
     return true;
 }
 
 /* ES5 15.4.4.2. NB: The algorithm here differs from the one in ES3. */
 static JSBool
 array_toString(JSContext *cx, uintN argc, Value *vp)
 {
+    JS_CHECK_RECURSION(cx, return false);
+
     JSObject *obj = ToObject(cx, &vp[1]);
     if (!obj)
         return false;
 
     Value &join = vp[0];
     if (!obj->getProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.joinAtom), &join))
         return false;
 
@@ -1424,16 +1424,18 @@ array_toString(JSContext *cx, uintN argc
         return false;
     *vp = args.rval();
     return true;
 }
 
 static JSBool
 array_toLocaleString(JSContext *cx, uintN argc, Value *vp)
 {
+    JS_CHECK_RECURSION(cx, return false);
+
     JSObject *obj = ToObject(cx, &vp[1]);
     if (!obj)
         return false;
 
     /*
      *  Passing comma here as the separator. Need a way to get a
      *  locale-specific version.
      */
@@ -1521,16 +1523,18 @@ InitArrayObject(JSContext *cx, JSObject 
 }
 
 /*
  * Perl-inspired join, reverse, and sort.
  */
 static JSBool
 array_join(JSContext *cx, uintN argc, Value *vp)
 {
+    JS_CHECK_RECURSION(cx, return false);
+
     JSString *str;
     if (argc == 0 || vp[2].isUndefined()) {
         str = NULL;
     } else {
         str = js_ValueToString(cx, vp[2]);
         if (!str)
             return JS_FALSE;
         vp[2].setString(str);
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_5/extensions/array-toString-recursion.js
@@ -0,0 +1,46 @@
+/*
+ * Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/licenses/publicdomain/
+ */
+
+//-----------------------------------------------------------------------------
+var BUGNUMBER = 635389;
+var summary = 'Infinite recursion via [].{toString,toLocaleString,join}';
+
+print(BUGNUMBER + ": " + summary);
+
+/**************
+ * BEGIN TEST *
+ **************/
+
+try
+{
+  var x = [];
+  x.join = Array.prototype.toString;
+  "" + x;
+  throw new Error("should have thrown");
+}
+catch (e)
+{
+  assertEq(e instanceof InternalError, true,
+           "should have thrown for over-recursion");
+}
+
+try
+{
+  var x = { toString: Array.prototype.toString, join: Array.prototype.toString };
+  "" + x;
+  throw new Error("should have thrown");
+}
+catch (e)
+{
+  assertEq(e instanceof InternalError, true,
+           "should have thrown for over-recursion");
+}
+
+/******************************************************************************/
+
+if (typeof reportCompare === "function")
+  reportCompare(true, true);
+
+print("All tests passed!");
--- a/js/src/tests/ecma_5/extensions/jstests.list
+++ b/js/src/tests/ecma_5/extensions/jstests.list
@@ -4,16 +4,17 @@ script 15.4.4.11.js
 script Boolean-toSource.js
 script Number-toSource.js
 script Object-keys-and-object-ids.js
 script String-toSource.js
 script bug352085.js
 script bug472534.js
 script bug496985.js
 script bug566661.js
+script array-toString-recursion.js
 skip-if(!xulRuntime.shell) script cross-global-eval-is-indirect.js # needs newGlobal()
 script eval-native-callback-is-indirect.js
 script extension-methods-reject-null-undefined-this.js
 skip-if(!xulRuntime.shell) script function-definition-with.js # needs evaluate()
 script iterator-in-catch.js
 skip-if(!xulRuntime.shell) script legacy-JSON.js # needs parseLegacyJSON
 fails script nested-delete-name-in-evalcode.js # bug 604301, at a minimum
 script proxy-strict.js