From ac48a891463373e39064c398814cc6a9992a226c Mon Sep 17 00:00:00 2001 From: Robert Griebl Date: Fri, 5 Aug 2022 00:34:12 +0200 Subject: Intents: prevent a crash if a sent request is gc'ed too early Not saving the result of IntentClient.sendIntentRequest could lead to the GC deleting the IntentClientRequest before it was even delivered to the receiver, leaving a dangling pointer. Change-Id: I8972795d166fa46dd736005dd4df33b9a7ea2463 Reviewed-by: Qt CI Bot Reviewed-by: Bernd Weimer (cherry picked from commit bb186192373c6ff796c9084f22d48b02d14886c7) --- src/intent-client-lib/intentclient.cpp | 13 ++++++++++--- src/intent-client-lib/intentclient.h | 4 +++- src/manager-lib/intentaminterface.cpp | 3 +++ 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/intent-client-lib/intentclient.cpp b/src/intent-client-lib/intentclient.cpp index bbd483a7..17e91eae 100644 --- a/src/intent-client-lib/intentclient.cpp +++ b/src/intent-client-lib/intentclient.cpp @@ -123,6 +123,7 @@ IntentClient::IntentClient(IntentClientSystemInterface *systemInterface, QObject : QObject(parent) , m_systemInterface(systemInterface) { + m_lastWaitingCleanup.start(); m_systemInterface->setParent(this); } @@ -237,11 +238,11 @@ void IntentClient::replyFromSystem(const QUuid &requestId, bool error, const QVa { IntentClientRequest *icr = nullptr; auto it = std::find_if(m_waiting.begin(), m_waiting.end(), - [requestId](IntentClientRequest *ir) -> bool { - return (ir->requestId() == requestId); + [requestId](const QPointer &ir) -> bool { + return ir && (ir->requestId() == requestId); }); - if (it == m_waiting.cend()) { + if (it == m_waiting.end()) { qCWarning(LogIntents) << "IntentClient received an unexpected intent reply for request" << requestId << " succeeded:" << !error << "error:" << result.value(qL1S("errorMessage")).toString() << "result:" << result; @@ -250,6 +251,12 @@ void IntentClient::replyFromSystem(const QUuid &requestId, bool error, const QVa icr = *it; m_waiting.erase(it); + // make sure to periodically remove all requests that were gc'ed before a reply was received + if (m_lastWaitingCleanup.elapsed() > 1000) { + m_waiting.removeAll({ }); + m_lastWaitingCleanup.start(); + } + if (error) icr->setErrorMessage(result.value(qSL("errorMessage")).toString()); else diff --git a/src/intent-client-lib/intentclient.h b/src/intent-client-lib/intentclient.h index 54bbf24a..d03f92ce 100644 --- a/src/intent-client-lib/intentclient.h +++ b/src/intent-client-lib/intentclient.h @@ -49,6 +49,7 @@ #include #include #include +#include #include @@ -100,7 +101,8 @@ private: Q_DISABLE_COPY(IntentClient) static IntentClient *s_instance; - QList m_waiting; + QList> m_waiting; + QElapsedTimer m_lastWaitingCleanup; QMap, IntentHandler *> m_handlers; // intentId + appId -> handler // no timeouts by default -- these have to be set at runtime diff --git a/src/manager-lib/intentaminterface.cpp b/src/manager-lib/intentaminterface.cpp index 1b8f447c..b704082b 100644 --- a/src/manager-lib/intentaminterface.cpp +++ b/src/manager-lib/intentaminterface.cpp @@ -313,6 +313,9 @@ void IntentClientAMImplementation::requestToSystem(QPointer // on app startup and (b) have consistent behavior in single- and multi-process mode QMetaObject::invokeMethod(m_ic, [icr, this]() { + if (!icr) + return; + IntentServerRequest *isr = m_issi->requestToSystem(icr->requestingApplicationId(), icr->intentId(), icr->applicationId(), icr->parameters()); QUuid requestId = isr ? isr->requestId() : QUuid(); -- cgit v1.2.1