diff --git a/src/corelib/global/qlogging.cpp b/src/corelib/global/qlogging.cpp index e80e5b72d52..82e79e5e01c 100644 --- a/src/corelib/global/qlogging.cpp +++ b/src/corelib/global/qlogging.cpp @@ -1021,6 +1021,12 @@ Q_AUTOTEST_EXPORT QByteArray qCleanupFuncinfo(QByteArray info) // Don't know how to parse this function name return info; } + if (info.indexOf('>', pos) != -1 + || info.indexOf(':', pos) != -1) { + // that wasn't the function argument list. + pos = info.size(); + break; + } // find the beginning of the argument list --pos; diff --git a/tests/auto/corelib/global/qlogging/tst_qlogging.cpp b/tests/auto/corelib/global/qlogging/tst_qlogging.cpp index 0a43395ac91..7e2f9e3838c 100644 --- a/tests/auto/corelib/global/qlogging/tst_qlogging.cpp +++ b/tests/auto/corelib/global/qlogging/tst_qlogging.cpp @@ -30,6 +30,8 @@ private slots: #ifdef QT_BUILD_INTERNAL void cleanupFuncinfo_data(); void cleanupFuncinfo(); + void cleanupFuncinfoBad_data(); + void cleanupFuncinfoBad(); #endif void qMessagePattern_data(); @@ -599,6 +601,26 @@ void tst_qmessagehandler::cleanupFuncinfo_data() << "int TestClass1::operator>(int)" << "TestClass1::operator>"; + QTest::newRow("gcc_40") + << "Polymorphic::~Polymorphic()" + << "Polymorphic::~Polymorphic"; + + QTest::newRow("gcc_41") + << "function()::S::f()" + << "function()::S::f"; + + QTest::newRow("msvc_41") + << "void `void function(void)'::`2'::S::f(void)" + << "function(void)'::`2'::S::f"; + + QTest::newRow("gcc_42") + << "function >()::S::f(Polymorphic*)" + << "function()::S::f"; + + QTest::newRow("msvc_42") + << "void `void function >(void)'::`2'::S::f(Polymorphic *)" + << "function(void)'::`2'::S::f"; + QTest::newRow("objc_1") << "-[SomeClass someMethod:withArguments:]" << "-[SomeClass someMethod:withArguments:]"; @@ -614,6 +636,14 @@ void tst_qmessagehandler::cleanupFuncinfo_data() QTest::newRow("objc_4") << "__31-[SomeClass someMethodSchedulingBlock]_block_invoke" << "__31-[SomeClass someMethodSchedulingBlock]_block_invoke"; + + QTest::newRow("thunk-1") + << "non-virtual thunk to QFutureWatcherBasePrivate::postCallOutEvent(QFutureCallOutEvent const&)" + << "QFutureWatcherBasePrivate::postCallOutEvent"; + + QTest::newRow("thunk-2") + << "virtual thunk to std::basic_iostream >::~basic_iostream()" + << "std::basic_iostream::~basic_iostream"; } #endif @@ -634,6 +664,41 @@ void tst_qmessagehandler::cleanupFuncinfo() QEXPECT_FAIL("TestClass1::nested_struct_const", "Nested function processing is broken", Continue); QTEST(QString::fromLatin1(result), "expected"); } + +void tst_qmessagehandler::cleanupFuncinfoBad_data() +{ + QTest::addColumn("funcinfo"); + + auto addBadFrame = [i = 0](const char *symbol) mutable { + QTest::addRow("%d", ++i) << QByteArray(symbol); + }; + addBadFrame("typeinfo for QEventLoop"); + addBadFrame("typeinfo name for QtPrivate::ResultStoreBase"); + addBadFrame("typeinfo name for ._anon_476"); + addBadFrame("typeinfo name for std::__1::__function::__base"); + addBadFrame("vtable for BezierEase"); + addBadFrame("vtable for Polymorphic"); + addBadFrame("vtable for Polymorphic"); + addBadFrame("TLS wrapper function for (anonymous namespace)::jitStacks"); + addBadFrame("lcCheckIndex()::category"); + addBadFrame("guard variable for lcEPDetach()::category"); + addBadFrame("guard variable for QImageReader::read(QImage*)::disableNxImageLoading"); + addBadFrame("VTT for std::__1::ostrstream"); + addBadFrame("qIsRelocatable<(anonymous namespace)::Data>"); + addBadFrame("qt_incomplete_metaTypeArray<(anonymous namespace)::qt_meta_stringdata_CLASSQNonContiguousByteDeviceIoDeviceImplENDCLASS_t, QtPrivate::TypeAndForceComplete > >"); + addBadFrame("f()::i"); +} + +void tst_qmessagehandler::cleanupFuncinfoBad() +{ + QFETCH(QByteArray, funcinfo); + + // A corrupted stack trace may find non-sensical symbols that aren't + // functions. The result doesn't matter, so long as we don't crash or hang. + + QByteArray result = qCleanupFuncinfo(funcinfo); + qDebug() << "Decode of" << funcinfo << "produced" << result; +} #endif void tst_qmessagehandler::qMessagePattern_data()