Web Inspector: Using "break on all exceptions" when throwing stack overflow hangs...
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 21 Jun 2017 21:32:44 +0000 (21:32 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 21 Jun 2017 21:32:44 +0000 (21:32 +0000)
https://bugs.webkit.org/show_bug.cgi?id=172432
<rdar://problem/29870873>

Patch by Joseph Pecoraro <pecoraro@apple.com> on 2017-06-21
Reviewed by Saam Barati.

Source/JavaScriptCore:

Avoid pausing on StackOverflow and OutOfMemory errors to avoid a hang.
We will proceed to improve debugging of these cases in the follow-up bugs.

* debugger/Debugger.cpp:
(JSC::Debugger::exception):
Ignore pausing on these errors.

* runtime/ErrorInstance.h:
(JSC::ErrorInstance::setStackOverflowError):
(JSC::ErrorInstance::isStackOverflowError):
(JSC::ErrorInstance::setOutOfMemoryError):
(JSC::ErrorInstance::isOutOfMemoryError):
* runtime/ExceptionHelpers.cpp:
(JSC::createStackOverflowError):
* runtime/Error.cpp:
(JSC::createOutOfMemoryError):
Mark these kinds of errors.

LayoutTests:

* inspector/debugger/no-pause-out-of-memory-exception-expected.txt: Added.
* inspector/debugger/no-pause-out-of-memory-exception.html: Added.
* inspector/debugger/no-pause-stack-overflow-exception-expected.txt: Added.
* inspector/debugger/no-pause-stack-overflow-exception.html: Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@218652 268f45cc-cd09-0410-ab3c-d52691b4dbfc

LayoutTests/ChangeLog
LayoutTests/inspector/debugger/no-pause-out-of-memory-exception-expected.txt [new file with mode: 0644]
LayoutTests/inspector/debugger/no-pause-out-of-memory-exception.html [new file with mode: 0644]
LayoutTests/inspector/debugger/no-pause-stack-overflow-exception-expected.txt [new file with mode: 0644]
LayoutTests/inspector/debugger/no-pause-stack-overflow-exception.html [new file with mode: 0644]
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/debugger/Debugger.cpp
Source/JavaScriptCore/runtime/Error.cpp
Source/JavaScriptCore/runtime/ErrorInstance.h
Source/JavaScriptCore/runtime/ExceptionHelpers.cpp

index 5d6aae5..31207f5 100644 (file)
@@ -1,3 +1,16 @@
+2017-06-21  Joseph Pecoraro  <pecoraro@apple.com>
+
+        Web Inspector: Using "break on all exceptions" when throwing stack overflow hangs inspector
+        https://bugs.webkit.org/show_bug.cgi?id=172432
+        <rdar://problem/29870873>
+
+        Reviewed by Saam Barati.
+
+        * inspector/debugger/no-pause-out-of-memory-exception-expected.txt: Added.
+        * inspector/debugger/no-pause-out-of-memory-exception.html: Added.
+        * inspector/debugger/no-pause-stack-overflow-exception-expected.txt: Added.
+        * inspector/debugger/no-pause-stack-overflow-exception.html: Added.
+
 2017-06-20  Simon Fraser  <simon.fraser@apple.com>
 
         Remove WILL_REVEAL_EDGE_EVENTS code
diff --git a/LayoutTests/inspector/debugger/no-pause-out-of-memory-exception-expected.txt b/LayoutTests/inspector/debugger/no-pause-out-of-memory-exception-expected.txt
new file mode 100644 (file)
index 0000000..ab846a8
--- /dev/null
@@ -0,0 +1,9 @@
+CONSOLE MESSAGE: line 12: Error: Out of memory
+Test we do not pause on a OutOfMemory Exception.
+
+
+== Running test suite: Debugger.OutOfMemoryException
+-- Running test case: Debugger.OutOfMemoryException.NoPause
+Uncaught exception in test page: Error: Out of memory [no-pause-out-of-memory-exception.html:12]
+PASS: Should not pause on OutOfMemory Exception.
+
diff --git a/LayoutTests/inspector/debugger/no-pause-out-of-memory-exception.html b/LayoutTests/inspector/debugger/no-pause-out-of-memory-exception.html
new file mode 100644 (file)
index 0000000..8403a38
--- /dev/null
@@ -0,0 +1,54 @@
+<!doctype html>
+<html>
+<head>
+<script src="../../http/tests/inspector/resources/inspector-test.js"></script>
+<script>
+TestPage.allowUncaughtExceptions = true;
+TestPage.needToSanitizeUncaughtExceptionURLs = true;
+
+function triggerOutOfMemoryException() {
+    let s = "a";
+    while (true)
+        s += s;
+}
+
+window.addEventListener("error", (event) => {
+    TestPage.dispatchEventToFrontend("AfterError");
+});
+
+function test()
+{
+    WebInspector.debuggerManager.allExceptionsBreakpoint.disabled = false;
+
+    let suite = InspectorTest.createAsyncSuite("Debugger.OutOfMemoryException");
+
+    suite.addTestCase({
+        name: "Debugger.OutOfMemoryException.NoPause",
+        description: "Should not pause on a OutOfMemory Exception.",
+        test(resolve, reject) {
+            let paused = false;
+
+            WebInspector.debuggerManager.singleFireEventListener(WebInspector.DebuggerManager.Event.Paused, (event) => {
+                paused = true;
+                InspectorTest.fail("Should not pause.");
+                reject();
+            });
+
+            InspectorTest.singleFireEventListener("AfterError", (event) => {
+                if (!paused)
+                    InspectorTest.pass("Should not pause on OutOfMemory Exception.");
+                resolve();
+            });
+
+            InspectorTest.evaluateInPage(`setTimeout(triggerOutOfMemoryException)`);
+        }
+    });
+
+    suite.runTestCasesAndFinish();
+}
+</script>
+</head>
+<body onload="runTest()">
+<p>Test we do not pause on a OutOfMemory Exception.</p>
+</body>
+</html>
diff --git a/LayoutTests/inspector/debugger/no-pause-stack-overflow-exception-expected.txt b/LayoutTests/inspector/debugger/no-pause-stack-overflow-exception-expected.txt
new file mode 100644 (file)
index 0000000..dc8e475
--- /dev/null
@@ -0,0 +1,9 @@
+CONSOLE MESSAGE: line 10: RangeError: Maximum call stack size exceeded.
+Test we do not pause on a StackOverflow Exception.
+
+
+== Running test suite: Debugger.StackOverflowException
+-- Running test case: Debugger.StackOverflowException.NoPause
+Uncaught exception in test page: RangeError: Maximum call stack size exceeded. [no-pause-stack-overflow-exception.html:10]
+PASS: Should not pause on StackOverflow Exception.
+
diff --git a/LayoutTests/inspector/debugger/no-pause-stack-overflow-exception.html b/LayoutTests/inspector/debugger/no-pause-stack-overflow-exception.html
new file mode 100644 (file)
index 0000000..52ed9dd
--- /dev/null
@@ -0,0 +1,53 @@
+<!doctype html>
+<html>
+<head>
+<script src="../../http/tests/inspector/resources/inspector-test.js"></script>
+<script>
+TestPage.allowUncaughtExceptions = true;
+TestPage.needToSanitizeUncaughtExceptionURLs = true;
+
+function triggerStackOverflowException() {
+    function f() { f(); }
+    f();
+}
+
+window.addEventListener("error", (event) => {
+    TestPage.dispatchEventToFrontend("AfterError");
+});
+
+function test()
+{
+    WebInspector.debuggerManager.allExceptionsBreakpoint.disabled = false;
+
+    let suite = InspectorTest.createAsyncSuite("Debugger.StackOverflowException");
+
+    suite.addTestCase({
+        name: "Debugger.StackOverflowException.NoPause",
+        description: "Should not pause on a StackOverflow Exception.",
+        test(resolve, reject) {
+            let paused = false;
+
+            WebInspector.debuggerManager.singleFireEventListener(WebInspector.DebuggerManager.Event.Paused, (event) => {
+                paused = true;
+                InspectorTest.fail("Should not pause.");
+                reject();
+            });
+
+            InspectorTest.singleFireEventListener("AfterError", (event) => {
+                if (!paused)
+                    InspectorTest.pass("Should not pause on StackOverflow Exception.");
+                resolve();
+            });
+
+            InspectorTest.evaluateInPage(`setTimeout(triggerStackOverflowException)`);
+        }
+    });
+
+    suite.runTestCasesAndFinish();
+}
+</script>
+</head>
+<body onload="runTest()">
+<p>Test we do not pause on a StackOverflow Exception.</p>
+</body>
+</html>
index ac7ef62..4c87fd0 100644 (file)
@@ -1,3 +1,29 @@
+2017-06-21  Joseph Pecoraro  <pecoraro@apple.com>
+
+        Web Inspector: Using "break on all exceptions" when throwing stack overflow hangs inspector
+        https://bugs.webkit.org/show_bug.cgi?id=172432
+        <rdar://problem/29870873>
+
+        Reviewed by Saam Barati.
+
+        Avoid pausing on StackOverflow and OutOfMemory errors to avoid a hang.
+        We will proceed to improve debugging of these cases in the follow-up bugs.
+
+        * debugger/Debugger.cpp:
+        (JSC::Debugger::exception):
+        Ignore pausing on these errors.
+
+        * runtime/ErrorInstance.h:
+        (JSC::ErrorInstance::setStackOverflowError):
+        (JSC::ErrorInstance::isStackOverflowError):
+        (JSC::ErrorInstance::setOutOfMemoryError):
+        (JSC::ErrorInstance::isOutOfMemoryError):
+        * runtime/ExceptionHelpers.cpp:
+        (JSC::createStackOverflowError):
+        * runtime/Error.cpp:
+        (JSC::createOutOfMemoryError):
+        Mark these kinds of errors.
+
 2017-06-21  Saam Barati  <sbarati@apple.com>
 
         Make it clear that regenerating ICs are holding the CodeBlock's lock by passing the locker as a parameter
index 8f39901..348c68c 100644 (file)
@@ -757,6 +757,16 @@ void Debugger::exception(CallFrame* callFrame, JSValue exception, bool hasCatchH
     if (m_isPaused)
         return;
 
+    if (JSObject* object = jsDynamicCast<JSObject*>(m_vm, exception)) {
+        if (object->isErrorInstance()) {
+            ErrorInstance* error = static_cast<ErrorInstance*>(object);
+            // FIXME: <https://webkit.org/b/173625> Web Inspector: Should be able to pause and debug a StackOverflow Exception
+            // FIXME: <https://webkit.org/b/173627> Web Inspector: Should be able to pause and debug an OutOfMemory Exception
+            if (error->isStackOverflowError() || error->isOutOfMemoryError())
+                return;
+        }
+    }
+
     PauseReasonDeclaration reason(*this, PausedForException);
     if (m_pauseOnExceptionsState == PauseOnAllExceptions || (m_pauseOnExceptionsState == PauseOnUncaughtExceptions && !hasCatchHandler)) {
         m_pauseAtNextOpportunity = true;
index 6415736..2bcdf15 100644 (file)
 #include "FunctionPrototype.h"
 #include "Interpreter.h"
 #include "JSArray.h"
+#include "JSCInlines.h"
 #include "JSFunction.h"
 #include "JSGlobalObject.h"
 #include "JSObject.h"
 #include "JSString.h"
-#include "JSCInlines.h"
 #include "NativeErrorConstructor.h"
 #include "SourceCode.h"
 #include "StackFrame.h"
@@ -310,7 +310,9 @@ JSObject* createURIError(ExecState* exec, const String& message)
 
 JSObject* createOutOfMemoryError(ExecState* exec)
 {
-    return createError(exec, ASCIILiteral("Out of memory"), nullptr);
+    auto* error = createError(exec, ASCIILiteral("Out of memory"), nullptr);
+    jsCast<ErrorInstance*>(error)->setOutOfMemoryError();
+    return error;
 }
 
 
index 732b79a..6b70b63 100644 (file)
@@ -61,6 +61,11 @@ public:
     RuntimeType runtimeTypeForCause() const { return m_runtimeTypeForCause; }
     void clearRuntimeTypeForCause() { m_runtimeTypeForCause = TypeNothing; }
 
+    void setStackOverflowError() { m_stackOverflowError = true; }
+    bool isStackOverflowError() const { return m_stackOverflowError; }
+    void setOutOfMemoryError() { m_outOfMemoryError = true; }
+    bool isOutOfMemoryError() const { return m_outOfMemoryError; }
+
     JS_EXPORT_PRIVATE String sanitizedToString(ExecState*);
 
 protected:
@@ -70,6 +75,8 @@ protected:
 
     SourceAppender m_sourceAppender { nullptr };
     RuntimeType m_runtimeTypeForCause { TypeNothing };
+    bool m_stackOverflowError { false };
+    bool m_outOfMemoryError { false };
 };
 
 } // namespace JSC
index 616e697..2c2e2e0 100644 (file)
 #include "config.h"
 #include "ExceptionHelpers.h"
 
-#include "CodeBlock.h"
 #include "CallFrame.h"
+#include "CodeBlock.h"
 #include "ErrorHandlingScope.h"
 #include "Exception.h"
-#include "JSGlobalObjectFunctions.h"
 #include "Interpreter.h"
-#include "Nodes.h"
 #include "JSCInlines.h"
+#include "JSGlobalObjectFunctions.h"
+#include "Nodes.h"
 #include "RuntimeType.h"
 #include <wtf/text/StringBuilder.h>
 #include <wtf/text/StringView.h>
@@ -74,7 +74,9 @@ JSObject* createStackOverflowError(ExecState* exec)
 
 JSObject* createStackOverflowError(ExecState* exec, JSGlobalObject* globalObject)
 {
-    return createRangeError(exec, globalObject, ASCIILiteral("Maximum call stack size exceeded."));
+    auto* error = createRangeError(exec, globalObject, ASCIILiteral("Maximum call stack size exceeded."));
+    jsCast<ErrorInstance*>(error)->setStackOverflowError();
+    return error;
 }
 
 JSObject* createUndefinedVariableError(ExecState* exec, const Identifier& ident)