Make formatting error message side-effect-free.
authoryangguo@chromium.org <yangguo@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 12 Nov 2012 10:33:20 +0000 (10:33 +0000)
committeryangguo@chromium.org <yangguo@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 12 Nov 2012 10:33:20 +0000 (10:33 +0000)
BUG=v8:2398

Review URL: https://chromiumcodereview.appspot.com/11359130

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@12926 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

src/isolate.cc
src/messages.js
src/runtime.cc
src/runtime.h
test/mjsunit/regress/regress-2398.js [new file with mode: 0644]

index 75e15a4..b077a70 100644 (file)
@@ -1138,6 +1138,14 @@ void Isolate::DoThrow(Object* exception, MessageLocation* location) {
               stack_trace_for_uncaught_exceptions_options_);
         }
       }
+      // Stringify custom error objects for the message object.
+      if (exception_handle->IsJSObject() && !IsErrorObject(exception_handle)) {
+        bool failed = false;
+        exception_handle = Execution::ToString(exception_handle, &failed);
+        if (failed) {
+          exception_handle = factory()->LookupAsciiSymbol("exception");
+        }
+      }
       Handle<Object> message_obj = MessageHandler::MakeMessageObject(
           "uncaught_exception",
           location,
index 58f0db0..f04bed9 100644 (file)
@@ -167,7 +167,7 @@ function FormatString(format, args) {
       if (arg_num < 4) {
         // str is one of %0, %1, %2 or %3.
         try {
-          str = ToDetailString(args[arg_num]);
+          str = NoSideEffectToString(args[arg_num]);
         } catch (e) {
           if (%IsJSModule(args[arg_num]))
             str = "module";
@@ -184,6 +184,26 @@ function FormatString(format, args) {
 }
 
 
+function NoSideEffectToString(obj) {
+  if (IS_STRING(obj)) return obj;
+  if (IS_NUMBER(obj)) return %_NumberToString(obj);
+  if (IS_BOOLEAN(obj)) return x ? 'true' : 'false';
+  if (IS_UNDEFINED(obj)) return 'undefined';
+  if (IS_NULL(obj)) return 'null';
+  if (IS_OBJECT(obj) && %GetDataProperty(obj, "toString") === ObjectToString) {
+    var constructor = obj.constructor;
+    if (typeof constructor == "function") {
+      var constructorName = constructor.name;
+      if (IS_STRING(constructorName) && constructorName !== "") {
+        return "#<" + constructorName + ">";
+      }
+    }
+  }
+  if (IsNativeErrorObject(obj)) return %_CallFunction(obj, ErrorToString);
+  return %_CallFunction(obj, ObjectToString);
+}
+
+
 // To check if something is a native error we need to check the
 // concrete native error types. It is not sufficient to use instanceof
 // since it possible to create an object that has Error.prototype on
index fb40d5e..11ba4c8 100644 (file)
@@ -4238,6 +4238,33 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineDataProperty) {
 }
 
 
+// Return property without being observable by accessors or interceptors.
+RUNTIME_FUNCTION(MaybeObject*, Runtime_GetDataProperty) {
+  ASSERT(args.length() == 2);
+  CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
+  CONVERT_ARG_HANDLE_CHECKED(String, key, 1);
+  LookupResult lookup(isolate);
+  object->LookupRealNamedProperty(*key, &lookup);
+  if (!lookup.IsFound()) return isolate->heap()->undefined_value();
+  switch (lookup.type()) {
+    case NORMAL:
+      return lookup.holder()->GetNormalizedProperty(&lookup);
+    case FIELD:
+      return lookup.holder()->FastPropertyAt(lookup.GetFieldIndex());
+    case CONSTANT_FUNCTION:
+      return lookup.GetConstantFunction();
+    case CALLBACKS:
+    case HANDLER:
+    case INTERCEPTOR:
+    case TRANSITION:
+      return isolate->heap()->undefined_value();
+    case NONEXISTENT:
+      UNREACHABLE();
+  }
+  return isolate->heap()->undefined_value();
+}
+
+
 MaybeObject* Runtime::SetObjectProperty(Isolate* isolate,
                                         Handle<Object> object,
                                         Handle<Object> key,
index 4f8d1d7..f63844c 100644 (file)
@@ -267,6 +267,7 @@ namespace internal {
   F(DefineOrRedefineDataProperty, 4, 1) \
   F(DefineOrRedefineAccessorProperty, 5, 1) \
   F(IgnoreAttributesAndSetProperty, -1 /* 3 or 4 */, 1) \
+  F(GetDataProperty, 2, 1) \
   \
   /* Arrays */ \
   F(RemoveArrayHoles, 2, 1) \
diff --git a/test/mjsunit/regress/regress-2398.js b/test/mjsunit/regress/regress-2398.js
new file mode 100644 (file)
index 0000000..1c66e7f
--- /dev/null
@@ -0,0 +1,41 @@
+// Copyright 2012 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.
+
+"use strict";
+
+var observed = false;
+
+var object = { get toString() { observed = true; } };
+Object.defineProperty(object, "ro", { value: 1 });
+
+try {
+  object.ro = 2;  // TypeError caused by trying to write to read-only.
+} catch (e) {
+  e.message;  // Forces formatting of the message object.
+}
+
+assertFalse(observed);