QSharedPointer: Use matching new/delete

When a weak pointer calls getAndRef and there is no strong reference
yet, getAndRef creates a new ExternalRefCountData. Normally,
ExternalRefCountData is never constructed directly, only its subclasses
are constructed via placement new into a memory buffer.
To that end, ExternalRefCountData has a custom operator delete, which
calls the global operator delete (do deallocate the memory buffer
correctly).
When using operator new directly in getAndRef, gcc notices a new/delete
mismatch with the delete in the same function: global operator new
matched with class operator delete. This isn't actually an issue in
practice, as the class operator delete simply calls the global delete.
But to avoid the warning, we can simply call the global operators
explicitly.
To make it clear that allocation of ExternalRefCountData requires some
care, we additionally delete the class operator new, and only allow
placement new (or usage of global operator new, as in getAndRef).

Task-number: QTBUG-93360
Change-Id: I132d1e4e07520eadc5b8f3f955c06aecec80c646
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
(cherry picked from commit 5e96c64afb274a3cc4364b1390ce0b776d637dd6)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
Fabian Kosmale 2021-05-24 17:29:10 +02:00 committed by Qt Cherry-pick Bot
parent 80fe72c6ec
commit 9bed8335f7
2 changed files with 8 additions and 2 deletions

View File

@ -1400,7 +1400,7 @@ QtSharedPointer::ExternalRefCountData *QtSharedPointer::ExternalRefCountData::ge
}
// we can create the refcount data because it doesn't exist
ExternalRefCountData *x = new ExternalRefCountData(Qt::Uninitialized);
ExternalRefCountData *x = ::new ExternalRefCountData(Qt::Uninitialized);
x->strongref.storeRelaxed(-1);
x->weakref.storeRelaxed(2); // the QWeakPointer that called us plus the QObject itself
@ -1411,7 +1411,7 @@ QtSharedPointer::ExternalRefCountData *QtSharedPointer::ExternalRefCountData::ge
// ~ExternalRefCountData has a Q_ASSERT, so we use this trick to
// only execute this if Q_ASSERTs are enabled
Q_ASSERT((x->weakref.storeRelaxed(0), true));
delete x;
::delete x;
ret->weakref.ref();
}
return ret;

View File

@ -153,6 +153,12 @@ namespace QtSharedPointer {
inline void checkQObjectShared(...) { }
inline void setQObjectShared(...) { }
// Normally, only subclasses of ExternalRefCountData are allocated
// One exception exists in getAndRef; that uses the global operator new
// to prevent a mismatch with the custom operator delete
inline void *operator new(std::size_t) = delete;
// placement new
inline void *operator new(std::size_t, void *ptr) noexcept { return ptr; }
inline void operator delete(void *ptr) { ::operator delete(ptr); }
inline void operator delete(void *, void *) { }
};