Changeset 228488 in webkit


Ignore:
Timestamp:
Feb 14, 2018 3:25:52 PM (6 years ago)
Author:
sbarati@apple.com
Message:

Setting a VMTrap shouldn't look at topCallFrame since that may imply we're in C code and holding the malloc lock
https://bugs.webkit.org/show_bug.cgi?id=182801

Reviewed by Keith Miller.

JSTests:

  • stress/watchdog-dont-malloc-when-in-c-code.js: Added.

Source/JavaScriptCore:

VMTraps would sometimes install traps when it paused the JS thread when it
was in C code. This is wrong, as installing traps mallocs, and the JS thread
may have been holding the malloc lock while in C code. This could lead to a
deadlock when C code was holding the malloc lock.

This patch makes it so that we only install traps when we've proven the PC
is in JIT or LLInt code. If we're in JIT/LLInt code, we are guaranteed that
we're not holding the malloc lock.

  • jsc.cpp:

(GlobalObject::finishCreation):
(functionMallocInALoop):

  • runtime/VMTraps.cpp:

(JSC::VMTraps::tryInstallTrapBreakpoints):

Location:
trunk
Files:
1 added
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/JSTests/ChangeLog

    r228474 r228488  
     12018-02-14  Saam Barati  <sbarati@apple.com>
     2
     3        Setting a VMTrap shouldn't look at topCallFrame since that may imply we're in C code and holding the malloc lock
     4        https://bugs.webkit.org/show_bug.cgi?id=182801
     5
     6        Reviewed by Keith Miller.
     7
     8        * stress/watchdog-dont-malloc-when-in-c-code.js: Added.
     9
    1102018-02-14  Ryan Haddad  <ryanhaddad@apple.com>
    211
  • trunk/Source/JavaScriptCore/ChangeLog

    r228481 r228488  
     12018-02-14  Saam Barati  <sbarati@apple.com>
     2
     3        Setting a VMTrap shouldn't look at topCallFrame since that may imply we're in C code and holding the malloc lock
     4        https://bugs.webkit.org/show_bug.cgi?id=182801
     5
     6        Reviewed by Keith Miller.
     7
     8        VMTraps would sometimes install traps when it paused the JS thread when it
     9        was in C code. This is wrong, as installing traps mallocs, and the JS thread
     10        may have been holding the malloc lock while in C code. This could lead to a
     11        deadlock when C code was holding the malloc lock.
     12       
     13        This patch makes it so that we only install traps when we've proven the PC
     14        is in JIT or LLInt code. If we're in JIT/LLInt code, we are guaranteed that
     15        we're not holding the malloc lock.
     16
     17        * jsc.cpp:
     18        (GlobalObject::finishCreation):
     19        (functionMallocInALoop):
     20        * runtime/VMTraps.cpp:
     21        (JSC::VMTraps::tryInstallTrapBreakpoints):
     22
    1232018-02-14  Michael Saboff  <msaboff@apple.com>
    224
  • trunk/Source/JavaScriptCore/jsc.cpp

    r227898 r228488  
    343343static EncodedJSValue JSC_HOST_CALL functionFlashHeapAccess(ExecState*);
    344344static EncodedJSValue JSC_HOST_CALL functionDisableRichSourceInfo(ExecState*);
     345static EncodedJSValue JSC_HOST_CALL functionMallocInALoop(ExecState*);
    345346
    346347struct Script {
     
    600601
    601602        addFunction(vm, "disableRichSourceInfo", functionDisableRichSourceInfo, 0);
     603        addFunction(vm, "mallocInALoop", functionMallocInALoop, 0);
    602604    }
    603605   
     
    17491751}
    17501752
     1753EncodedJSValue JSC_HOST_CALL functionMallocInALoop(ExecState*)
     1754{
     1755    Vector<void*> ptrs;
     1756    for (unsigned i = 0; i < 5000; ++i)
     1757        ptrs.append(fastMalloc(1024 * 2));
     1758    for (void* ptr : ptrs)
     1759        fastFree(ptr);
     1760    return JSValue::encode(jsUndefined());
     1761}
     1762
    17511763template<typename ValueType>
    17521764typename std::enable_if<!std::is_fundamental<ValueType>::value>::type addOption(VM&, JSObject*, Identifier, ValueType) { }
  • trunk/Source/JavaScriptCore/runtime/VMTraps.cpp

    r226783 r228488  
    7373}
    7474
    75 inline CallFrame* sanitizedTopCallFrame(CallFrame* topCallFrame)
    76 {
    77 #if !defined(NDEBUG) && !CPU(ARM) && !CPU(MIPS)
    78     // prepareForExternalCall() in DFGSpeculativeJIT.h may set topCallFrame to a bad word
    79     // before calling native functions, but tryInstallTrapBreakpoints() below expects
    80     // topCallFrame to be null if not set.
    81 #if USE(JSVALUE64)
    82     const uintptr_t badBeefWord = 0xbadbeef0badbeef;
    83 #else
    84     const uintptr_t badBeefWord = 0xbadbeef;
    85 #endif
    86     if (topCallFrame == reinterpret_cast<CallFrame*>(badBeefWord))
    87         topCallFrame = nullptr;
    88 #endif
    89     return topCallFrame;
    90 }
    91 
    9275static bool isSaneFrame(CallFrame* frame, CallFrame* calleeFrame, EntryFrame* entryFrame, StackBounds stackBounds)
    9376{
     
    10588    VM& vm = this->vm();
    10689    void* trapPC = context.trapPC;
     90    // We must ensure we're in JIT/LLint code. If we are, we know a few things:
     91    // - The JS thread isn't holding the malloc lock. Therefore, it's safe to malloc below.
     92    // - The JS thread isn't holding the CodeBlockSet lock.
     93    // If we're not in JIT/LLInt code, we can't run the C++ code below because it
     94    // mallocs, and we must prove the JS thread isn't holding the malloc lock
     95    // to be able to do that without risking a deadlock.
     96    if (!isJITPC(trapPC) && !LLInt::isLLIntPC(trapPC))
     97        return;
    10798
    10899    CallFrame* callFrame = reinterpret_cast<CallFrame*>(context.framePointer);
    109100
    110     auto& lock = vm.heap.codeBlockSet().getLock();
    111     // If the target thread is in C++ code it might be holding the codeBlockSet lock.
    112     // if it's in JIT code then it cannot be holding that lock but the GC might be.
    113     auto codeBlockSetLocker = isJITPC(trapPC) ? holdLock(lock) : tryHoldLock(lock);
    114     if (!codeBlockSetLocker)
    115         return; // Let the SignalSender try again later.
    116 
    117     if (!isJITPC(trapPC) && !LLInt::isLLIntPC(trapPC)) {
    118         // We resort to topCallFrame to see if we can get anything
    119         // useful. We usually get here when we're executing C code.
    120         callFrame = sanitizedTopCallFrame(vm.topCallFrame);
    121     }
     101    auto codeBlockSetLocker = holdLock(vm.heap.codeBlockSet().getLock());
    122102
    123103    CodeBlock* foundCodeBlock = nullptr;
Note: See TracChangeset for help on using the changeset viewer.