Changeset 147670 in webkit


Ignore:
Timestamp:
Apr 4, 2013 2:25:26 PM (11 years ago)
Author:
oliver@apple.com
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):

Location:
trunk
Files:
3 added
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r147668 r147670  
     12013-04-04  Oliver Hunt  <oliver@apple.com>
     2
     3        Exception stack unwinding doesn't handle inline callframes correctly
     4        https://bugs.webkit.org/show_bug.cgi?id=113952
     5
     6        Reviewed by Geoffrey Garen.
     7
     8        Yay tests!
     9
     10        * fast/js/js-correct-exception-handler-expected.txt: Added.
     11        * fast/js/js-correct-exception-handler.html: Added.
     12        * fast/js/script-tests/js-correct-exception-handler.js: Added.
     13        (throwEventually):
     14        (f.g):
     15        (f):
     16        (test):
     17
    1182013-04-04  Glenn Adams  <glenn@skynav.com>
    219
  • trunk/Source/JavaScriptCore/ChangeLog

    r147669 r147670  
     12013-04-04  Oliver Hunt  <oliver@apple.com>
     2
     3        Exception stack unwinding doesn't handle inline callframes correctly
     4        https://bugs.webkit.org/show_bug.cgi?id=113952
     5
     6        Reviewed by Geoffrey Garen.
     7
     8        The basic problem here is that the exception stack unwinding was
     9        attempting to be "clever" and avoid doing a correct stack walk
     10        as it "knew" inline callframes couldn't have exception handlers.
     11
     12        This used to be safe as the exception handling machinery was
     13        designed to fail gently and just claim that no handler existed.
     14        This was "safe" and even "correct" inasmuch as we currently
     15        don't run any code with exception handlers through the dfg.
     16
     17        This patch fixes the logic by simply making everything uniformly
     18        use the safe stack walking machinery, and making the correct
     19        boundary checks occur everywhere that they should.
     20
     21        * bytecode/CodeBlock.cpp:
     22        (JSC::CodeBlock::findClosureCallForReturnPC):
     23        (JSC::CodeBlock::bytecodeOffset):
     24        * interpreter/Interpreter.cpp:
     25        (JSC):
     26        (JSC::Interpreter::dumpRegisters):
     27        (JSC::Interpreter::unwindCallFrame):
     28        (JSC::getCallerInfo):
     29        (JSC::Interpreter::getStackTrace):
     30        (JSC::Interpreter::retrieveCallerFromVMCode):
     31
    1322013-04-04  Geoffrey Garen  <ggaren@apple.com>
    233
  • trunk/Source/JavaScriptCore/bytecode/CodeBlock.cpp

    r147514 r147670  
    24632463HandlerInfo* CodeBlock::handlerForBytecodeOffset(unsigned bytecodeOffset)
    24642464{
    2465     ASSERT(bytecodeOffset < instructions().size());
     2465    RELEASE_ASSERT(bytecodeOffset < instructions().size());
    24662466
    24672467    if (!m_rareData)
     
    26612661        if (!info.stub->code().executableMemory()->contains(returnAddress.value()))
    26622662            continue;
    2663        
     2663
     2664        RELEASE_ASSERT(info.stub->codeOrigin().bytecodeIndex < info.stub->codeOrigin().maximumBytecodeIndex);
    26642665        return info.stub.get();
    26652666    }
     
    26742675        if (!stub->code().executableMemory()->contains(returnAddress.value()))
    26752676            continue;
     2677        RELEASE_ASSERT(stub->codeOrigin().bytecodeIndex < stub->codeOrigin().maximumBytecodeIndex);
    26762678        return stub;
    26772679    }
     
    27252727                callIndices, callIndices.size(), callReturnOffset, getCallReturnOffset);
    27262728        RELEASE_ASSERT(result->callReturnOffset == callReturnOffset);
     2729        RELEASE_ASSERT(result->bytecodeOffset < instructionCount());
    27272730        return result->bytecodeOffset;
    27282731    }
    2729 
    2730     return findClosureCallForReturnPC(returnAddress)->codeOrigin().bytecodeIndex;
     2732    ClosureCallStubRoutine* closureInfo = findClosureCallForReturnPC(returnAddress);
     2733    CodeOrigin origin = closureInfo->codeOrigin();
     2734    while (InlineCallFrame* inlineCallFrame = origin.inlineCallFrame) {
     2735        if (inlineCallFrame->baselineCodeBlock() == this)
     2736            break;
     2737        origin = inlineCallFrame->caller;
     2738        RELEASE_ASSERT(origin.bytecodeIndex < origin.maximumBytecodeIndex);
     2739    }
     2740    RELEASE_ASSERT(origin.bytecodeIndex < origin.maximumBytecodeIndex);
     2741    unsigned bytecodeIndex = origin.bytecodeIndex;
     2742    RELEASE_ASSERT(bytecodeIndex < instructionCount());
     2743    return bytecodeIndex;
    27312744#endif // ENABLE(JIT)
    27322745
  • 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.