aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMÃ¥rten Nordheim <marten.nordheim@qt.io>2023-11-03 14:06:56 +0100
committerQt Cherry-pick Bot <cherrypick_bot@qt-project.org>2023-11-06 19:46:14 +0000
commit5b111a8d4be35105eebfd32dfaca2da890502f3e (patch)
tree4412c5dce4001986de6305eeaf91af02257ac839
parentf95f24467b553c406f58a555f154c97f76df1eac (diff)
Rewrite QuickTests's qWaitForSignal
It doesn't use any of the features of QSignalSpy, so it hasn't done it any favors. On top of that QSignalSpy connects with DirectConnection which means that frequently emitted signals on another thread may end up trying to append another signal emission to its internal list during destruction of the signal spy, leading to use-after-free. The new implementation uses a small class with a slot that just sets a boolean. We use AutoConnection so it is thread safe, and pending emissions go away when the object is destroyed. Fixes: QTBUG-118744 Fixes: QTBUG-118163 Pick-to: 6.5 Change-Id: Ib2ccce2369a681bfe9a2e04d2c091f9690edee49 Reviewed-by: Dimitrios Apostolou <jimis@qt.io> Reviewed-by: Ulf Hermann <ulf.hermann@qt.io> (cherry picked from commit 80532bcd26bd125763fe6b3f9ffd42e535e9b14c) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
-rw-r--r--src/qmltest/quicktest.cpp48
1 files changed, 36 insertions, 12 deletions
diff --git a/src/qmltest/quicktest.cpp b/src/qmltest/quicktest.cpp
index c333f7fe1b..b4bfd94d17 100644
--- a/src/qmltest/quicktest.cpp
+++ b/src/qmltest/quicktest.cpp
@@ -223,22 +223,45 @@ static void handleCompileErrors(
results.stopLogging();
}
+class SimpleReceiver : public QObject {
+ Q_OBJECT
+public:
+ bool signalReceived = false;
+public slots:
+ void slotFun() { signalReceived = true; }
+};
+
bool qWaitForSignal(QObject *obj, const char* signal, int timeout)
{
- QSignalSpy spy(obj, signal);
- QElapsedTimer timer;
- timer.start();
-
- while (!spy.size()) {
- int remaining = timeout - int(timer.elapsed());
- if (remaining <= 0)
- break;
- QCoreApplication::processEvents(QEventLoop::AllEvents, remaining);
- QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete);
- QTest::qSleep(10);
+ if (!obj || !signal) {
+ qWarning("qWaitForSignal: invalid arguments");
+ return false;
+ }
+ if (((signal[0] - '0') & 0x03) != QSIGNAL_CODE) {
+ qWarning("qWaitForSignal: not a valid signal, use the SIGNAL macro");
+ return false;
+ }
+
+ int sig = obj->metaObject()->indexOfSignal(signal + 1);
+ if (sig == -1) {
+ const QByteArray ba = QMetaObject::normalizedSignature(signal + 1);
+ sig = obj->metaObject()->indexOfSignal(ba.constData());
+ if (sig == -1) {
+ qWarning("qWaitForSignal: no such signal %s::%s", obj->metaObject()->className(),
+ signal);
+ return false;
+ }
+ }
+
+ SimpleReceiver receiver;
+ static int slot = receiver.metaObject()->indexOfSlot("slotFun()");
+ if (!QMetaObject::connect(obj, sig, &receiver, slot)) {
+ qWarning("qWaitForSignal: failed to connect to signal %s::%s",
+ obj->metaObject()->className(), signal);
+ return false;
}
- return spy.size();
+ return QTest::qWaitFor([&]() { return receiver.signalReceived; }, timeout);
}
template <typename... Args>
@@ -667,3 +690,4 @@ int quick_test_main_with_setup(int argc, char **argv, const char *name, const ch
QT_END_NAMESPACE
#include "moc_quicktest_p.cpp"
+#include "quicktest.moc"