From b3ee8cda1030515844d727f3ee822ef7e48a159c Mon Sep 17 00:00:00 2001 From: David Faure Date: Wed, 26 Mar 2025 12:03:02 +0100 Subject: [PATCH] QTestLib: fix crashes when using qDebug()s from threads with -junitxml Other test loggers just output things immediately, but the junit test logger appends messages to a vector, so this needs to be mutex-protected. In case of qDebug()s from long-running threads, we also need to protect creation/destruction of systemOutputElement and systemErrorElement -- and in case of qFatal(), currentTestCase. Pick-to: 6.5 Change-Id: If35055fc232276a778951ebbfeaccd185b04f46b Reviewed-by: Edward Welbourne Reviewed-by: Jason McDonald (cherry picked from commit b4d6892ba5a745c1836daf34c850d13ef61e7ae0) Reviewed-by: Qt Cherry-pick Bot (cherry picked from commit 120a987544dc4d3824b02016dc837850b1fc8aef) --- src/testlib/qjunittestlogger.cpp | 19 ++++++++++++------- src/testlib/qjunittestlogger_p.h | 4 ++++ 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/src/testlib/qjunittestlogger.cpp b/src/testlib/qjunittestlogger.cpp index 2ba6e71bb98..ef4f1561c15 100644 --- a/src/testlib/qjunittestlogger.cpp +++ b/src/testlib/qjunittestlogger.cpp @@ -130,14 +130,17 @@ void QJUnitTestLogger::enterTestFunction(const char *function) void QJUnitTestLogger::enterTestCase(const char *name) { - currentTestCase = new QTestElement(QTest::LET_TestCase); - currentTestCase->addAttribute(QTest::AI_Name, name); - currentTestCase->addAttribute(QTest::AI_Classname, QTestResult::currentTestObjectName()); - listOfTestcases.push_back(currentTestCase); + { + QMutexLocker locker(&mutex); + currentTestCase = new QTestElement(QTest::LET_TestCase); + currentTestCase->addAttribute(QTest::AI_Name, name); + currentTestCase->addAttribute(QTest::AI_Classname, QTestResult::currentTestObjectName()); + listOfTestcases.push_back(currentTestCase); - Q_ASSERT(!systemOutputElement && !systemErrorElement); - systemOutputElement = new QTestElement(QTest::LET_SystemOutput); - systemErrorElement = new QTestElement(QTest::LET_SystemError); + Q_ASSERT(!systemOutputElement && !systemErrorElement); + systemOutputElement = new QTestElement(QTest::LET_SystemOutput); + systemErrorElement = new QTestElement(QTest::LET_SystemError); + } // The element will be deleted when the suite is deleted @@ -174,6 +177,7 @@ void QJUnitTestLogger::leaveTestFunction() void QJUnitTestLogger::leaveTestCase() { + QMutexLocker locker(&mutex); currentTestCase->addAttribute(QTest::AI_Time, toSecondsFormat(elapsedTestCaseSeconds() * 1000).constData()); @@ -257,6 +261,7 @@ void QJUnitTestLogger::addMessage(MessageTypes type, const QString &message, con Q_UNUSED(file); Q_UNUSED(line); + QMutexLocker locker(&mutex); if (type == QFatal) { addFailure(QTest::LET_Error, "qfatal", message); return; diff --git a/src/testlib/qjunittestlogger_p.h b/src/testlib/qjunittestlogger_p.h index 6a7ff316152..6c4c7d71f2a 100644 --- a/src/testlib/qjunittestlogger_p.h +++ b/src/testlib/qjunittestlogger_p.h @@ -19,6 +19,7 @@ #include #include +#include #include @@ -61,6 +62,9 @@ class QJUnitTestLogger : public QAbstractTestLogger QTestElement *systemOutputElement = nullptr; QTestElement *systemErrorElement = nullptr; QTestJUnitStreamer *logFormatter = nullptr; + // protects currentTestCase, systemOutputElement and systemErrorElement + // in case of qDebug()/qWarning() etc. from threads + QMutex mutex; int testCounter = 0; int failureCounter = 0;