Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fix (flaky) heap-use-after-free in QQuickItemGrabResult::render
The full backtrace is below. My understanding is that this line in TestHelper::addNewGuides VERIFY(imageGrabber.requestImage(canvas)); results in QQuickItem::grabToImage connecting to this signal: connect(window(), &QQuickWindow::afterRendering, result, &QQuickItemGrabResult::render, Qt::DirectConnection); We then wait until the image is not null: TRY_VERIFY(imageGrabber.isReady()); This is important, as we should really be listening to the ready signal. Meanwhile, on the render thread, the image is set at some point: d->image = d->texture->toImage(); I'm guessing that, back in the main thread, we then detect that the image is not null, store it, and destroy the QQuickItemGrabResult: const QImage originalCanvasGrab = imageGrabber.takeImage(); QQuickItemGrabResult::render() is still running though, so it tries to delete the texture and set it to null: delete d->texture; d->texture = nullptr; The latter causes the HUAF. Fix it by listening to the ready signal, which is emitted via a posted event, so we can be sure that it's safe to destroy the QQuickItemGrabResult. ================================================================= ==26184==ERROR: AddressSanitizer: heap-use-after-free on address 0x6110005356d0 at pc 0x00011a46f761 bp 0x700006e81610 sp 0x700006e81608 WRITE of size 8 at 0x6110005356d0 thread T5 #0 0x11a46f760 in QQuickItemGrabResult::render() qquickitemgrabresult.cpp:294 #1 0x11a47e648 in QtPrivate::FunctorCall<QtPrivate::IndexesList<>, QtPrivate::List<>, void, void (QQuickItemGrabResult::*)()>::call(void (QQuickItemGrabResult::*)(), QQuickItemGrabResult*, void**) qobjectdefs_impl.h:171 #2 0x11a47e34d in void QtPrivate::FunctionPointer<void (QQuickItemGrabResult::*)()>::call<QtPrivate::List<>, void>(void (QQuickItemGrabResult::*)(), QQuickItemGrabResult*, void**) qobjectdefs_impl.h:208 #3 0x11a47def2 in QtPrivate::QSlotObject<void (QQuickItemGrabResult::*)(), QtPrivate::List<>, void>::impl(int, QtPrivate::QSlotObjectBase*, QObject*, void**, bool*) qobjectdefs_impl.h:419 #4 0x11d620cd5 in QtPrivate::QSlotObjectBase::call(QObject*, void**) qobjectdefs_impl.h:399 #5 0x11d7a84d0 in void doActivate<false>(QObject*, int, void**) qobject.cpp:3932 #6 0x11d7a53a8 in QMetaObject::activate(QObject*, QMetaObject const*, int, void**) qobject.cpp:3992 #7 0x11a789314 in QQuickWindow::afterRendering() moc_qquickwindow.cpp:590 #8 0x11a788d68 in QQuickWindowPrivate::renderSceneGraph(QSize const&, QSize const&) qquickwindow.cpp:668 #9 0x11b39b84e in QSGRenderThread::syncAndRender() qsgthreadedrenderloop.cpp:769 #10 0x11b39f607 in QSGRenderThread::run() qsgthreadedrenderloop.cpp:974 #11 0x11df239da in QThreadPrivate::start(void*)::$_0::operator()() const qthread_unix.cpp:358 #12 0x11df1c80c in void (anonymous namespace)::terminate_on_exception<QThreadPrivate::start(void*)::$_0>(QThreadPrivate::start(void*)::$_0&&) qthread_unix.cpp:294 #13 0x11df1c446 in QThreadPrivate::start(void*) qthread_unix.cpp:317 #14 0x7ff80ab714e0 in _pthread_start+0x7c (libsystem_pthread.dylib:x86_64+0x64e0) #15 0x7ff80ab6cf6a in thread_start+0xe (libsystem_pthread.dylib:x86_64+0x1f6a) 0x6110005356d0 is located 208 bytes inside of 240-byte region [0x611000535600,0x6110005356f0) freed by thread T0 here: #0 0x11091c66d in wrap__ZdlPv+0x7d (libclang_rt.asan_osx_dynamic.dylib:x86_64h+0x5766d) #1 0x11a473221 in QQuickItemGrabResultPrivate::~QQuickItemGrabResultPrivate() qquickitemgrabresult.cpp:73 #2 0x11d7c7778 in QScopedPointerDeleter<QObjectData>::cleanup(QObjectData*) qscopedpointer.h:60 #3 0x11d7c76dc in QScopedPointer<QObjectData, QScopedPointerDeleter<QObjectData> >::~QScopedPointer() qscopedpointer.h:116 #4 0x11d788144 in QScopedPointer<QObjectData, QScopedPointerDeleter<QObjectData> >::~QScopedPointer() qscopedpointer.h:114 #5 0x11d78941a in QObject::~QObject() qobject.cpp:1116 #6 0x11a4753d4 in QQuickItemGrabResult::~QQuickItemGrabResult() qquickitemgrabresult.h:57 #7 0x11a472ff4 in QQuickItemGrabResult::~QQuickItemGrabResult() qquickitemgrabresult.h:57 #8 0x11a473018 in QQuickItemGrabResult::~QQuickItemGrabResult() qquickitemgrabresult.h:57 #9 0x11a47ecb8 in QtSharedPointer::CustomDeleter<QQuickItemGrabResult, QtSharedPointer::NormalDeleter>::execute() qsharedpointer_impl.h:190 #10 0x11a47eb70 in QtSharedPointer::ExternalRefCountWithCustomDeleter<QQuickItemGrabResult, QtSharedPointer::NormalDeleter>::deleter(QtSharedPointer::ExternalRefCountData*) qsharedpointer_impl.h:208 #11 0x10e3d46fa in QtSharedPointer::ExternalRefCountData::destroy() qsharedpointer_impl.h:146 #12 0x10e3d4649 in QSharedPointer<QQuickItemGrabResult>::deref(QtSharedPointer::ExternalRefCountData*) qsharedpointer_impl.h:477 #13 0x10e3d4608 in QSharedPointer<QQuickItemGrabResult>::deref() qsharedpointer_impl.h:472 #14 0x10e3d45b4 in QSharedPointer<QQuickItemGrabResult>::~QSharedPointer() qsharedpointer_impl.h:312 #15 0x10e3d4074 in QSharedPointer<QQuickItemGrabResult>::~QSharedPointer() qsharedpointer_impl.h:312 #16 0x10e3d4b4f in QSharedPointer<QQuickItemGrabResult>::clear() qsharedpointer_impl.h:416 #17 0x10e3d4a24 in QSharedPointer<QQuickItemGrabResult>::reset() qsharedpointer_impl.h:383 #18 0x10e23b7ee in ImageGrabber::takeImage() testhelper.h:78 #19 0x10e5a1424 in TestHelper::addNewGuides(int, int, TestHelper::AddNewGuidesFlag) testhelper.cpp:1601 #20 0x10e2def3c in tst_App::addAndDeleteMultipleGuides() tst_app.cpp:3484 #21 0x10e3abed9 in tst_App::qt_static_metacall(QObject*, QMetaObject::Call, int, void**) tst_app.moc:744 #22 0x11d61f5ea in QMetaMethod::invoke(QObject*, Qt::ConnectionType, QGenericReturnArgument, QGenericArgument, QGenericArgument, QGenericArgument, QGenericArgument, QGenericArgument, QGenericArgument, QGenericArgument, QGenericArgument, QGenericArgument, QGenericArgument) const qmetaobject.cpp:2390 #23 0x10f298aed in QMetaMethod::invoke(QObject*, Qt::ConnectionType, QGenericArgument, QGenericArgument, QGenericArgument, QGenericArgument, QGenericArgument, QGenericArgument, QGenericArgument, QGenericArgument, QGenericArgument, QGenericArgument) const qmetaobject.h:126 #24 0x10f296661 in QTest::TestMethods::invokeTestOnData(int) const qtestcase.cpp:966 #25 0x10f299b96 in QTest::TestMethods::invokeTest(int, char const*, QTest::WatchDog*) const qtestcase.cpp:1210 #26 0x10f2a002a in QTest::TestMethods::invokeTests(QObject*) const qtestcase.cpp:1552 #27 0x10f2a23cf in QTest::qRun() qtestcase.cpp:2018 #28 0x10f2a1047 in QTest::qExec(QObject*, int, char**) qtestcase.cpp:1920 #29 0x10e3ab836 in main tst_app.cpp:7095 previously allocated by thread T0 here: #0 0x11091c24d in wrap__Znwm+0x7d (libclang_rt.asan_osx_dynamic.dylib:x86_64h+0x5724d) #1 0x11a46cd45 in QQuickItemGrabResult::QQuickItemGrabResult(QObject*) qquickitemgrabresult.cpp:175 #2 0x11a46cdec in QQuickItemGrabResult::QQuickItemGrabResult(QObject*) qquickitemgrabresult.cpp:176 #3 0x11a470b1a in QQuickItemGrabResultPrivate::create(QQuickItem*, QSize const&) qquickitemgrabresult.cpp:326 #4 0x11a470efd in QQuickItem::grabToImage(QSize const&) qquickitemgrabresult.cpp:360 #5 0x10e23b2bf in ImageGrabber::requestImage(QQuickItem*) testhelper.h:64 #6 0x10e59fb7b in TestHelper::addNewGuides(int, int, TestHelper::AddNewGuidesFlag) testhelper.cpp:1599 #7 0x10e2def3c in tst_App::addAndDeleteMultipleGuides() tst_app.cpp:3484 #8 0x10e3abed9 in tst_App::qt_static_metacall(QObject*, QMetaObject::Call, int, void**) tst_app.moc:744 #9 0x11d61f5ea in QMetaMethod::invoke(QObject*, Qt::ConnectionType, QGenericReturnArgument, QGenericArgument, QGenericArgument, QGenericArgument, QGenericArgument, QGenericArgument, QGenericArgument, QGenericArgument, QGenericArgument, QGenericArgument, QGenericArgument) const qmetaobject.cpp:2390 #10 0x10f298aed in QMetaMethod::invoke(QObject*, Qt::ConnectionType, QGenericArgument, QGenericArgument, QGenericArgument, QGenericArgument, QGenericArgument, QGenericArgument, QGenericArgument, QGenericArgument, QGenericArgument, QGenericArgument) const qmetaobject.h:126 #11 0x10f296661 in QTest::TestMethods::invokeTestOnData(int) const qtestcase.cpp:966 #12 0x10f299b96 in QTest::TestMethods::invokeTest(int, char const*, QTest::WatchDog*) const qtestcase.cpp:1210 #13 0x10f2a002a in QTest::TestMethods::invokeTests(QObject*) const qtestcase.cpp:1552 #14 0x10f2a23cf in QTest::qRun() qtestcase.cpp:2018 #15 0x10f2a1047 in QTest::qExec(QObject*, int, char**) qtestcase.cpp:1920 #16 0x10e3ab836 in main tst_app.cpp:7095 #17 0x11139751d in start+0x1cd (dyld:x86_64+0x551d) Thread T5 created by T0 here: #0 0x11090771c in wrap_pthread_create+0x5c (libclang_rt.asan_osx_dynamic.dylib:x86_64h+0x4271c) #1 0x11df1e41f in QThread::start(QThread::Priority) qthread_unix.cpp:744 #2 0x11b3a7030 in QSGThreadedRenderLoop::handleExposure(QQuickWindow*) qsgthreadedrenderloop.cpp:1319 #3 0x11b3a5215 in QSGThreadedRenderLoop::exposureChanged(QQuickWindow*) qsgthreadedrenderloop.cpp:1244 #4 0x11a781ffc in QQuickWindow::exposeEvent(QExposeEvent*) qquickwindow.cpp:214 #5 0x12835b785 in QWindow::event(QEvent*) qwindow.cpp:2501 #6 0x11a792d84 in QQuickWindow::event(QEvent*) qquickwindow.cpp:1552 #7 0x11426e051 in QApplicationPrivate::notify_helper(QObject*, QEvent*) qapplication.cpp:3340 #8 0x11427b41e in QApplication::notify(QObject*, QEvent*) qapplication.cpp:3291 #9 0x11d5b2ac7 in QCoreApplication::notifyInternal2(QObject*, QEvent*) qcoreapplication.cpp:1067 #10 0x11d5b5843 in QCoreApplication::sendSpontaneousEvent(QObject*, QEvent*) qcoreapplication.cpp:1497 #11 0x128170b9f in QGuiApplicationPrivate::processExposeEvent(QWindowSystemInterfacePrivate::ExposeEvent*) qguiapplication.cpp:3174 #12 0x128162f0b in QGuiApplicationPrivate::processWindowSystemEvent(QWindowSystemInterfacePrivate::WindowSystemEvent*) qguiapplication.cpp:2078 #13 0x1283af9c1 in bool QWindowSystemHelper<QWindowSystemInterface::SynchronousDelivery>::handleEvent<QWindowSystemInterfacePrivate::ExposeEvent, QWindow*, QRegion>(QWindow*, QRegion) qwindowsysteminterface.cpp:134 #14 0x128394c88 in bool handleWindowSystemEvent<QWindowSystemInterfacePrivate::ExposeEvent, QWindowSystemInterface::SynchronousDelivery, QWindow*, QRegion>(QWindow*, QRegion) qwindowsysteminterface.cpp:166 #15 0x128394b1c in bool QWindowSystemInterface::handleExposeEvent<QWindowSystemInterface::SynchronousDelivery>(QWindow*, QRegion const&) qwindowsysteminterface.cpp:359 #16 0x1128c0c8e in QCocoaWindow::handleExposeEvent(QRegion const&) qcocoawindow.mm:1444 #17 0x1128f2ddd in -[QNSView(Drawing) displayLayer:] qnsview_drawing.mm:243 #18 0x7ff811ce4950 in CA::Layer::display_if_needed(CA::Transaction*)+0x368 (QuartzCore:x86_64+0x20950) #19 0x7ff811e3b335 in CA::Context::commit_transaction(CA::Transaction*, double, double*)+0x27f (QuartzCore:x86_64+0x177335) #20 0x7ff811cc6230 in CA::Transaction::commit()+0x308 (QuartzCore:x86_64+0x2230) #21 0x7ff80d7c87f0 in __62+[CATransaction(NSCATransaction) NS_setFlushesWithDisplayLink]_block_invoke+0x11c (AppKit:x86_64+0x1aa7f0) #22 0x7ff80df0f687 in ___NSRunLoopObserverCreateWithHandler_block_invoke+0x28 (AppKit:x86_64+0x8f1687) #23 0x7ff80ac36e8f in __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__+0x16 (CoreFoundation:x86_64h+0x7ee8f) #24 0x7ff80ac36d21 in __CFRunLoopDoObservers+0x21e (CoreFoundation:x86_64h+0x7ed21) #25 0x7ff80ac361b3 in __CFRunLoopRun+0x347 (CoreFoundation:x86_64h+0x7e1b3) #26 0x7ff80ac357ab in CFRunLoopRunSpecific+0x231 (CoreFoundation:x86_64h+0x7d7ab) #27 0x7ff8138bcce5 in RunCurrentEventLoopInMode+0x123 (HIToolbox:x86_64+0x2fce5) #28 0x7ff8138bc912 in ReceiveNextEventCommon+0x11a (HIToolbox:x86_64+0x2f912) #29 0x7ff8138bc7e4 in _BlockUntilNextEventMatchingListInModeWithFilter+0x45 (HIToolbox:x86_64+0x2f7e4) #30 0x7ff80d65c5cc in _DPSNextEvent+0x39e (AppKit:x86_64+0x3e5cc) #31 0x7ff80d65ac89 in -[NSApplication(NSEvent) _nextEventMatchingEventMask:untilDate:inMode:dequeue:]+0x571 (AppKit:x86_64+0x3cc89) #32 0x7ff80d64d338 in -[NSApplication run]+0x249 (AppKit:x86_64+0x2f338) #33 0x11284b68d in QCocoaEventDispatcherPrivate::ensureNSAppInitialized() qcocoaeventdispatcher.mm:608 #34 0x11284a486 in QCocoaEventDispatcher::processEvents(QFlags<QEventLoop::ProcessEventsFlag>) qcocoaeventdispatcher.mm:438 #35 0x11d5b3eed in QCoreApplication::processEvents(QFlags<QEventLoop::ProcessEventsFlag>) qcoreapplication.cpp:1296 #36 0x12832fdf1 in bool QTest::qWaitFor<QTest::qWaitForWindowExposed(QWindow*, int)::$_1>(QTest::qWaitForWindowExposed(QWindow*, int)::$_1, int) qtestsupport_core.h:75 #37 0x12832f522 in QTest::qWaitForWindowExposed(QWindow*, int) qtestsupport_gui.cpp:93 #38 0x10e4c3a7a in TestHelper::initTestCase() testhelper.cpp:64 #39 0x10e452a50 in TestHelper::qt_static_metacall(QObject*, QMetaObject::Call, int, void**) moc_testhelper.cpp:74 #40 0x11d61f5ea in QMetaMethod::invoke(QObject*, Qt::ConnectionType, QGenericReturnArgument, QGenericArgument, QGenericArgument, QGenericArgument, QGenericArgument, QGenericArgument, QGenericArgument, QGenericArgument, QGenericArgument, QGenericArgument, QGenericArgument) const qmetaobject.cpp:2390 #41 0x10f298aed in QMetaMethod::invoke(QObject*, Qt::ConnectionType, QGenericArgument, QGenericArgument, QGenericArgument, QGenericArgument, QGenericArgument, QGenericArgument, QGenericArgument, QGenericArgument, QGenericArgument, QGenericArgument) const qmetaobject.h:126 #42 0x10f29fdca in QTest::TestMethods::invokeTests(QObject*) const qtestcase.cpp:1539 #43 0x10f2a23cf in QTest::qRun() qtestcase.cpp:2018 #44 0x10f2a1047 in QTest::qExec(QObject*, int, char**) qtestcase.cpp:1920 #45 0x10e3ab836 in main tst_app.cpp:7095 #46 0x11139751d in start+0x1cd (dyld:x86_64+0x551d)
- Loading branch information