Bug 136080

Summary: Crash in jsc-layout-tests.yaml/js/script-tests/reentrant-caching.js
Product: WebKit Reporter: Mark Lam <mark.lam>
Component: JavaScriptCoreAssignee: Michael Saboff <msaboff>
Status: RESOLVED FIXED    
Severity: Normal CC: fpizlo, ggaren, mmirman, msaboff, oliver, webkit-bug-importer
Priority: P2 Keywords: InRadar
Version: 528+ (Nightly build)   
Hardware: Unspecified   
OS: Unspecified   
Attachments:
Description Flags
Patch mark.lam: review+

Description Mark Lam 2014-08-19 11:27:57 PDT
This crash only manifests when I run the test as follows:
$ JSC_useLLInt=false ... jsc jsc-stress-results/.tests/jsc-layout-tests.yaml/js/script-tests/reentrant-caching.js

Some tidbits that may or may not be related to the root cause:
1. If I disable the FTL, it stops reproducing.
2. If I re-enable the LLINT, it stops reproducing.
3. The test is doing some deep recursion, and have ultimately encountered an eminent stack overflow.  The backtrace below shows the top frames on the stack at the point of the crash.
4. At frame 4, the callFrame that we're trying to get the callee() from appears to be invalid (or at least, I can't use my debugPrintCallFrame on it).  Needs more investigation.

(lldb) bt 30
* thread #1: tid = 0x367234, 0x00000001008cc1fa JavaScriptCore`WTFCrash + 42 at Assertions.cpp:329, queue = 'com.apple.main-thread, stop reason = EXC_BAD_ACCESS (code=1, address=0xbbadbeef)
    frame #0: 0x00000001008cc1fa JavaScriptCore`WTFCrash + 42 at Assertions.cpp:329
    frame #1: 0x00000001000807a1 JavaScriptCore`JSC::asObject(cell=0x00007fff5f8200f0) + 65 at JSObject.h:1189
    frame #2: 0x0000000100080750 JavaScriptCore`JSC::asObject(value=JSValue at 0x00007fff5f81f3f8) + 32 at JSObject.h:1195
    frame #3: 0x00000001000806e5 JavaScriptCore`JSC::Register::function(this=0x00007fff5f81ffd0) const + 85 at JSObject.h:1472
    frame #4: 0x000000010008060c JavaScriptCore`JSC::ExecState::callee(this=0x00007fff5f81ffb0) const + 28 at CallFrame.h:46
    frame #5: 0x0000000100823492 JavaScriptCore`JSC::StackVisitor::readNonInlinedFrame(this=0x00007fff5f81f540, callFrame=0x00007fff5f81ffb0, codeOrigin=0x0000000000000000) + 114 at StackVisitor.cpp:114
    frame #6: 0x0000000100823113 JavaScriptCore`JSC::StackVisitor::readFrame(this=0x00007fff5f81f540, callFrame=0x00007fff5f81ffb0) + 147 at StackVisitor.cpp:84
    frame #7: 0x0000000100823254 JavaScriptCore`JSC::StackVisitor::gotoNextFrame(this=0x00007fff5f81f540) + 116 at StackVisitor.cpp:59
    frame #8: 0x0000000100531788 JavaScriptCore`void JSC::StackVisitor::visit<JSC::GetStackTraceFunctor>(startFrame=0x00007fff5f81fee0, functor=0x00007fff5f81f5d0) + 104 at StackVisitor.h:130
    frame #9: 0x000000010052fe9d JavaScriptCore`void JSC::ExecState::iterate<JSC::GetStackTraceFunctor>(this=0x00007fff5f81fee0, functor=0x00007fff5f81f5d0) + 29 at CallFrame.h:260
    frame #10: 0x000000010052bc74 JavaScriptCore`JSC::Interpreter::getStackTrace(this=0x0000000106901be0, results=0x00007fff5f81f7a8, maxStackSize=18446744073709551615) + 100 at Interpreter.cpp:604
    frame #11: 0x0000000100872ee2 JavaScriptCore`JSC::VM::throwException(this=0x0000000102007800, exec=0x00007fff5f81fee0, error=JSValue at 0x00007fff5f81f7c0) + 306 at VM.cpp:644
    frame #12: 0x0000000100873a18 JavaScriptCore`JSC::VM::throwException(this=0x0000000102007800, exec=0x00007fff5f81fee0, error=0x0000000108971190) + 72 at VM.cpp:692
    frame #13: 0x0000000100556e3d JavaScriptCore`operationThrowStackOverflowError(exec=0x00007fff5f81f8b0, codeBlock=0x0000000108a51540) + 157 at JITOperations.cpp:91
    frame #14: 0x00003bf360803373
    frame #15: 0x00000001006b2ed9 JavaScriptCore`vmEntryToJavaScript + 361
    frame #16: 0x0000000100548b3d JavaScriptCore`JSC::JITCode::execute(this=0x00000001088fc050, vm=0x0000000102007800, protoCallFrame=0x00007fff5f81fa70) + 45 at JITCode.cpp:47
    frame #17: 0x000000010052dc7a JavaScriptCore`JSC::Interpreter::executeCall(this=0x0000000106901be0, callFrame=0x00007fff5f81fee0, function=0x0000000106ec6030, callType=CallTypeJS, callData=0x00007fff5f81fc80, thisValue=JSValue at 0x00007fff5f81fb20, args=0x00007fff5f81fc58) + 1450 at Interpreter.cpp:986
    frame #18: 0x000000010010bcce JavaScriptCore`JSC::call(exec=0x00007fff5f81fee0, functionObject=JSValue at 0x00007fff5f81fc08, callType=CallTypeJS, callData=0x00007fff5f81fc80, thisValue=JSValue at 0x00007fff5f81fbf0, args=0x00007fff5f81fc58) + 190 at CallData.cpp:39
    frame #19: 0x00000001004b9c85 JavaScriptCore`JSC::callGetter(exec=0x00007fff5f81fee0, base=JSValue at 0x00007fff5f81fca8, getterSetter=JSValue at 0x00007fff5f81fca0) + 261 at GetterSetter.cpp:86
    frame #20: 0x00000001007e4314 JavaScriptCore`JSC::PropertySlot::functionGetter(this=0x00007fff5f81fe38, exec=0x00007fff5f81fee0) const + 148 at PropertySlot.cpp:32
    frame #21: 0x000000010008793d JavaScriptCore`JSC::PropertySlot::getValue(this=0x00007fff5f81fe38, exec=0x00007fff5f81fee0, propertyName=PropertyName at 0x00007fff5f81fd50) const + 93 at JSObject.h:1581
    frame #22: 0x00000001000ab1f3 JavaScriptCore`JSC::JSValue::get(this=0x00007fff5f81fe70, exec=0x00007fff5f81fee0, propertyName=PropertyName at 0x00007fff5f81fdc0, slot=0x00007fff5f81fe38) const + 291 at JSCJSValueInlines.h:696
    frame #23: 0x00000001005572bd JavaScriptCore`operationGetByIdOptimize(exec=0x00007fff5f81fee0, stubInfo=0x0000000102a01130, base=4411200208, uid=0x0000000106906a60) + 269 at JITOperations.cpp:164
    frame #24: 0x00003bf3a0800293
    frame #25: 0x00003bf36080310a
    frame #26: 0x00000001006b2ed9 JavaScriptCore`vmEntryToJavaScript + 361
    frame #27: 0x0000000100548b3d JavaScriptCore`JSC::JITCode::execute(this=0x00000001088fc050, vm=0x0000000102007800, protoCallFrame=0x00007fff5f8200f0) + 45 at JITCode.cpp:47
    frame #28: 0x000000010052dc7a JavaScriptCore`JSC::Interpreter::executeCall(this=0x0000000106901be0, callFrame=0x00007fff5f820560, function=0x0000000106ec6070, callType=CallTypeJS, callData=0x00007fff5f820300, thisValue=JSValue at 0x00007fff5f8201a0, args=0x00007fff5f8202d8) + 1450 at Interpreter.cpp:986
    frame #29: 0x000000010010bcce JavaScriptCore`JSC::call(exec=0x00007fff5f820560, functionObject=JSValue at 0x00007fff5f820288, callType=CallTypeJS, callData=0x00007fff5f820300, thisValue=JSValue at 0x00007fff5f820270, args=0x00007fff5f8202d8) + 190 at CallData.cpp:39
    ...

Here's an instance of this crash in the wild: http://build.webkit.org/builders/Apple%20Mavericks%20Debug%20WK1%20%28Tests%29/builds/7159/steps/jscore-test/logs/stdio
Comment 1 Radar WebKit Bug Importer 2014-08-19 11:28:52 PDT
<rdar://problem/18065110>
Comment 2 Michael Saboff 2014-08-19 12:39:19 PDT
Taking this bug because <https://trac.webkit.org/changeset/163179> is likely responsible for it.
Comment 3 Michael Saboff 2014-08-19 15:13:25 PDT
The issue is that operationThrowStackOverflowError() unwinds one frame, pointed to by callerFrame.  We create a NativeCallFrameTracer object to "wrap" the unwinding.  NativeCallFrameTracer sets VM::topCallFrame, which is used as the frame to start unwinding from.  If the callee frame, pointed to by exec, is the direct callee of a VM entry frame, then "calleeFrame" will point to a frame somewhat above VM entry frame, BUT we haven't updated VM::topVMEntryFrame accordingly.  This messes up unwinding.

Patch in progress.
Comment 4 Michael Saboff 2014-08-19 16:50:35 PDT
Created attachment 236835 [details]
Patch
Comment 5 Mark Lam 2014-08-19 17:16:16 PDT
Comment on attachment 236835 [details]
Patch

Please add a comment to the ChangeLog to explain the difference between when we should use one constructor and the other, so as to explain why only these 3 cases have been fixed to use the new constructor.

r=me with comment added.
Comment 6 Michael Saboff 2014-08-19 17:37:13 PDT
Committed r172792: <http://trac.webkit.org/changeset/172792>