<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[169221] trunk</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/169221">169221</a></dd>
<dt>Author</dt> <dd>mark.lam@apple.com</dd>
<dt>Date</dt> <dd>2014-05-22 14:40:21 -0700 (Thu, 22 May 2014)</dd>
</dl>

<h3>Log Message</h3>
<pre>REGRESSION(<a href="http://trac.webkit.org/projects/webkit/changeset/154797">r154797</a>): Debugger crashes when stepping over an uncaught exception.
&lt;https://webkit.org/b/133182&gt;

Reviewed by Oliver Hunt.


Source/JavaScriptCore: 
Before <a href="http://trac.webkit.org/projects/webkit/changeset/154797">r154797</a>, we used to clear the VM exception before calling into the
debugger.  After <a href="http://trac.webkit.org/projects/webkit/changeset/154797">r154797</a>, we don't.  This patch will restore this clearing
of the exception before calling into the debugger.

Also added assertions after returning from calls into the debugger to
ensure that the debugger did not introduce any exceptions.

* interpreter/Interpreter.cpp:
(JSC::unwindCallFrame):
(JSC::Interpreter::unwind):
(JSC::Interpreter::debug):
- Fixed the assertion here.  Interpreter::debug() should never be called
  with a pending exception.  Debugger callbacks for exceptions should be
  handled by Interpreter::unwind() and Interpreter::unwindCallFrame().

LayoutTests: 
* inspector-protocol/debugger/regress-133182-expected.txt: Added.
* inspector-protocol/debugger/regress-133182.html: Added.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoreinterpreterInterpretercpp">trunk/Source/JavaScriptCore/interpreter/Interpreter.cpp</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsinspectorprotocoldebuggerregress133182expectedtxt">trunk/LayoutTests/inspector-protocol/debugger/regress-133182-expected.txt</a></li>
<li><a href="#trunkLayoutTestsinspectorprotocoldebuggerregress133182html">trunk/LayoutTests/inspector-protocol/debugger/regress-133182.html</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (169220 => 169221)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog        2014-05-22 21:37:38 UTC (rev 169220)
+++ trunk/LayoutTests/ChangeLog        2014-05-22 21:40:21 UTC (rev 169221)
</span><span class="lines">@@ -1,3 +1,13 @@
</span><ins>+2014-05-22  Mark Lam  &lt;mark.lam@apple.com&gt;
+
+        REGRESSION(r154797): Debugger crashes when stepping over an uncaught exception.
+        &lt;https://webkit.org/b/133182&gt;
+
+        Reviewed by Oliver Hunt.
+
+        * inspector-protocol/debugger/regress-133182-expected.txt: Added.
+        * inspector-protocol/debugger/regress-133182.html: Added.
+
</ins><span class="cx"> 2014-05-22  Michał Pakuła vel Rutka  &lt;m.pakula@samsung.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Unreviewed EFL gardening
</span></span></pre></div>
<a id="trunkLayoutTestsinspectorprotocoldebuggerregress133182expectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/inspector-protocol/debugger/regress-133182-expected.txt (0 => 169221)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/inspector-protocol/debugger/regress-133182-expected.txt                                (rev 0)
+++ trunk/LayoutTests/inspector-protocol/debugger/regress-133182-expected.txt        2014-05-22 21:40:21 UTC (rev 169221)
</span><span class="lines">@@ -0,0 +1,48 @@
</span><ins>+CONSOLE MESSAGE: line 48: [1] Testing statement '({}).a.b.c.d;'
+CONSOLE MESSAGE: line 49: [1] Paused and about to step
+CONSOLE MESSAGE: line 61: [1] Resumed
+CONSOLE MESSAGE: line 53: [1] Paused after stepping
+CONSOLE MESSAGE: line 61: [1] Resumed
+CONSOLE MESSAGE: line 1: TypeError: undefined is not an object (evaluating '({}).a.b')
+CONSOLE MESSAGE: line 48: [2] Testing statement 'exceptionBasic();'
+CONSOLE MESSAGE: line 49: [2] Paused and about to step
+CONSOLE MESSAGE: line 61: [2] Resumed
+CONSOLE MESSAGE: line 53: [2] Paused after stepping
+CONSOLE MESSAGE: line 61: [2] Resumed
+CONSOLE MESSAGE: line 3: TypeError: undefined is not an object (evaluating '({}).a.b')
+CONSOLE MESSAGE: line 48: [3] Testing statement 'exceptionDOM();'
+CONSOLE MESSAGE: line 49: [3] Paused and about to step
+CONSOLE MESSAGE: line 61: [3] Resumed
+CONSOLE MESSAGE: line 53: [3] Paused after stepping
+CONSOLE MESSAGE: line 61: [3] Resumed
+CONSOLE MESSAGE: line 8: NotFoundError: DOM Exception 8: An attempt was made to reference a Node in a context where it does not exist.
+CONSOLE MESSAGE: line 48: [4] Testing statement 'exceptionInHostFunction();'
+CONSOLE MESSAGE: line 49: [4] Paused and about to step
+CONSOLE MESSAGE: line 61: [4] Resumed
+CONSOLE MESSAGE: line 53: [4] Paused after stepping
+CONSOLE MESSAGE: line 61: [4] Resumed
+CONSOLE MESSAGE: line 24: exception in host function
+CONSOLE MESSAGE: line 48: [5] Testing statement 'throwString();'
+CONSOLE MESSAGE: line 49: [5] Paused and about to step
+CONSOLE MESSAGE: line 61: [5] Resumed
+CONSOLE MESSAGE: line 53: [5] Paused after stepping
+CONSOLE MESSAGE: line 61: [5] Resumed
+CONSOLE MESSAGE: line 13: exception string
+CONSOLE MESSAGE: line 48: [6] Testing statement 'throwParam({x:1});'
+CONSOLE MESSAGE: line 49: [6] Paused and about to step
+CONSOLE MESSAGE: line 61: [6] Resumed
+CONSOLE MESSAGE: line 53: [6] Paused after stepping
+CONSOLE MESSAGE: line 61: [6] Resumed
+CONSOLE MESSAGE: line 18: [object Object]
+CONSOLE MESSAGE: line 48: [7] Testing statement 'throwParam(new Error('error message'));'
+CONSOLE MESSAGE: line 49: [7] Paused and about to step
+CONSOLE MESSAGE: line 61: [7] Resumed
+CONSOLE MESSAGE: line 53: [7] Paused after stepping
+CONSOLE MESSAGE: line 61: [7] Resumed
+CONSOLE MESSAGE: line 18: Error: error message
+Regression test for https://bugs.webkit.org/show_bug.cgi?id=133182
+
+Stepping after breaking on uncaught exceptions should not crash
+
+PASS - paused for each uncaught exception
+
</ins></span></pre></div>
<a id="trunkLayoutTestsinspectorprotocoldebuggerregress133182html"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/inspector-protocol/debugger/regress-133182.html (0 => 169221)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/inspector-protocol/debugger/regress-133182.html                                (rev 0)
+++ trunk/LayoutTests/inspector-protocol/debugger/regress-133182.html        2014-05-22 21:40:21 UTC (rev 169221)
</span><span class="lines">@@ -0,0 +1,78 @@
</span><ins>+&lt;html&gt;
+&lt;head&gt;
+&lt;script src=&quot;../../http/tests/inspector-protocol/resources/protocol-test.js&quot;&gt;&lt;/script&gt;
+&lt;script src=&quot;resources/exception.js&quot;&gt;&lt;/script&gt;
+&lt;script&gt;
+function test()
+{
+    var expectPause = false;
+    var isStepping = false;
+
+    var testIndex = 0;
+    var statementsWithUncaughtExceptions = [
+        &quot;({}).a.b.c.d;&quot;,
+        &quot;exceptionBasic();&quot;,
+        &quot;exceptionDOM();&quot;,
+        &quot;exceptionInHostFunction();&quot;,
+        &quot;throwString();&quot;,
+        &quot;throwParam({x:1});&quot;,
+        &quot;throwParam(new Error('error message'));&quot;
+    ];
+
+    function triggerNextUncaughtException()
+    {
+
+        // Evaluate statement and expect to pause.
+        if (testIndex &lt; statementsWithUncaughtExceptions.length) {
+            var statement = statementsWithUncaughtExceptions[testIndex++];
+            InspectorTest.sendCommand(&quot;Runtime.evaluate&quot;, {expression: &quot;setTimeout(function() { &quot; + statement + &quot; }, 0);&quot;});
+            return;
+        }
+
+        // Done evaluating statements to pause. Evaluate some more we do not expect to pause.
+        InspectorTest.log(&quot;PASS - paused for each uncaught exception&quot;);
+        InspectorTest.completeTest();
+    }
+
+
+    InspectorTest.sendCommand(&quot;Debugger.enable&quot;, {});
+    InspectorTest.sendCommand(&quot;Debugger.setPauseOnExceptions&quot;, {state: &quot;uncaught&quot;}, function(responseObject) {
+        InspectorTest.checkForError(responseObject);
+        expectPause = true;
+        triggerNextUncaughtException();
+    });
+
+    InspectorTest.eventHandler[&quot;Debugger.paused&quot;] = function(messageObject)
+    {
+        if (!expectPause) {
+            InspectorTest.log(&quot;FAIL - debugger paused when we did not expect to&quot;);
+            InspectorTest.completeTest();
+            return;
+        }
+
+        if (!isStepping) {
+            console.log(&quot;[&quot; + testIndex + &quot;] Testing statement '&quot; + statementsWithUncaughtExceptions[testIndex - 1] + &quot;'&quot;);
+            console.log(&quot;[&quot; + testIndex + &quot;] Paused and about to step&quot;);
+            isStepping = true;
+            InspectorTest.sendCommand(&quot;Debugger.stepOver&quot;, {});
+        } else {
+            console.log(&quot;[&quot; + testIndex + &quot;] Paused after stepping&quot;);
+            isStepping = false;
+            InspectorTest.sendCommand(&quot;Debugger.resume&quot;, {});
+        }
+    }
+
+    InspectorTest.eventHandler[&quot;Debugger.resumed&quot;] = function(messageObject)
+    {
+        console.log(&quot;[&quot; + testIndex + &quot;] Resumed&quot;);
+        if (!isStepping)
+            triggerNextUncaughtException();
+    }
+}
+&lt;/script&gt;
+&lt;/head&gt;
+&lt;body onload=&quot;runTest()&quot;&gt;
+&lt;p&gt;Regression test for https://bugs.webkit.org/show_bug.cgi?id=133182&lt;/p&gt;
+&lt;p&gt;Stepping after breaking on uncaught exceptions should not crash&lt;/p&gt;
+&lt;/body&gt;
+&lt;/html&gt;
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (169220 => 169221)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2014-05-22 21:37:38 UTC (rev 169220)
+++ trunk/Source/JavaScriptCore/ChangeLog        2014-05-22 21:40:21 UTC (rev 169221)
</span><span class="lines">@@ -1,3 +1,25 @@
</span><ins>+2014-05-22  Mark Lam  &lt;mark.lam@apple.com&gt;
+
+        REGRESSION(r154797): Debugger crashes when stepping over an uncaught exception.
+        &lt;https://webkit.org/b/133182&gt;
+
+        Reviewed by Oliver Hunt.
+
+        Before r154797, we used to clear the VM exception before calling into the
+        debugger.  After r154797, we don't.  This patch will restore this clearing
+        of the exception before calling into the debugger.
+
+        Also added assertions after returning from calls into the debugger to
+        ensure that the debugger did not introduce any exceptions.
+
+        * interpreter/Interpreter.cpp:
+        (JSC::unwindCallFrame):
+        (JSC::Interpreter::unwind):
+        (JSC::Interpreter::debug):
+        - Fixed the assertion here.  Interpreter::debug() should never be called
+          with a pending exception.  Debugger callbacks for exceptions should be
+          handled by Interpreter::unwind() and Interpreter::unwindCallFrame().
+
</ins><span class="cx"> 2014-05-21  Filip Pizlo  &lt;fpizlo@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Store barrier elision should run after DCE in both the DFG path and the FTL path
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreinterpreterInterpretercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/interpreter/Interpreter.cpp (169220 => 169221)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/interpreter/Interpreter.cpp        2014-05-22 21:37:38 UTC (rev 169220)
+++ trunk/Source/JavaScriptCore/interpreter/Interpreter.cpp        2014-05-22 21:40:21 UTC (rev 169221)
</span><span class="lines">@@ -447,10 +447,12 @@
</span><span class="cx">     JSScope* scope = callFrame-&gt;scope();
</span><span class="cx"> 
</span><span class="cx">     if (Debugger* debugger = callFrame-&gt;vmEntryGlobalObject()-&gt;debugger()) {
</span><ins>+        ClearExceptionScope scope(&amp;callFrame-&gt;vm());
</ins><span class="cx">         if (callFrame-&gt;callee())
</span><span class="cx">             debugger-&gt;returnEvent(callFrame);
</span><span class="cx">         else
</span><span class="cx">             debugger-&gt;didExecuteProgram(callFrame);
</span><ins>+        ASSERT(!callFrame-&gt;hadException());
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     JSValue activation;
</span><span class="lines">@@ -700,9 +702,8 @@
</span><span class="cx">     if (exceptionValue.isEmpty() || (exceptionValue.isCell() &amp;&amp; !exceptionValue.asCell()))
</span><span class="cx">         exceptionValue = jsNull();
</span><span class="cx"> 
</span><del>-    if (exceptionValue.isObject()) {
</del><ins>+    if (exceptionValue.isObject())
</ins><span class="cx">         isTermination = isTerminatedExecutionException(asObject(exceptionValue));
</span><del>-    }
</del><span class="cx"> 
</span><span class="cx">     ASSERT(callFrame-&gt;vm().exceptionStack().size());
</span><span class="cx"> 
</span><span class="lines">@@ -726,6 +727,7 @@
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         debugger-&gt;exception(callFrame, exceptionValue, hasHandler);
</span><ins>+        ASSERT(!callFrame-&gt;hadException());
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     // Calculate an exception handler vPC, unwinding call frames as necessary.
</span><span class="lines">@@ -1225,28 +1227,31 @@
</span><span class="cx">     Debugger* debugger = callFrame-&gt;vmEntryGlobalObject()-&gt;debugger();
</span><span class="cx">     if (!debugger)
</span><span class="cx">         return;
</span><del>-    ASSERT(callFrame-&gt;codeBlock()-&gt;hasDebuggerRequests() || callFrame-&gt;hadException());
</del><span class="cx"> 
</span><ins>+    ASSERT(callFrame-&gt;codeBlock()-&gt;hasDebuggerRequests());
+    ASSERT(!callFrame-&gt;hadException());
+
</ins><span class="cx">     switch (debugHookID) {
</span><span class="cx">         case DidEnterCallFrame:
</span><span class="cx">             debugger-&gt;callEvent(callFrame);
</span><del>-            return;
</del><ins>+            break;
</ins><span class="cx">         case WillLeaveCallFrame:
</span><span class="cx">             debugger-&gt;returnEvent(callFrame);
</span><del>-            return;
</del><ins>+            break;
</ins><span class="cx">         case WillExecuteStatement:
</span><span class="cx">             debugger-&gt;atStatement(callFrame);
</span><del>-            return;
</del><ins>+            break;
</ins><span class="cx">         case WillExecuteProgram:
</span><span class="cx">             debugger-&gt;willExecuteProgram(callFrame);
</span><del>-            return;
</del><ins>+            break;
</ins><span class="cx">         case DidExecuteProgram:
</span><span class="cx">             debugger-&gt;didExecuteProgram(callFrame);
</span><del>-            return;
</del><ins>+            break;
</ins><span class="cx">         case DidReachBreakpoint:
</span><span class="cx">             debugger-&gt;didReachBreakpoint(callFrame);
</span><del>-            return;
</del><ins>+            break;
</ins><span class="cx">     }
</span><ins>+    ASSERT(!callFrame-&gt;hadException());
</ins><span class="cx"> }    
</span><span class="cx"> 
</span><span class="cx"> void Interpreter::enableSampler()
</span></span></pre>
</div>
</div>

</body>
</html>