Summary: | [GTK] 'pure virtual method called' in WebCore::JSNodeOwner::isReachableFromOpaqueRoots | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Product: | WebKit | Reporter: | Jochen Sprickerhof <webkit> | ||||||||||
Component: | WebKitGTK | Assignee: | Nobody <webkit-unassigned> | ||||||||||
Status: | NEW --- | ||||||||||||
Severity: | Normal | CC: | bugs-noreply, fpizlo, ggaren, gustavo, gyuyoung.kim, kling, koivisto, oliver, pochu27, psychon, zan | ||||||||||
Priority: | P2 | ||||||||||||
Version: | 528+ (Nightly build) | ||||||||||||
Hardware: | Unspecified | ||||||||||||
OS: | Unspecified | ||||||||||||
Attachments: |
|
Description
Jochen Sprickerhof
2013-08-17 09:47:42 PDT
Pretty similar to bug #112266. Looking at the Debian-provided libraries, there are differences in what symbols are provided. I'll set up a libwebkitgtk-1.0-0 build for starters. I can't reproduce this using surf inside a Debian Sid chroot, performing the given GitHub test case, and I also can't reproduce with the test case from bug #112266 (which seemed to reproduce more consistently than the test case provided in this bug). The Debian packaging only the API-related symbols, hence the difference in the symbols listing. I don't think this is related to these crashes, though. Although, plenty of symbols get stripped through dh_strip when creating the Debian packages. For instance, this shows the JSNodeOwner::isReachableFromOpaqueRoots symbol is still present in the built libwebkitgtk-1.0.so: (sid)zan@strade:~/Dev/webkit/releases/debian/webkitgtk-2.0.4/build-2.0$ objdump -tT .libs/libwebkitgtk-1.0.so | grep JSNodeOwner | grep isReachableFromOpaqueRoots 00000000004ba1f0 l F .text 0000000000000259 _ZN7WebCore11JSNodeOwner26isReachableFromOpaqueRootsEN3JSC6HandleINS1_7UnknownEEEPvRNS1_11SlotVisitorE This symbol, along with many others, is stripped from the packaged shared library. Gustavo, do you have any insight on this? (In reply to comment #2) > I can't reproduce this using surf inside a Debian Sid chroot, performing the given GitHub test case, and I also can't reproduce with the test case from bug #112266 (which seemed to reproduce more consistently than the test case provided in this bug). Given the information in [1], I guess this is a timing problem. Make sure you install a minimal system/chroot to try it. So I can only trigger this without recommend packages installed. Try this: $ mkdir /srv/chroot/sid/ $ debootstrap sid /srv/chroot/sid/ $ schroot $ apt-get --no-install-recommends install surf $ DISPLAY=:0.0 /usr/bin/surf https://github.com/ros/rosdistro/issues/1676 To not trigger this, it's enough to install the recommend gstreamer1.0-plugins-base into the chroot. Not that this is only a workaround, it's not solving the bug. [1] https://tombarta.wordpress.com/2008/07/10/gcc-pure-virtual-method-called/ ... and there's the crash. Thanks for the pointers. Ignore the whole 'but look at the symbols!' charade. This also reproduces in trunk. Adjusting the title a bit and CC-ing a couple of JSC developers who could possibly take a look at this. Created attachment 209080 [details]
Backtraces for all the threads
Here's the gdb output, containing backtraces for all the threads at the time of the crash.
This looks to be a use after free. Are you able to run under valgrind/asan? Based on the assertion, and path to assertion land we've lost a ref() of Node (or subclass) CC'ing antti and kling as they've been playing with object construction recently I've recompiled with disabled JIT, just so Valgrind could process the execution without crashing in JIT-specific code. The resulting crash is a bit different, though the culprit still seems a FUBAR'd Node object in WebCore::isReachableFromDOM. Here's the incomplete backtrace for the crashing thread. I'll upload a complete backtrace dump and the Valgrind log file shortly. #0 0x00007ffff4856db0 in WebCore::Node::dispatchEvent (this=0xa0e190, event=...) at ../Source/WebCore/dom/Node.cpp:2112 #1 0x00007ffff45863cd in WebCore::isReachableFromDOM (jsNode=0x7fff8918fa70, node=0xa0e190, visitor=...) at ../Source/WebCore/bindings/js/JSNodeCustom.cpp:114 #2 0x00007ffff458649c in WebCore::JSNodeOwner::isReachableFromOpaqueRoots (this=0x9289d0, handle=..., visitor=...) at ../Source/WebCore/bindings/js/JSNodeCustom.cpp:131 #3 0x00007ffff36acf66 in JSC::WeakBlock::visit (this=0x7ffff7eea000, heapRootVisitor=...) at ../Source/JavaScriptCore/heap/WeakBlock.cpp:108 #4 0x00007ffff36a795b in JSC::WeakSet::visit (this=0x7fff89180448, visitor=...) at ../Source/JavaScriptCore/heap/WeakSet.h:104 #5 0x00007ffff36a7afe in JSC::MarkedBlock::visitWeakSet (this=0x7fff89180000, heapRootVisitor=...) at ../Source/JavaScriptCore/heap/MarkedBlock.h:260 #6 0x00007ffff36a7f7c in JSC::VisitWeakSet::operator() (this=0x7fffffffd040, block=0x7fff89180000) at ../Source/JavaScriptCore/heap/MarkedSpace.cpp:71 #7 0x00007ffff36a8ddb in JSC::MarkedAllocator::forEachBlock<JSC::VisitWeakSet> (this=0x7758a0, functor=...) at ../Source/JavaScriptCore/heap/MarkedAllocator.h:120 #8 0x00007ffff36a8567 in JSC::MarkedSpace::forEachBlock<JSC::VisitWeakSet> (this=0x7757b0, functor=...) at ../Source/JavaScriptCore/heap/MarkedSpace.h:222 #9 0x00007ffff36a735e in JSC::MarkedSpace::visitWeakSets (this=0x7757b0, heapRootVisitor=...) at ../Source/JavaScriptCore/heap/MarkedSpace.cpp:144 #10 0x00007ffff369531b in JSC::Heap::markRoots (this=0x775528) at ../Source/JavaScriptCore/heap/Heap.cpp:580 #11 0x00007ffff3695a9b in JSC::Heap::collect (this=0x775528, sweepToggle=JSC::Heap::DoSweep) at ../Source/JavaScriptCore/heap/Heap.cpp:760 #12 0x00007ffff36957b3 in JSC::Heap::collectAllGarbage (this=0x775528) at ../Source/JavaScriptCore/heap/Heap.cpp:713 #13 0x00007ffff4526ff2 in WebCore::collect () at ../Source/WebCore/bindings/js/GCController.cpp:42 #14 0x00007ffff45270de in WebCore::GCController::gcTimerFired (this=0xa6ced0) at ../Source/WebCore/bindings/js/GCController.cpp:77 #15 0x00007ffff4527369 in WebCore::Timer<WebCore::GCController>::fired (this=0xa6ced0) at ../Source/WebCore/platform/Timer.h:114 #16 0x00007ffff44b6c9b in WebCore::ThreadTimers::sharedTimerFiredInternal (this=0x6cc9b0) at ../Source/WebCore/platform/ThreadTimers.cpp:129 #17 0x00007ffff44b6b8b in WebCore::ThreadTimers::sharedTimerFired () at ../Source/WebCore/platform/ThreadTimers.cpp:105 #18 0x00007ffff44d36f5 in WebCore::timeout_cb () at ../Source/WebCore/platform/gtk/SharedTimerGtk.cpp:49 #19 0x00007fffeef9ea03 in ?? () from /lib/x86_64-linux-gnu/libglib-2.0.so.0 #20 0x00007fffeef9dea6 in g_main_context_dispatch () from /lib/x86_64-linux-gnu/libglib-2.0.so.0 #21 0x00007fffeef9e1f8 in ?? () from /lib/x86_64-linux-gnu/libglib-2.0.so.0 #22 0x00007fffeef9e5fa in g_main_loop_run () from /lib/x86_64-linux-gnu/libglib-2.0.so.0 #23 0x00007ffff2853257 in gtk_main () from /usr/lib/x86_64-linux-gnu/libgtk-x11-2.0.so.0 #24 0x0000000000405b02 in main (argc=1, argv=0x7fffffffde48) at ../Tools/GtkLauncher/main.c:557 Created attachment 209186 [details]
Backtraces for all the threads - crash #2 (Node::dispatchEvent)
Created attachment 209188 [details]
Valgrind log file
Log output from displaying the crash-causing site under valgrind with --track-origins=yes.
Seems that the uninitialized value that's causing the crashes is coming from the creation of the <audio> tag QualifiedName.
Confirmed, with the JIT-less build crashing in Node::dispatchEvent, the event argument in that method is actually pointing to the same address as HTMLNames::audioTag. Odd. Program received signal SIGSEGV, Segmentation fault. 0x00007ffff4856db0 in WebCore::Node::dispatchEvent (this=0x9e1630, event=...) at ../Source/WebCore/dom/Node.cpp:2112 warning: Source file is more recent than executable. 2112 if (event->isMouseEvent()) (gdb) l 2107 EventDispatcher::dispatchScopedEvent(this, eventDispatchMediator); 2108 } 2109 2110 bool Node::dispatchEvent(PassRefPtr<Event> event) 2111 { 2112 if (event->isMouseEvent()) 2113 return EventDispatcher::dispatchEvent(this, MouseEventDispatchMediator::create(adoptRef(toMouseEvent(event.leakRef())), MouseEventDispatchMediator::SyntheticMouseEvent)); 2114 #if ENABLE(TOUCH_EVENTS) 2115 if (event->isTouchEvent()) 2116 return dispatchTouchEvent(adoptRef(toTouchEvent(event.leakRef()))); (gdb) info args this = 0x9e1630 event = {m_ptr = 0x6bdcc0} (gdb) p HTMLNames::audioTag $3 = {m_impl = 0x6bdcc0} (In reply to comment #4) > To not trigger this, it's enough to install the recommend gstreamer1.0-plugins-base into the chroot. Not that this is only a workaround, it's not solving the bug. > This is actually essential. If the plugins are not installed, MediaPlayer::isAvailable() is returning false. In the generated HTMLElementFactory.cpp, when HTMLElementFactory::createHTMLElement() is called with the audioTag, WebCore::audioConstructor is called, but it returns 0 since the MediaPlayer::isAvailable() is returning false due to the missing plugins. This causes the creation of the HTMLUnknownElement with the 'audio' tag name. Later, in WebCore::isReachableFromDOM, this HTMLUnknownElement passes the isHTMLAudioElement test because it has the correct tag name. It's then cast to HTMLAudioElement through toHTMLAudioElement and the crash ensues. Looking through HTMLElementFactory, constructors for the following HTML elements can return 0, falling back to creating HTMLUnknownElements with the same tag name: audio, source, track, video - if either MediaPlayer::isAvailiable() or Settings::mediaEnabled is returning false, content - if RuntimeEnabledFeatures::shadowDOMEnabled() is returning false, dialog - if ContextFeatures::dialogElementEnabled() is returning false. Created attachment 209335 [details]
Reproducible test case
A reproducible test case that first disables media support through window.internals.settings.setMediaEnabled(false), creates the element through window.createElement('audio') and then garbage-collects it.
I can reproduce crashes under both DumpRenderTree and WebKitTestRunner.
(In reply to comment #13) > (In reply to comment #4) > > To not trigger this, it's enough to install the recommend gstreamer1.0-plugins-base into the chroot. Not that this is only a workaround, it's not solving the bug. > > > > This is actually essential. If the plugins are not installed, MediaPlayer::isAvailable() is returning false. > > In the generated HTMLElementFactory.cpp, when HTMLElementFactory::createHTMLElement() is called with the audioTag, WebCore::audioConstructor is called, but it returns 0 since the MediaPlayer::isAvailable() is returning false due to the missing plugins. This causes the creation of the HTMLUnknownElement with the 'audio' tag name. > > Later, in WebCore::isReachableFromDOM, this HTMLUnknownElement passes the isHTMLAudioElement test because it has the correct tag name. It's then cast to HTMLAudioElement through toHTMLAudioElement and the crash ensues. > > Looking through HTMLElementFactory, constructors for the following HTML elements can return 0, falling back to creating HTMLUnknownElements with the same tag name: > audio, source, track, video - if either MediaPlayer::isAvailiable() or Settings::mediaEnabled is returning false, > content - if RuntimeEnabledFeatures::shadowDOMEnabled() is returning false, > dialog - if ContextFeatures::dialogElementEnabled() is returning false. I file a bug for this issue at Bug 120297. https://bugs.webkit.org/show_bug.cgi?id=120297 |