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) <ogoffart@woboq.com>
This commit is contained in:
Marc Mutz 2016-01-06 17:46:11 +01:00
parent 889fcfbf2b
commit 1e2b42523f

View File

@ -5987,7 +5987,7 @@ class GetSenderObject : public QObject
{ {
Q_OBJECT Q_OBJECT
public: public:
QObject *accessSender() { return sender(); } using QObject::sender; // make public
public Q_SLOTS: public Q_SLOTS:
void triggerSignal() { Q_EMIT aSignal(); } void triggerSignal() { Q_EMIT aSignal(); }
@ -6003,8 +6003,8 @@ struct CountedStruct
CountedStruct(GetSenderObject *sender) : sender(sender) { ++countedStructObjectsCount; } CountedStruct(GetSenderObject *sender) : sender(sender) { ++countedStructObjectsCount; }
CountedStruct(const CountedStruct &o) : sender(o.sender) { ++countedStructObjectsCount; } CountedStruct(const CountedStruct &o) : sender(o.sender) { ++countedStructObjectsCount; }
CountedStruct &operator=(const CountedStruct &) { return *this; } CountedStruct &operator=(const CountedStruct &) { return *this; }
// accessSender here allows us to check if there's a deadlock // calling sender() here allows us to check if there's a deadlock
~CountedStruct() { --countedStructObjectsCount; if (sender != Q_NULLPTR) (void)sender->accessSender(); } ~CountedStruct() { --countedStructObjectsCount; if (sender) (void)sender->sender(); }
void operator()() const { } void operator()() const { }
GetSenderObject *sender; GetSenderObject *sender;