From 47f5c21e1b48fcbed6644fb74e7e5df8bb2414b7 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Thu, 21 Mar 2024 18:09:48 +0100 Subject: [PATCH] QSignalSpy: pull makeArgs() out of ctor critical section MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit First store the result in a temporary, and, in the critical section, only move it into place. This minimizes the amount of code in the critical section (Amdahl's Law) and also means we don't need to permanently drop the mutex when we call unbounded code using metacall(). That, in turn, makes sure the args member is only ever seen empty or fully populated. Since makeArgs() no longer accesses member functions now, we can make it static. Task-number: QTBUG-123544 Change-Id: If19db53f85d7c9eb18d4fb2c61e1aa3d4b9c2e00 Reviewed-by: MÃ¥rten Nordheim Reviewed-by: Ahmad Samir Reviewed-by: David Faure --- src/testlib/qsignalspy.cpp | 3 --- src/testlib/qsignalspy.h | 11 +++++++++-- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/testlib/qsignalspy.cpp b/src/testlib/qsignalspy.cpp index 05b9868e34..52be7ff212 100644 --- a/src/testlib/qsignalspy.cpp +++ b/src/testlib/qsignalspy.cpp @@ -223,17 +223,14 @@ QSignalSpy::ObjectSignal QSignalSpy::verify(const QObject *obj, QMetaMethod sign QList QSignalSpy::makeArgs(const QMetaMethod &member, const QObject *obj) { QList result; - QMutexLocker locker(&m_mutex); result.reserve(member.parameterCount()); for (int i = 0; i < member.parameterCount(); ++i) { QMetaType tp = member.parameterMetaType(i); if (!tp.isValid() && obj) { - locker.unlock(); void *argv[] = { &tp, &i }; QMetaObject::metacall(const_cast(obj), QMetaObject::RegisterMethodArgumentMetaType, member.methodIndex(), argv); - locker.relock(); } if (!tp.isValid()) { qWarning("QSignalSpy: Unable to handle parameter '%s' of type '%s' of method '%s'," diff --git a/src/testlib/qsignalspy.h b/src/testlib/qsignalspy.h index af9587b369..cbb3bfbe42 100644 --- a/src/testlib/qsignalspy.h +++ b/src/testlib/qsignalspy.h @@ -12,6 +12,8 @@ #include #include +#include + QT_BEGIN_NAMESPACE @@ -66,7 +68,12 @@ private: { if (!os.obj) return; - args = makeArgs(os.sig, os.obj); + + auto tmp = makeArgs(os.sig, os.obj); + { + const auto lock = std::scoped_lock(m_mutex); + args = std::move(tmp); + } if (!connectToSignal(os.obj, os.sig.methodIndex())) return; @@ -82,7 +89,7 @@ private: Q_TESTLIB_EXPORT static bool isSignalMetaMethodValid(const QMetaMethod &signal); Q_TESTLIB_EXPORT static bool isObjectValid(const QObject *object); - Q_TESTLIB_EXPORT QList makeArgs(const QMetaMethod &member, const QObject *obj); + Q_TESTLIB_EXPORT static QList makeArgs(const QMetaMethod &member, const QObject *obj); Q_TESTLIB_EXPORT void appendArgs(void **a); // the full, normalized signal name