Fix Debug::Break crash.
authoryangguo@chromium.org <yangguo@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 9 Jul 2012 15:18:08 +0000 (15:18 +0000)
committeryangguo@chromium.org <yangguo@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 9 Jul 2012 15:18:08 +0000 (15:18 +0000)
BUG=131642
TEST=test-debug/Regress131642

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

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

src/debug.cc
src/debug.h
src/execution.cc
src/runtime.cc
test/cctest/test-debug.cc

index 40ddabb3cb1a37a85958a2b6799bdc3ba1330ba7..da928159d8cb134d72d039814ad2f2cdf2f1170e 100644 (file)
@@ -892,27 +892,6 @@ void Debug::Iterate(ObjectVisitor* v) {
 }
 
 
-// TODO(131642): Remove this when fixed.
-void Debug::PutValuesOnStackAndDie(int start,
-                                   Address c_entry_fp,
-                                   Address last_fp,
-                                   Address larger_fp,
-                                   int count,
-                                   char* stack,
-                                   int end) {
-  OS::PrintError("start:       %d\n", start);
-  OS::PrintError("c_entry_fp:  %p\n", static_cast<void*>(c_entry_fp));
-  OS::PrintError("last_fp:     %p\n", static_cast<void*>(last_fp));
-  OS::PrintError("larger_fp:   %p\n", static_cast<void*>(larger_fp));
-  OS::PrintError("count:       %d\n", count);
-  if (stack != NULL) {
-    OS::PrintError("stack:       %s\n", stack);
-  }
-  OS::PrintError("end:         %d\n", end);
-  OS::Abort();
-}
-
-
 Object* Debug::Break(Arguments args) {
   Heap* heap = isolate_->heap();
   HandleScope scope(isolate_);
@@ -1010,53 +989,16 @@ Object* Debug::Break(Arguments args) {
         it.Advance();
       }
 
-      // TODO(131642): Remove this when fixed.
-      // Catch the cases that would lead to crashes and capture
-      // - C entry FP at which to start stack crawl.
-      // - FP of the frame at which we plan to stop stepping out (last FP).
-      // - current FP that's larger than last FP.
-      // - Counter for the number of steps to step out.
-      // - stack trace string.
-      if (it.done()) {
-        // We crawled the entire stack, never reaching last_fp_.
-        Handle<String> stack = isolate_->StackTraceString();
-        char buffer[8192];
-        int length = Min(8192, stack->length());
-        String::WriteToFlat(*stack, buffer, 0, length - 1);
-        PutValuesOnStackAndDie(0xBEEEEEEE,
-                               frame->fp(),
-                               thread_local_.last_fp_,
-                               reinterpret_cast<Address>(0xDEADDEAD),
-                               count,
-                               buffer,
-                               0xCEEEEEEE);
-      } else if (it.frame()->fp() != thread_local_.last_fp_) {
-        // We crawled over last_fp_, without getting a match.
-        Handle<String> stack = isolate_->StackTraceString();
-        char buffer[8192];
-        int length = Min(8192, stack->length());
-        String::WriteToFlat(*stack, buffer, 0, length - 1);
-        PutValuesOnStackAndDie(0xDEEEEEEE,
-                               frame->fp(),
-                               thread_local_.last_fp_,
-                               it.frame()->fp(),
-                               count,
-                               buffer,
-                               0xFEEEEEEE);
+      // Check that we indeed found the frame we are looking for.
+      CHECK(!it.done() && (it.frame()->fp() == thread_local_.last_fp_));
+      if (step_count > 1) {
+        // Save old count and action to continue stepping after StepOut.
+        thread_local_.queued_step_count_ = step_count - 1;
       }
 
-      // If we found original frame
-      if (it.frame()->fp() == thread_local_.last_fp_) {
-        if (step_count > 1) {
-          // Save old count and action to continue stepping after
-          // StepOut
-          thread_local_.queued_step_count_ = step_count - 1;
-        }
-
-        // Set up for StepOut to reach target frame
-        step_action = StepOut;
-        step_count = count;
-      }
+      // Set up for StepOut to reach target frame.
+      step_action = StepOut;
+      step_count = count;
     }
 
     // Clear all current stepping setup.
index f3215c93df349497d207b399152aa537c02f3655..bb804206cdd2a8626c22858eac05520448eb0fbe 100644 (file)
@@ -232,14 +232,6 @@ class Debug {
   void PreemptionWhileInDebugger();
   void Iterate(ObjectVisitor* v);
 
-  // TODO(131642): Remove this when fixed.
-  NO_INLINE(void PutValuesOnStackAndDie(int start,
-                                        Address c_entry_fp,
-                                        Address last_fp,
-                                        Address larger_fp,
-                                        int count,
-                                        char* stack,
-                                        int end));
   Object* Break(Arguments args);
   void SetBreakPoint(Handle<JSFunction> function,
                      Handle<Object> break_point_object,
index 561897567378e90e0d6011334aaf3ffbd65648cb..40ed7de4140d1ea5716c5bc625bd46c00d26fa9b 100644 (file)
@@ -132,6 +132,12 @@ static Handle<Object> Invoke(bool is_construct,
         V8::FatalProcessOutOfMemory("JS", true);
       }
     }
+#ifdef ENABLE_DEBUGGER_SUPPORT
+    // Reset stepping state when script exits with uncaught exception.
+    if (isolate->debugger()->IsDebuggerActive()) {
+      isolate->debug()->ClearStepping();
+    }
+#endif  // ENABLE_DEBUGGER_SUPPORT
     return Handle<Object>();
   } else {
     isolate->clear_pending_message();
index 3909da6a7c1f0fb833125dc7d10447f623b9ede6..93479d89a7daa1e009983eda722e73104a4decd0 100644 (file)
@@ -4893,7 +4893,9 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreArrayLiteralElement) {
 // to a built-in function such as Array.forEach.
 RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugCallbackSupportsStepping) {
 #ifdef ENABLE_DEBUGGER_SUPPORT
-  if (!isolate->IsDebuggerActive()) return isolate->heap()->false_value();
+  if (!isolate->IsDebuggerActive() || !isolate->debug()->StepInActive()) {
+    return isolate->heap()->false_value();
+  }
   CONVERT_ARG_CHECKED(Object, callback, 0);
   // We do not step into the callback if it's a builtin or not even a function.
   if (!callback->IsJSFunction() || JSFunction::cast(callback)->IsBuiltin()) {
index 84245946c6422c36c1e2500efbbab26745e829f6..9f52cea2b3d490a846ecdacb86a68e7cd131fd6f 100644 (file)
@@ -7349,4 +7349,47 @@ TEST(DebugBreakInline) {
 }
 
 
+static void DebugEventStepNext(v8::DebugEvent event,
+                               v8::Handle<v8::Object> exec_state,
+                               v8::Handle<v8::Object> event_data,
+                               v8::Handle<v8::Value> data) {
+  if (event == v8::Break) {
+    PrepareStep(StepNext);
+  }
+}
+
+
+static void RunScriptInANewCFrame(const char* source) {
+  v8::TryCatch try_catch;
+  CompileRun(source);
+  CHECK(try_catch.HasCaught());
+}
+
+
+TEST(Regress131642) {
+  // Bug description:
+  // When doing StepNext through the first script, the debugger is not reset
+  // after exiting through exception.  A flawed implementation enabling the
+  // debugger to step into Array.prototype.forEach breaks inside the callback
+  // for forEach in the second script under the assumption that we are in a
+  // recursive call.  In an attempt to step out, we crawl the stack using the
+  // recorded frame pointer from the first script and fail when not finding it
+  // on the stack.
+  v8::HandleScope scope;
+  DebugLocalContext env;
+  v8::Debug::SetDebugEventListener(DebugEventStepNext);
+
+  // We step through the first script.  It exits through an exception.  We run
+  // this inside a new frame to record a different FP than the second script
+  // would expect.
+  const char* script_1 = "debugger; throw new Error();";
+  RunScriptInANewCFrame(script_1);
+
+  // The second script uses forEach.
+  const char* script_2 = "[0].forEach(function() { });";
+  CompileRun(script_2);
+
+  v8::Debug::SetDebugEventListener(NULL);
+}
+
 #endif  // ENABLE_DEBUGGER_SUPPORT