[JSC] Error prototypes are called on remote scripts.
https://bugs.webkit.org/show_bug.cgi?id=52192

Reviewed by Keith Miller.

Source/JavaScriptCore:

Added a sanitizedToString() to the Error instance object so that it can be used
to get an error string without invoking getters and proxies.

* runtime/ErrorInstance.cpp:
(JSC::ErrorInstance::finishCreation):
(JSC::ErrorInstance::sanitizedToString):
* runtime/ErrorInstance.h:
(JSC::ErrorInstance::createStructure):
(JSC::ErrorInstance::runtimeTypeForCause):
(JSC::ErrorInstance::clearRuntimeTypeForCause):

Source/WebCore:

Test: http/tests/security/regress-52192.html

Parsing errors are reported to the main script's window.onerror function.  AFAIK,
both Chrome and Firefox have the error reporting mechanism use an internal
sanitized version of Error.prototype.toString() that will not invoke any getters
or proxies instead.

This patch fixes this issue by matching Chrome and Firefox's behavior.

Note: we did not choose to make error objects and prototypes read-only because
that was observed to have broken the web.
See https://bugs.chromium.org/p/chromium/issues/detail?id=69187#c73

Credit for reporting this issue goes to Daniel Divricean (http://divricean.ro).

* bindings/js/JSDOMBinding.cpp:
(WebCore::reportException):
* ForwardingHeaders/runtime/ErrorInstance.h: Added.

LayoutTests:

The added test will test the following combinations of factors:

1. Explicitly throwing an error of each of the types of JS errors i.e.
   Error, EvalError, RangeError, ReferenceError, SyntaxError, TypeError, URIError.
2. Validating that the error received in window.onerror does not leak any info.
3. Validating that the 'name' and 'toString' getters set on the error prototype
   object does not get invoked for creating the error message to be passed to
   window.error.

* http/tests/security/regress-52192-expected.txt: Added.
* http/tests/security/regress-52192.html: Added.
* http/tests/security/resources/regress-52192-syntax-error.js: Added.
* http/tests/security/resources/regress-52192-throw-error.js: Added.
(catch):



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@202460 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/LayoutTests/http/tests/security/resources/regress-52192-throw-error.js b/LayoutTests/http/tests/security/resources/regress-52192-throw-error.js
new file mode 100644
index 0000000..93910ec
--- /dev/null
+++ b/LayoutTests/http/tests/security/resources/regress-52192-throw-error.js
@@ -0,0 +1,38 @@
+{
+    let errorType = errorTypes[errorTypeIndexToTest];
+    let errorTypeName = errorTypeNames[errorTypeIndexToTest];
+
+    logTitle("Test thrown " + errorTypeName + " from a script from another domain");
+    incCaseIndex();
+
+    try {
+        console.log("   " + caseStr + " var e = new " + errorTypeName + "('Error thrown from other script with Secret');");
+        var e = new errorType("Error thrown from other script with Secret");
+        console.log("   " + caseStr + " e.name = 'OtherScript" + errorTypeName + "'");
+        e.name = "OtherScript" + errorTypeName;
+
+        let oldInMainScript = inMainScript;
+        inMainScript = false;
+
+        console.log("      [" + errorTypeName + "] e = '" + e + "'");
+        console.log("      [" + errorTypeName + "] e.name = '" + e.name + "'");
+        console.log("      [" + errorTypeName + "] e.message = '" + e.message + "'");
+        console.log("      [" + errorTypeName + "] e.toString() = '" + e.toString() + "'");
+
+        inMainScript = oldInMainScript;
+
+        console.log("   " + caseStr + " throw e;");
+        throw e;
+
+    } catch (e) {
+        let oldInMainScript = inMainScript;
+        inMainScript = false;
+
+        console.log("   " + caseStr + " Caught: " + e);
+        console.log("   " + caseStr + "    re-throw e;");
+
+        inMainScript = oldInMainScript;
+
+        throw e;
+    }
+}
\ No newline at end of file