Ignore:
Timestamp:
Apr 4, 2013, 2:25:26 PM (12 years ago)
Author:
[email protected]
Message:

Exception stack unwinding doesn't handle inline callframes correctly
https://bugs.webkit.org/show_bug.cgi?id=113952

Reviewed by Geoffrey Garen.

Source/JavaScriptCore:

The basic problem here is that the exception stack unwinding was
attempting to be "clever" and avoid doing a correct stack walk
as it "knew" inline callframes couldn't have exception handlers.

This used to be safe as the exception handling machinery was
designed to fail gently and just claim that no handler existed.
This was "safe" and even "correct" inasmuch as we currently
don't run any code with exception handlers through the dfg.

This patch fixes the logic by simply making everything uniformly
use the safe stack walking machinery, and making the correct
boundary checks occur everywhere that they should.

  • bytecode/CodeBlock.cpp:

(JSC::CodeBlock::findClosureCallForReturnPC):
(JSC::CodeBlock::bytecodeOffset):

  • interpreter/Interpreter.cpp:

(JSC):
(JSC::Interpreter::dumpRegisters):
(JSC::Interpreter::unwindCallFrame):
(JSC::getCallerInfo):
(JSC::Interpreter::getStackTrace):
(JSC::Interpreter::retrieveCallerFromVMCode):

LayoutTests:

Yay tests!

  • fast/js/js-correct-exception-handler-expected.txt: Added.
  • fast/js/js-correct-exception-handler.html: Added.
  • fast/js/script-tests/js-correct-exception-handler.js: Added.

(throwEventually):
(f.g):
(f):
(test):

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/interpreter/Interpreter.cpp

    r146552 r147670  
    200200
    201201
    202 static CallFrame* getCallerInfo(JSGlobalData*, CallFrame*, int& lineNumber, unsigned& bytecodeOffset);
     202static CallFrame* getCallerInfo(JSGlobalData*, CallFrame*, int& lineNumber, unsigned& bytecodeOffset, CodeBlock*& callerOut);
    203203
    204204// Returns the depth of the scope chain within a given call frame.
     
    423423    unsigned bytecodeOffset = 0;
    424424    int line = 0;
    425     getCallerInfo(&callFrame->globalData(), callFrame, line, bytecodeOffset);
     425    CodeBlock* unusedCallerCodeBlock = 0;
     426    getCallerInfo(&callFrame->globalData(), callFrame, line, bytecodeOffset, unusedCallerCodeBlock);
    426427    dataLogF("[ReturnVPC]                | %10p | %d (line %d)\n", it, bytecodeOffset, line);
    427428    ++it;
     
    507508    if (callerFrame->hasHostCallFrameFlag())
    508509        return false;
    509 
    510     codeBlock = callerFrame->codeBlock();
    511    
    512     // Because of how the JIT records call site->bytecode offset
    513     // information the JIT reports the bytecodeOffset for the returnPC
    514     // to be at the beginning of the opcode that has caused the call.
    515 #if ENABLE(JIT) || ENABLE(LLINT)
    516     bytecodeOffset = codeBlock->bytecodeOffset(callerFrame, callFrame->returnPC());
    517 #endif
    518 
    519     callFrame = callerFrame;
     510    int unusedLineNumber = 0;
     511    callFrame = getCallerInfo(&callFrame->globalData(), callFrame, unusedLineNumber, bytecodeOffset, codeBlock);
    520512    return true;
    521513}
     
    589581}
    590582
    591 static CallFrame* getCallerInfo(JSGlobalData* globalData, CallFrame* callFrame, int& lineNumber, unsigned& bytecodeOffset)
    592 {
    593     UNUSED_PARAM(globalData);
     583static CallFrame* getCallerInfo(JSGlobalData* globalData, CallFrame* callFrame, int& lineNumber, unsigned& bytecodeOffset, CodeBlock*& caller)
     584{
     585    ASSERT_UNUSED(globalData, globalData);
    594586    bytecodeOffset = 0;
    595587    lineNumber = -1;
     
    599591    ASSERT(!callerFrame->hasHostCallFrameFlag());
    600592
    601     if (callerFrame == CallFrame::noCaller() || !callerFrame || !callerFrame->codeBlock())
     593    if (callerFrame == CallFrame::noCaller() || !callerFrame || !callerFrame->codeBlock()) {
     594        caller = 0;
    602595        return callerFrame;
     596    }
    603597   
    604598    CodeBlock* callerCodeBlock = callerFrame->codeBlock();
     
    660654
    661655    RELEASE_ASSERT(callerCodeBlock);
     656    caller = callerCodeBlock;
    662657    lineNumber = callerCodeBlock->lineNumberForBytecodeOffset(bytecodeOffset);
    663658    return callerFrame;
     
    706701        }
    707702        unsigned unusedBytecodeOffset = 0;
    708         callFrame = getCallerInfo(globalData, callFrame, line, unusedBytecodeOffset);
     703        CodeBlock* unusedCallerCodeBlock = 0;
     704        callFrame = getCallerInfo(globalData, callFrame, line, unusedBytecodeOffset, unusedCallerCodeBlock);
    709705    }
    710706}
     
    13821378    int lineNumber;
    13831379    unsigned bytecodeOffset;
    1384     CallFrame* callerFrame = getCallerInfo(&callFrame->globalData(), functionCallFrame, lineNumber, bytecodeOffset);
     1380    CodeBlock* unusedCallerCodeBlock = 0;
     1381    CallFrame* callerFrame = getCallerInfo(&callFrame->globalData(), functionCallFrame, lineNumber, bytecodeOffset, unusedCallerCodeBlock);
    13851382    if (!callerFrame)
    13861383        return jsNull();
     
    13921389    ASSERT(caller.isObject());
    13931390    while (asObject(caller)->inherits(&JSBoundFunction::s_info)) {
    1394         callerFrame = getCallerInfo(&callFrame->globalData(), callerFrame, lineNumber, bytecodeOffset);
     1391        callerFrame = getCallerInfo(&callFrame->globalData(), callerFrame, lineNumber, bytecodeOffset, unusedCallerCodeBlock);
    13951392        if (!callerFrame)
    13961393            return jsNull();
Note: See TracChangeset for help on using the changeset viewer.