Revision: 6428
Author: [email protected]
Date: Fri Jan 21 03:44:29 2011
Log: Return the empty string when formatting recursive error messages. This
matches the behavior of Safari and Firefox. Our old behavior was to
throw a stack overflow exception.

BUG=crbug.com/70334
TEST=mjsunit/cyclic-error-to-string.js

Review URL: http://codereview.chromium.org/6261018
http://code.google.com/p/v8/source/detail?r=6428

Added:
 /branches/bleeding_edge/test/mjsunit/cyclic-error-to-string.js
Modified:
 /branches/bleeding_edge/src/messages.js

=======================================
--- /dev/null
+++ /branches/bleeding_edge/test/mjsunit/cyclic-error-to-string.js Fri Jan 21 03:44:29 2011
@@ -0,0 +1,46 @@
+// Copyright 2011 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Test printing of cyclic errors which return the empty string for
+// compatibility with Safari and Firefox.
+
+var e = new Error();
+assertEquals('Error', e + '');
+
+e = new Error();
+e.name = e;
+e.message = e;
+e.stack = e;
+e.arguments = e;
+assertEquals('', e + '');
+
+e = new Error();
+e.name = [ e ];
+e.message = [ e ];
+e.stack = [ e ];
+e.arguments = [ e ];
+assertEquals('', e + '');
=======================================
--- /branches/bleeding_edge/src/messages.js     Thu Jan 20 10:51:47 2011
+++ /branches/bleeding_edge/src/messages.js     Fri Jan 21 03:44:29 2011
@@ -1011,20 +1011,48 @@

 // Setup extra properties of the Error.prototype object.
 $Error.prototype.message = '';
+
+// Global list of error objects visited during errorToString. This is
+// used to detect cycles in error toString formatting.
+var visited_errors = new $Array();
+var cyclic_error_marker = new $Object();
+
+function errorToStringDetectCycle() {
+  if (!%PushIfAbsent(visited_errors, this)) throw cyclic_error_marker;
+  try {
+    var type = this.type;
+    if (type && !this.hasOwnProperty("message")) {
+      var formatted = FormatMessage({ type: type, args: this.arguments });
+      return this.name + ": " + formatted;
+    }
+ var message = this.hasOwnProperty("message") ? (": " + this.message) : "";
+    return this.name + message;
+  } finally {
+    visited_errors.pop();
+  }
+}

 function errorToString() {
-  var type = this.type;
-  if (type && !this.hasOwnProperty("message")) {
- return this.name + ": " + FormatMessage({ type: type, args: this.arguments });
-  }
- var message = this.hasOwnProperty("message") ? (": " + this.message) : "";
-  return this.name + message;
+  // These helper functions are needed because access to properties on
+  // the builtins object do not work inside of a catch clause.
+  function isCyclicErrorMarker(o) { return o === cyclic_error_marker; }
+  function isVisitedErrorsEmpty() { return visited_errors.length === 0; }
+
+  try {
+    return %_CallFunction(this, errorToStringDetectCycle);
+  } catch(e) {
+    // Propagate cyclic_error_marker exception until all error
+    // formatting is finished and then return the empty string. Safari
+    // and Firefox also returns the empty string when converting a
+    // cyclic error to a string.
+    if (isCyclicErrorMarker(e) && isVisitedErrorsEmpty()) return '';
+    else throw e;
+  }
 }

 %FunctionSetName(errorToString, 'toString');
 %SetProperty($Error.prototype, 'toString', errorToString, DONT_ENUM);

-
 // Boilerplate for exceptions for stack overflows. Used from
 // Top::StackOverflow().
 const kStackOverflowBoilerplate = MakeRangeError('stack_overflow', []);

--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev

Reply via email to