Ignore:
Timestamp:
Sep 6, 2015, 10:19:28 PM (10 years ago)
Author:
[email protected]
Message:

StackOverflow stack unwinding should stop at native frames.
https://bugs.webkit.org/show_bug.cgi?id=148749

Reviewed by Michael Saboff.

In the present code, after ping-pong'ing back and forth between native and JS
code a few times, if we have a stack overflow on re-entry into the VM to run
JS code's whose stack frame would overflow the JS stack, the code will end up
unwinding past the native function that is making the call to re-enter the VM.
As a result, any clean up code (e.g. destructors for stack variables) in the
skipped native function frame (and its chain of native function callers) will
not be called.

This patch is based on the Michael Saboff's fix of this issue landed on the
jsc-tailcall branch: http://trac.webkit.org/changeset/188555

We now check for the case where there are no JS frames to unwind since the
last native frame, and treat the exception as an unhandled exception. The
native function is responsible for further propagating the exception if needed.

Other supporting work:

  1. Remove vm->vmEntryFrameForThrow. It should always be the same as vm->topVMEntryFrame.
  2. Change operationThrowStackOverflowError() to use the throwStackOverflowError() helper function instead of rolling its own.
  3. Added a test that exercises this edge case. The test should not hang or crash.
  • API/tests/PingPongStackOverflowTest.cpp: Added.

(PingPongStackOverflowObject_hasInstance):
(testPingPongStackOverflow):

  • API/tests/PingPongStackOverflowTest.h: Added.
  • API/tests/testapi.c:

(main):

(JSC::ExecState::operator=):
(JSC::ExecState::callerFrame):
(JSC::ExecState::callerFrameOrVMEntryFrame):
(JSC::ExecState::argIndexForRegister):
(JSC::ExecState::callerFrameAndPC):

  • interpreter/Interpreter.cpp:

(JSC::UnwindFunctor::UnwindFunctor):
(JSC::UnwindFunctor::operator()):
(JSC::Interpreter::unwind):

  • interpreter/Interpreter.h:

(JSC::NativeCallFrameTracer::NativeCallFrameTracer):
(JSC::Interpreter::sampler):

  • jit/CCallHelpers.h:

(JSC::CCallHelpers::jumpToExceptionHandler):

  • jit/JITExceptions.cpp:

(JSC::genericUnwind):

  • jit/JITExceptions.h:
  • jit/JITOpcodes.cpp:

(JSC::JIT::emit_op_catch):

  • jit/JITOpcodes32_64.cpp:

(JSC::JIT::emit_op_catch):

  • jit/JITOperations.cpp:
  • llint/LowLevelInterpreter32_64.asm:
  • llint/LowLevelInterpreter64.asm:
  • runtime/VM.h:

(JSC::VM::exceptionOffset):
(JSC::VM::callFrameForThrowOffset):
(JSC::VM::vmEntryFrameForThrowOffset): Deleted.
(JSC::VM::topVMEntryFrameOffset): Deleted.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/jit/JITExceptions.cpp

    r189417 r189454  
    4141namespace JSC {
    4242
    43 void genericUnwind(VM* vm, ExecState* callFrame)
     43void genericUnwind(VM* vm, ExecState* callFrame, UnwindStart unwindStart)
    4444{
    4545    if (Options::breakOnThrow()) {
     
    5050    Exception* exception = vm->exception();
    5151    RELEASE_ASSERT(exception);
    52     VMEntryFrame* vmEntryFrame = vm->topVMEntryFrame;
    53     HandlerInfo* handler = vm->interpreter->unwind(vmEntryFrame, callFrame, exception); // This may update vmEntryFrame and callFrame.
     52    HandlerInfo* handler = vm->interpreter->unwind(*vm, callFrame, exception, unwindStart); // This may update callFrame.
    5453
    5554    void* catchRoutine;
     
    6564        catchRoutine = LLInt::getCodePtr(handleUncaughtException);
    6665   
    67     vm->vmEntryFrameForThrow = vmEntryFrame;
    6866    vm->callFrameForThrow = callFrame;
    6967    vm->targetMachinePCForThrow = catchRoutine;
Note: See TracChangeset for help on using the changeset viewer.