Bug 19183 - REGRESSION (r33979): Crash in DebuggerCallFrame::functionName when clicking button in returnEvent-crash.html
Summary: REGRESSION (r33979): Crash in DebuggerCallFrame::functionName when clicking b...
Status: RESOLVED FIXED
Alias: None
Product: WebKit
Classification: Unclassified
Component: JavaScriptCore (show other bugs)
Version: 528+ (Nightly build)
Hardware: All All
: P2 Normal
Assignee: Geoffrey Garen
URL:
Keywords: InRadar
Depends on:
Blocks:
 
Reported: 2008-05-22 01:23 PDT by Adam Roben (:aroben)
Modified: 2008-05-28 13:48 PDT (History)
1 user (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Adam Roben (:aroben) 2008-05-22 01:23:54 PDT
I'm seeing a crash in DebuggerCallFrame::functionName when running WebCore/manual-tests/inspector/returnEvent-crash.html

Steps to repro:
0. Run a debug Windows build or a debug Mac build with MallocScribble enabled
1. Set Safari to open new windows with empty pages
2. Open a new window
3. Open the Inspector
4. Go to WebCore/manual-tests/inspector/returnEvent-crash.html
5. Attach the Inspector's debugger
6. Set a breakpoint on line 9 of returnEvent-crash.html
7. Click the button that says "click me" in returnEvent-crash.html

>	WebKit_debug.dll!KJS::DebuggerCallFrame::functionName()  Line 49 + 0x3 bytes	C++
 	WebKit_debug.dll!WebCore::JavaScriptCallFrame::functionName()  Line 67 + 0xb bytes	C++
 	WebKit_debug.dll!WebCore::JSJavaScriptCallFrame::getValueProperty(KJS::ExecState * exec=0x06a7e820, int token=5)  Line 115 + 0x10 bytes	C++
 	WebKit_debug.dll!KJS::staticValueGetter<WebCore::JSJavaScriptCallFrame>(KJS::ExecState * exec=0x06a7e820, KJS::JSObject * __formal=0x07fa7480, KJS::JSObject * __formal=0x07fa7480, const KJS::PropertySlot & slot={...})  Line 110	C++
 	WebKit_debug.dll!KJS::PropertySlot::getValue(KJS::ExecState * exec=0x06a7e820, KJS::JSObject * originalObject=0x07fa7480, const KJS::Identifier & propertyName={...})  Line 49 + 0x19 bytes	C++
 	WebKit_debug.dll!WebCore::JSQuarantinedObjectWrapper::getOwnPropertySlot(KJS::ExecState * exec=0x0012e804, const KJS::Identifier & identifier={...}, KJS::PropertySlot & slot={...})  Line 113 + 0x1c bytes	C++
 	WebKit_debug.dll!KJS::JSObject::getPropertySlot(KJS::ExecState * exec=0x0012e804, const KJS::Identifier & propertyName={...}, KJS::PropertySlot & slot={...})  Line 553 + 0x1b bytes	C++
 	WebKit_debug.dll!KJS::JSObject::get(KJS::ExecState * exec=0x0012e804, const KJS::Identifier & propertyName={...})  Line 532 + 0x14 bytes	C++
 	WebKit_debug.dll!KJS::Machine::privateExecute(KJS::Machine::ExecutionFlag flag=Normal, KJS::ExecState * exec=0x0012e804, KJS::RegisterFile * registerFile=0x075fffe8, KJS::Register * r=0x07608208, KJS::ScopeChainNode * scopeChain=0x067be9f8, KJS::CodeBlock * codeBlock=0x06d60a60, KJS::JSValue * * exception=0x0012e8a0)  Line 1544 + 0x16 bytes	C++
 	WebKit_debug.dll!KJS::Machine::execute(KJS::FunctionBodyNode * functionBodyNode=0x06a12738, KJS::ExecState * exec=0x067bea88, KJS::FunctionImp * function=0x046533c0, KJS::JSObject * thisObj=0x046526e0, const KJS::List & args={...}, KJS::RegisterFileStack * registerFileStack=0x067be830, KJS::ScopeChainNode * scopeChain=0x06a123e8, KJS::JSValue * * exception=0x0012e8a0)  Line 709 + 0x22 bytes	C++
 	WebKit_debug.dll!KJS::FunctionImp::callAsFunction(KJS::ExecState * exec=0x067bea88, KJS::JSObject * thisObj=0x046526e0, const KJS::List & args={...})  Line 90 + 0x3c bytes	C++
 	WebKit_debug.dll!KJS::JSObject::call(KJS::ExecState * exec=0x067bea88, KJS::JSObject * thisObj=0x046526e0, const KJS::List & args={...})  Line 99 + 0x1b bytes	C++
 	WebKit_debug.dll!JSObjectCallAsFunction(const OpaqueJSContext * ctx=0x067bea88, OpaqueJSValue * object=0x046533c0, OpaqueJSValue * thisObject=0x046526e0, unsigned int argumentCount=0, const OpaqueJSValue * const * arguments=0x00000000, const OpaqueJSValue * * exception=0x0012e9a4)  Line 288 + 0x14 bytes	C++
 	WebKit_debug.dll!WebCore::InspectorController::callFunction(const OpaqueJSContext * context=0x067bea88, OpaqueJSValue * thisObject=0x046526e0, const char * functionName=0x01841e44, unsigned int argumentCount=0, const OpaqueJSValue * const * arguments=0x00000000, const OpaqueJSValue * & exception=0x00000000)  Line 143 + 0x1d bytes	C++
 	WebKit_debug.dll!WebCore::InspectorController::didPause()  Line 2391	C++
 	WebKit_debug.dll!WebCore::dispatchFunctionToListeners(const WTF::HashSet<WebCore::JavaScriptDebugListener *,WTF::PtrHash<WebCore::JavaScriptDebugListener *>,WTF::HashTraits<WebCore::JavaScriptDebugListener *> > & listeners={...}, void (void)* callback=0x00f9c7d0)  Line 306 + 0x13 bytes	C++
 	WebKit_debug.dll!WebCore::JavaScriptDebugServer::dispatchFunctionToListeners(void (void)* callback=0x00f9c7d0, WebCore::Page * page=0x046d3378)  Line 321 + 0xd bytes	C++
 	WebKit_debug.dll!WebCore::JavaScriptDebugServer::pauseIfNeeded(WebCore::Page * page=0x046d3378)  Line 406	C++
 	WebKit_debug.dll!WebCore::JavaScriptDebugServer::atStatement(const KJS::DebuggerCallFrame & debuggerCallFrame={...}, int sourceID=41, int lineNumber=9)  Line 435	C++
 	WebKit_debug.dll!KJS::Machine::debug(KJS::ExecState * exec=0x0012f0b8, const KJS::Instruction * vPC=0x07607098, const KJS::CodeBlock * codeBlock=0x076065a8, KJS::ScopeChainNode * scopeChain=0x06ae3cb0, KJS::Register * * registerBase=0x07605808, KJS::Register * r=0x06aea738)  Line 812 + 0x22 bytes	C++
 	WebKit_debug.dll!KJS::Machine::privateExecute(KJS::Machine::ExecutionFlag flag=Normal, KJS::ExecState * exec=0x0012f0b8, KJS::RegisterFile * registerFile=0x076057f8, KJS::Register * r=0x06aea738, KJS::ScopeChainNode * scopeChain=0x06ae3cb0, KJS::CodeBlock * codeBlock=0x076065a8, KJS::JSValue * * exception=0x0012f154)  Line 2233	C++
 	WebKit_debug.dll!KJS::Machine::execute(KJS::FunctionBodyNode * functionBodyNode=0x07605e40, KJS::ExecState * exec=0x06a7e820, KJS::FunctionImp * function=0x05650620, KJS::JSObject * thisObj=0x07fb4160, const KJS::List & args={...}, KJS::RegisterFileStack * registerFileStack=0x06c0e5c0, KJS::ScopeChainNode * scopeChain=0x076058a0, KJS::JSValue * * exception=0x0012f154)  Line 709 + 0x22 bytes	C++
 	WebKit_debug.dll!KJS::FunctionImp::callAsFunction(KJS::ExecState * exec=0x06a7e820, KJS::JSObject * thisObj=0x07fb4160, const KJS::List & args={...})  Line 90 + 0x3c bytes	C++
 	WebKit_debug.dll!KJS::JSObject::call(KJS::ExecState * exec=0x06a7e820, KJS::JSObject * thisObj=0x07fb4160, const KJS::List & args={...})  Line 99 + 0x1b bytes	C++
 	WebKit_debug.dll!WebCore::JSAbstractEventListener::handleEvent(WebCore::Event * ele=0x07367150, bool isWindowEvent=false)  Line 100 + 0x14 bytes	C++
 	WebKit_debug.dll!WebCore::EventTarget::handleLocalEvents(WebCore::EventTargetNode * referenceNode=0x072fc8c8, WebCore::Event * evt=0x07367150, bool useCapture=false)  Line 314 + 0x2e bytes	C++
 	WebKit_debug.dll!WebCore::EventTargetNode::handleLocalEvents(WebCore::Event * evt=0x07367150, bool useCapture=false)  Line 106	C++
 	WebKit_debug.dll!WebCore::EventTarget::dispatchGenericEvent(WebCore::EventTargetNode * referenceNode=0x072fc8c8, WTF::PassRefPtr<WebCore::Event> e={...}, int & __formal=0, bool tempEvent=true)  Line 212 + 0x1d bytes	C++
 	WebKit_debug.dll!WebCore::EventTargetNode::dispatchEvent(WTF::PassRefPtr<WebCore::Event> e={...}, int & ec=0, bool tempEvent=true)  Line 121 + 0x1e bytes	C++
 	WebKit_debug.dll!WebCore::EventTargetNode::dispatchMouseEvent(const WebCore::AtomicString & eventType={...}, int button=0, int detail=1, int pageX=41, int pageY=93, int screenX=545, int screenY=190, bool ctrlKey=false, bool altKey=false, bool shiftKey=false, bool metaKey=false, bool isSimulated=false, WebCore::Node * relatedTargetArg=0x00000000, WTF::PassRefPtr<WebCore::Event> underlyingEvent={...})  Line 297	C++
 	WebKit_debug.dll!WebCore::EventTargetNode::dispatchMouseEvent(const WebCore::PlatformMouseEvent & event={...}, const WebCore::AtomicString & eventType={...}, int detail=1, WebCore::Node * relatedTarget=0x00000000)  Line 215	C++
 	WebKit_debug.dll!WebCore::EventHandler::dispatchMouseEvent(const WebCore::AtomicString & eventType={...}, WebCore::Node * targetNode=0x072fc8c8, bool cancelable=true, int clickCount=1, const WebCore::PlatformMouseEvent & mouseEvent={...}, bool setUnder=true)  Line 1279 + 0x29 bytes	C++
 	WebKit_debug.dll!WebCore::EventHandler::handleMouseReleaseEvent(const WebCore::PlatformMouseEvent & mouseEvent={...})  Line 1101 + 0x28 bytes	C++
 	WebKit_debug.dll!WebView::handleMouseEvent(unsigned int message=514, unsigned int wParam=0, long lParam=6094889)  Line 1244	C++
 	WebKit_debug.dll!WebViewWndProc(HWND__ * hWnd=0x002b06d0, unsigned int message=514, unsigned int wParam=0, long lParam=6094889)  Line 1673 + 0x14 bytes	C++
Comment 1 Mark Rowe (bdash) 2008-05-22 01:25:15 PDT
<rdar://problem/5955362>
Comment 2 Timothy Hatcher 2008-05-24 21:49:17 PDT
I have not been able to reproduce this.
Comment 3 Adam Roben (:aroben) 2008-05-27 07:54:35 PDT
Geoff said he could reproduce with MallocScribble enabled. It's quite easy to reproduce with a Windows debug build.
Comment 4 Adam Roben (:aroben) 2008-05-27 09:22:32 PDT
I can still reproduce this in ToT today. I will try to debug further.
Comment 5 Adam Roben (:aroben) 2008-05-27 09:49:04 PDT
m_codeBlock->numLocals is returning 0xcdcdcdcc, which in a debug Windows build means this is free()'d memory.
Comment 6 Adam Roben (:aroben) 2008-05-27 10:28:32 PDT
(In reply to comment #5)
> m_codeBlock->numLocals is returning 0xcdcdcdcc, which in a debug Windows build
> means this is free()'d memory.

Sorry, 0xcdcdcdcd means uninitialized memory, not free()d memory.

Comment 7 Adam Roben (:aroben) 2008-05-27 10:36:29 PDT
It looks as if the JavaScriptCallFrame in question is the one created when the contents of the <script> tag is parsed. I'm not sure why that call frame is being used here. Instead we should be using the call frames relevant to the script execution.
Comment 8 Adam Roben (:aroben) 2008-05-27 10:46:43 PDT
OK, I think I know what's going on here.

The code block when parsing the contents of the <script> element is:

[   0] new_func          lr8, f0
[   3] new_func          lr9, f1
[   6] load              tr0, undefined(@k0)
[   9] debug             willExecuteStatement, -1, -1
[  13] debug             willExecuteStatement, -1, -1
[  17] end               tr0

Notice that there are two willExecuteStatement calls but no {didEnter,willLeave}CallFrame calls. At the end of this code block, JavaScriptDebugServer::m_currentCallFrame will hold the call frame from the last willExecuteStatement call. Call this call frame "A".

The code block when executing the onclick handler of the "click me" button is:

[   0] debug             didEnterCallFrame, 16, 17
[   4] debug             willExecuteStatement, 17, 17
[   8] resolve_func      tr0, tr1, test(@id0)
[  12] call              tr0, tr1, tr0, 12, 1
[  18] load              tr0, undefined(@k0)
[  21] debug             willLeaveCallFrame, 16, 17
[  25] ret               tr0

The first call to didEnterCallFrame will cause a new JavaScriptCallFrame to be created. Call this call frame "B". B's "caller" will be set to A. But by this time the CodeBlock that A holds might already have been deleted.

The crash occurs when the Inspector is building up the call stack to display in the debugger. It crawls up from B to A via JavaScriptCallFrame::caller, and then calls DebuggerCallFrame::functionName, which dereferences the deleted CodeBlock.
Comment 9 Geoffrey Garen 2008-05-28 13:48:11 PDT
Committed revision 34182.