From f051e2fe04f661b2e0df6ed48c4dd9edb74473ae Mon Sep 17 00:00:00 2001 From: Mike Magruder Date: Fri, 12 Jul 2013 15:04:40 -0700 Subject: [PATCH] Don't go back to the interpreter after the end of pseudo main when debugging Fix a long-standing bug where if you step off of the end of pseudo main we'd segfault in the interpreter loop. To get this we have to have a breakpoint in the final TC in pseudo main, and have that called from another TC, then Step or Next off the end. We'd end up with a PC of zero after the ret, which makes sense, but the logic after interpreting a block of code to stay in the interpreter when debugging was blind to this case. --- hphp/runtime/base/execution_context.h | 1 + hphp/runtime/vm/bytecode.cpp | 21 ++++++++++--------- hphp/test/quick/debugger/flow_pseudomain.php | 5 +++++ .../debugger/flow_pseudomain.php.expectf | 13 ++++++++++++ .../quick/debugger/flow_pseudomain.php.in | 3 +++ 5 files changed, 33 insertions(+), 10 deletions(-) create mode 100644 hphp/test/quick/debugger/flow_pseudomain.php create mode 100644 hphp/test/quick/debugger/flow_pseudomain.php.expectf create mode 100644 hphp/test/quick/debugger/flow_pseudomain.php.in diff --git a/hphp/runtime/base/execution_context.h b/hphp/runtime/base/execution_context.h index f537d02b7..30f326017 100644 --- a/hphp/runtime/base/execution_context.h +++ b/hphp/runtime/base/execution_context.h @@ -687,6 +687,7 @@ private: bool prepareArrayArgs(ActRec* ar, ArrayData* args); void recordCodeCoverage(PC pc); bool isReturnHelper(uintptr_t address); + void switchModeForDebugger(); int m_coverPrevLine; HPHP::Unit* m_coverPrevUnit; Array m_evaledArgs; diff --git a/hphp/runtime/vm/bytecode.cpp b/hphp/runtime/vm/bytecode.cpp index 4678be6d4..54afbae00 100644 --- a/hphp/runtime/vm/bytecode.cpp +++ b/hphp/runtime/vm/bytecode.cpp @@ -7134,22 +7134,23 @@ void VMExecutionContext::dispatch() { } } -void VMExecutionContext::dispatchN(int numInstrs) { - dispatchImpl(numInstrs); - // We are about to go back to Jit, check whether we should - // stick with interpreter - if (DEBUGGER_FORCE_INTR) { +// We are about to go back to translated code, check whether we should +// stick with the interpreter. NB: if we've just executed a return +// from pseudomain, then there's no PC and no more code to interpret. +void VMExecutionContext::switchModeForDebugger() { + if (DEBUGGER_FORCE_INTR && (getPC() != 0)) { throw VMSwitchMode(); } } +void VMExecutionContext::dispatchN(int numInstrs) { + dispatchImpl(numInstrs); + switchModeForDebugger(); +} + void VMExecutionContext::dispatchBB() { dispatchImpl(0); - // We are about to go back to Jit, check whether we should - // stick with interpreter - if (DEBUGGER_FORCE_INTR) { - throw VMSwitchMode(); - } + switchModeForDebugger(); } void VMExecutionContext::recordCodeCoverage(PC pc) { diff --git a/hphp/test/quick/debugger/flow_pseudomain.php b/hphp/test/quick/debugger/flow_pseudomain.php new file mode 100644 index 000000000..7b76b07f6 --- /dev/null +++ b/hphp/test/quick/debugger/flow_pseudomain.php @@ -0,0 +1,5 @@ +