Bug 24247

Summary: Crash in WebCore::RenderBlock::deleteLineBoxTree()
Product: WebKit Reporter: Scott Violet <sky>
Component: WebCore Misc.Assignee: Nobody <webkit-unassigned>
Status: RESOLVED DUPLICATE    
Severity: Normal CC: bdakin
Priority: P1    
Version: 528+ (Nightly build)   
Hardware: PC   
OS: All   
Attachments:
Description Flags
Test case for first assertion (crashes safari!)
none
stack trace of test case crashing Safari 4 public beta none

Description Scott Violet 2009-02-27 13:29:04 PST
This showed up in a recent Chrome build. Here's the stack:

 [renderblock.cpp:387] - WebCore::RenderBlock::deleteLineBoxTree()
[renderinline.cpp:325] - WebCore::RenderInline::splitFlow(WebCore::RenderObject *,WebCore::RenderBlock *,WebCore::RenderObject *,WebCore::RenderBoxModelObject *)
[renderinline.cpp:217] - WebCore::RenderInline::addChildIgnoringContinuation(WebCore::RenderObject *,WebCore::RenderObject *)
[renderinline.cpp:294] - WebCore::RenderInline::splitInlines(WebCore::RenderBlock *,WebCore::RenderBlock *,WebCore::RenderBlock *,WebCore::RenderObject *,WebCore::RenderBoxModelObject *)
[renderinline.cpp:357] - WebCore::RenderInline::splitFlow(WebCore::RenderObject *,WebCore::RenderBlock *,WebCore::RenderObject *,WebCore::RenderBoxModelObject *)
[renderinline.cpp:217] - WebCore::RenderInline::addChildIgnoringContinuation(WebCore::RenderObject *,WebCore::RenderObject *)
       [node.cpp:1241] - WebCore::Node::createRendererIfNeeded()
     [element.cpp:686] - WebCore::Element::attach()
[containernode.cpp:497] - WebCore::ContainerNode::appendChild(WTF::PassRefPtr&lt;WebCore::Node&gt;,int &amp;,bool)
      [v8node.cpp:270] - WebCore::NodeInternal::appendChildCallback

The minidump shows that in RenderInline::splitFlow() containingBlock() returns NULL, so that we end up invoking deleteLineBoxTree on NULL and crash.

This containingBlock() is NULL because in the innermost while in RenderInline::splitInlines addChildIgnoringContinuation is invoked on a cloned RenderInline which has no containingBlock().

I couldn't find a URL to reproduce this, nor am I sure of the right approach in fixing it. I'll poke some more at. Suggestions on fixing or creating a page that hits this code path are most welcome.
Comment 1 Scott Violet 2009-02-27 14:02:43 PST
One more comment, the bottom of the stack has:

v8::internal::Builtin_HandleApiCall

on it, meaning this is triggered by some JavaScript. Is it possible we're letting JavaScript do something it shouldn't?
Comment 2 Scott Violet 2009-03-03 16:22:02 PST
I don't have a distilled case yet, but I can repro this. Before the crash I'm hitting an ASSERT in RenderObjectChildList::appendChildNode because newChild is a table selection. Here's the stack:

 	chrome.dll!WebCore::RenderTableSection::isTableSection()  Line 50	C++
>	chrome.dll!WebCore::RenderObjectChildList::appendChildNode(WebCore::RenderObject * owner=0x06a43b54, WebCore::RenderObject * newChild=0x0512fa64, bool fullAppend=true)  Line 135 + 0x2f bytes	C++
 	chrome.dll!WebCore::RenderInline::splitFlow(WebCore::RenderObject * beforeChild=0x00000000, WebCore::RenderBlock * newBlockBox=0x06a43a04, WebCore::RenderObject * newChild=0x06a1d174, WebCore::RenderBoxModelObject * oldCont=0x00000000)  Line 353	C++
 	chrome.dll!WebCore::RenderInline::addChildIgnoringContinuation(WebCore::RenderObject * newChild=0x06a1d174, WebCore::RenderObject * beforeChild=0x00000000)  Line 218	C++
 	chrome.dll!WebCore::RenderInline::addChild(WebCore::RenderObject * newChild=0x06a1d174, WebCore::RenderObject * beforeChild=0x00000000)  Line 152 + 0x17 bytes	C++
 	chrome.dll!WebCore::Node::createRendererIfNeeded()  Line 1241 + 0x21 bytes	C++
 	chrome.dll!WebCore::Element::attach()  Line 700	C++
 	chrome.dll!WebCore::HTMLTableElement::attach()  Line 644	C++
 	chrome.dll!WebCore::ContainerNode::appendChild(WTF::PassRefPtr<WebCore::Node> newChild={...}, int & ec=0, bool shouldLazyAttach=false)  Line 497 + 0x1d bytes	C++
 	chrome.dll!WebCore::NodeInternal::appendChildCallback(const v8::Arguments & args={...})  Line 270 + 0x1f bytes	C++
 	chrome.dll!v8::internal::Builtin_HandleApiCall(int __argc__=2, v8::internal::Object * * __argv__=0x0562ef70)  Line 380 + 0xe bytes	C++
 	05de016c()	
 	chrome.dll!v8::internal::Invoke(bool construct=false, v8::internal::Handle<v8::internal::JSFunction> func={...}, v8::internal::Handle<v8::internal::Object> receiver={...}, int argc=0, v8::internal::Object * * * args=0x00000000, bool * has_pending_exception=0x0562f117)  Line 90 + 0x34 bytes	C++
 	chrome.dll!v8::internal::Execution::Call(v8::internal::Handle<v8::internal::JSFunction> func={...}, v8::internal::Handle<v8::internal::Object> receiver={...}, int argc=0, v8::internal::Object * * * args=0x00000000, bool * pending_exception=0x0562f117)  Line 116 + 0x1f bytes	C++
 	chrome.dll!v8::Script::Run()  Line 1047 + 0x19 bytes	C++
 	chrome.dll!WebCore::V8Proxy::RunScript(v8::Handle<v8::Script> script={...}, bool inline_code=false)  Line 1428 + 0x13 bytes	C++
 	chrome.dll!WebCore::V8Proxy::Evaluate(const WebCore::String & fileName={...}, int baseLine=0, const WebCore::String & str={...}, WebCore::Node * n=0x00000000)  Line 1382 + 0x19 bytes	C++
 	chrome.dll!WebCore::ScriptController::evaluate(const WebCore::ScriptSourceCode & sourceCode={...})  Line 232	C++
 	chrome.dll!WebCore::ScriptElementData::evaluateScript(const WebCore::ScriptSourceCode & sourceCode={...})  Line 180 + 0x17 bytes	C++
 	chrome.dll!WebCore::ScriptElementData::notifyFinished(WebCore::CachedResource * o=0x06ad4028)  Line 205 + 0x15 bytes	C++
 	chrome.dll!WebCore::CachedScript::checkNotify()  Line 108 + 0x13 bytes	C++
 	chrome.dll!WebCore::CachedScript::data(WTF::PassRefPtr<WebCore::SharedBuffer> data={...}, bool allDataReceived=true)  Line 99	C++
 	chrome.dll!WebCore::Loader::Host::didFinishLoading(WebCore::SubresourceLoader * loader=0x06ad5638)  Line 304	C++
 	chrome.dll!WebCore::SubresourceLoader::didFinishLoading()  Line 183 + 0x21 bytes	C++
 	chrome.dll!WebCore::ResourceLoader::didFinishLoading(WebCore::ResourceHandle * __formal=0x06ad5fc0)  Line 416 + 0xf bytes	C++
 	chrome.dll!WebCore::ResourceHandleInternal::OnCompletedRequest(const URLRequestStatus & status={...})  Line 632 + 0x1e bytes	C++
 	chrome.dll!ResourceDispatcher::OnRequestComplete(int request_id=13, const URLRequestStatus & status={...})  Line 417 + 0x13 bytes	C++
 	chrome.dll!DispatchToMethod<ResourceDispatcher,void (__thiscall ResourceDispatcher::*)(int,URLRequestStatus const &),int,URLRequestStatus>(ResourceDispatcher * obj=0x050ca508, void (int, const URLRequestStatus &)* method=0x010ed840, const Tuple2<int,URLRequestStatus> & arg={...})  Line 400 + 0x15 bytes	C++
 	chrome.dll!IPC::MessageWithTuple<Tuple2<int,URLRequestStatus> >::Dispatch<ResourceDispatcher,void (__thiscall ResourceDispatcher::*)(int,URLRequestStatus const &)>(const IPC::Message * msg=0x06a44d90, ResourceDispatcher * obj=0x050ca508, void (int, const URLRequestStatus &)* func=0x010ed840)  Line 1157 + 0x11 bytes	C++
 	chrome.dll!ResourceDispatcher::DispatchMessageW(const IPC::Message & message={...})  Line 464 + 0x12 bytes	C++
 	chrome.dll!ResourceDispatcher::OnMessageReceived(const IPC::Message & message={...})  Line 278	C++
 	chrome.dll!RenderView::OnMessageReceived(const IPC::Message & message={...})  Line 340 + 0x19 bytes	C++
 	chrome.dll!MessageRouter::RouteMessage(const IPC::Message & msg={...})  Line 39 + 0x13 bytes	C++
 	chrome.dll!MessageRouter::OnMessageReceived(const IPC::Message & msg={...})  Line 30 + 0x13 bytes	C++
 	chrome.dll!ChildThread::OnMessageReceived(const IPC::Message & msg={...})  Line 64 + 0x17 bytes	C++
 	chrome.dll!IPC::ChannelProxy::Context::OnDispatchMessage(const IPC::Message & message={...})  Line 174 + 0x1b bytes	C++
 	chrome.dll!DispatchToMethod<IPC::ChannelProxy::Context,void (__thiscall IPC::ChannelProxy::Context::*)(IPC::Message const &),IPC::Message>(IPC::ChannelProxy::Context * obj=0x04fa3928, void (const IPC::Message &)* method=0x010d6cd0, const Tuple1<IPC::Message> & arg={...})  Line 393 + 0xf bytes	C++
 	chrome.dll!RunnableMethod<IPC::ChannelProxy::Context,void (__thiscall IPC::ChannelProxy::Context::*)(IPC::Message const &),Tuple1<IPC::Message> >::Run()  Line 308 + 0x1e bytes	C++
 	chrome.dll!MessageLoop::RunTask(Task * task=0x06a44d68)  Line 308 + 0xf bytes	C++
 	chrome.dll!MessageLoop::DeferOrRunPendingTask(const MessageLoop::PendingTask & pending_task={...})  Line 319	C++
 	chrome.dll!MessageLoop::DoWork()  Line 408 + 0xc bytes	C++
 	chrome.dll!base::MessagePumpForUI::DoRunLoop()  Line 208 + 0x1d bytes	C++
 	chrome.dll!base::MessagePumpWin::RunWithDispatcher(base::MessagePump::Delegate * delegate=0x0562feb4, base::MessagePumpWin::Dispatcher * dispatcher=0x00000000)  Line 52 + 0xf bytes	C++
 	chrome.dll!base::MessagePumpWin::Run(base::MessagePump::Delegate * delegate=0x0562feb4)  Line 78 + 0x1c bytes	C++
 	chrome.dll!MessageLoop::RunInternal()  Line 197 + 0x2a bytes	C++
 	chrome.dll!MessageLoop::RunHandler()  Line 181	C++
 	chrome.dll!MessageLoop::Run()  Line 155	C++
 	chrome.dll!base::Thread::ThreadMain()  Line 159	C++
 	chrome.dll!`anonymous namespace'::ThreadFunc(void * closure=0x04fa32e4)  Line 26 + 0xf bytes	C++
 	kernel32.dll!7c80b713() 	
 	[Frames below may be incorrect and/or missing, no symbols loaded for kernel32.dll]	
Comment 3 Scott Violet 2009-03-04 09:44:03 PST
Created attachment 28266 [details]
Test case for first assertion (crashes safari!)

This is the first assertion I saw when running the crashing page. I don't know that this'll fix the crasher, or is representative of the crash, but at least it'll fix the assertion and hopefully avoid us from getting into a bad state.

The test adds a table to a form via script. When the renderer for the newly added table is created the parent renderer is a RenderInline. The parent renderer has a continuation, the child is not inlined or positioned so we end up in RenderInline::splitFlow. The parent of the form is a render table section, but the containing block is a table renderer. When splitFlow tries to move all the children from the table to the anonymous block we we hit this assert in RenderObjectChildList::appendChildNode:

   ASSERT(!owner->isBlockFlow() || (!newChild->isTableSection() && !newChild->isTableRow() && !newChild->isTableCell()));

because the newChild is a block and is a table section.

I'm not sure what the right way to fix this is though. Should the anonymous block get added to the table section (containingBlock() skips table sections)? Other ideas?
Comment 4 Scott Violet 2009-03-04 10:47:24 PST
I couldn't reproduce this in the first version of chrome, which has WebKit: 525.19. So, if it is a regression it certainly isn't recent.

If WebKit builds are archived I could go back further. Are they?
Comment 5 Scott Violet 2009-03-04 10:51:11 PST
(In reply to comment #4)
> I couldn't reproduce this in the first version of chrome, which has WebKit:
> 525.19. So, if it is a regression it certainly isn't recent.
> 
> If WebKit builds are archived I could go back further. Are they?

I'm totally wrong here. I COULD reproduce this in the first version of Chrome. So, this behavior has always been there in Chrome. I'll try the archived WebKit builds.
Comment 6 Scott Violet 2009-03-04 11:04:09 PST
I couldn't make progress with the archived webkit builds as they don't seem to have ASSERT turned on. I verified running the attached as a layout test crashes, and it does.
Comment 7 Eric Seidel (no email) 2009-03-13 17:09:02 PDT
This test case crashes Safari 4 as well.  P1  Attaching stack trace.
Comment 8 Eric Seidel (no email) 2009-03-13 17:09:54 PDT
Created attachment 28614 [details]
stack trace of test case crashing Safari 4 public beta
Comment 9 Beth Dakin 2009-04-16 13:22:10 PDT
I have a patch that fixes 20765 and this bug as well. They are essentially the same bug.

*** This bug has been marked as a duplicate of 20765 ***