Logging: fix crash when decoding a symbol that isn't a function
Saw this on my FreeBSD VM. The backtrace() function thought the nearest symbol to something was "_ZTSNSt3__110__function6__baseIFbPvS2_EEE", which decoded to typeinfo name for std::__1::__function::__base<bool (void*, void*)> The function pointer type inside parameter threw the decoder for a loop and caused it to crash with the failed assertion in qbytearray.h: inline char QByteArray::at(qsizetype i) const { Q_ASSERT(size_t(i) < size_t(size())); return d.data()[i]; } I noticed this - because tst_qtimer hung - because qFormatLogMessage deadlocked acquiring QMessagePattern::mutex - because the logging recursed - because qCleanupFuncinfo failed an assertion while formatting the backtrace (my QT_MESSAGE_PATTERN has %{backtrace}) - because QTimer::~QTimer -> QObject::killTimer printed a warning - because tst_QTimer::moveToThread produces warnings Pick-to: 5.15 6.2 6.4 6.5 Change-Id: Ieec322d73c1e40ad95c8fffd17464f86e9725991 Reviewed-by: Kai Köhne <kai.koehne@qt.io>
This commit is contained in:
parent
c827b058dd
commit
644c06b48f
@ -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;
|
||||
|
@ -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<void (*)(int)>::~Polymorphic()"
|
||||
<< "Polymorphic::~Polymorphic";
|
||||
|
||||
QTest::newRow("gcc_41")
|
||||
<< "function<void (int*)>()::S::f()"
|
||||
<< "function()::S::f";
|
||||
|
||||
QTest::newRow("msvc_41")
|
||||
<< "void `void function<void __cdecl(int *)>(void)'::`2'::S::f(void)"
|
||||
<< "function(void)'::`2'::S::f";
|
||||
|
||||
QTest::newRow("gcc_42")
|
||||
<< "function<Polymorphic<void (int*)> >()::S::f(Polymorphic<void (int*)>*)"
|
||||
<< "function()::S::f";
|
||||
|
||||
QTest::newRow("msvc_42")
|
||||
<< "void `void function<Polymorphic<void __cdecl(int *)> >(void)'::`2'::S::f(Polymorphic<void __cdecl(int *)> *)"
|
||||
<< "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<char, std::char_traits<char> >::~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<QByteArray>("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<bool (void*, void*)>");
|
||||
addBadFrame("vtable for BezierEase");
|
||||
addBadFrame("vtable for Polymorphic<void ()>");
|
||||
addBadFrame("vtable for Polymorphic<void (*)(int)>");
|
||||
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<void, std::integral_constant<bool, true> > >");
|
||||
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()
|
||||
|
Loading…
x
Reference in New Issue
Block a user