From 1e2b42523f3a04fc3403ef6864bbcba447e4362c Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Wed, 6 Jan 2016 17:46:11 +0100 Subject: Fix UB in tst_QObject::disconnectDoesNotLeakFunctor() If CountedStruct is passed a GetSenderObject object, it will attempt to call a member on it from within its own destructor. That works usually quite well, but in this test case, which tests for function object leaks when a connection is torn down because the sender object is destroyed, the destruction of the CountedStruct happens when all connections are severed in ~QObject. At that point, what used to be a GetSenderObject instance no longer is one and the call into one of its member functions invokes undefined behavior. Fix by making QObject::sender() public by a using declaration instead of a wrapper function. Found by UBSan: tests/auto/corelib/kernel/qobject/tst_qobject.cpp:6007:104: runtime error: member call on address 0x7ffc6e7538b0 which does not point to an object of type 'GetSenderObject' 0x7ffc6e7538b0: note: object is of type 'QObject' Change-Id: Ia973140037b3c1b5a670a8a3949d09b956f40349 Reviewed-by: Olivier Goffart (Woboq GmbH) --- tests/auto/corelib/kernel/qobject/tst_qobject.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'tests/auto/corelib/kernel') diff --git a/tests/auto/corelib/kernel/qobject/tst_qobject.cpp b/tests/auto/corelib/kernel/qobject/tst_qobject.cpp index aa6ab31065..5b1dad78cf 100644 --- a/tests/auto/corelib/kernel/qobject/tst_qobject.cpp +++ b/tests/auto/corelib/kernel/qobject/tst_qobject.cpp @@ -5987,7 +5987,7 @@ class GetSenderObject : public QObject { Q_OBJECT public: - QObject *accessSender() { return sender(); } + using QObject::sender; // make public public Q_SLOTS: void triggerSignal() { Q_EMIT aSignal(); } @@ -6003,8 +6003,8 @@ struct CountedStruct CountedStruct(GetSenderObject *sender) : sender(sender) { ++countedStructObjectsCount; } CountedStruct(const CountedStruct &o) : sender(o.sender) { ++countedStructObjectsCount; } CountedStruct &operator=(const CountedStruct &) { return *this; } - // accessSender here allows us to check if there's a deadlock - ~CountedStruct() { --countedStructObjectsCount; if (sender != Q_NULLPTR) (void)sender->accessSender(); } + // calling sender() here allows us to check if there's a deadlock + ~CountedStruct() { --countedStructObjectsCount; if (sender) (void)sender->sender(); } void operator()() const { } GetSenderObject *sender; -- cgit v1.2.3