QContiguousCache: drag the initialization of atomic ref behind ABI boundary

All callers of QContiguousCache<T>::allocateData() followed the call
with a storeRelaxed(1) to the ref member. So we can just drag that
into the function itself.

Next, it's UB to storeRelaxed() into a default-constructed std::atomic
(and, therefore, into a QBasicAtomicInt), because until C++17
(inclusive) you're supposed to use std::atomic_init to assign the
first (and only the first) value to a default-constructed
std::atomic. QBasicAtomic doesn't have API for that, so you can never
assign anything to a default-constructed QBasicAtomic.

To fix, use placement new to be able to create a QBasicAtomic directly
with an initial value (replacing QBasicAtomic with QAtomic wouldn't
help here, either, since a malloc doesn't run ctors).

A proper fix has to wait until we can depend on C++20's atomic_ref,
which decouples the underlying type from the atomic operations
performed on it, letting us depend on malloc's zero-initialization
of an int member properly initializing it even for a following atomic
operation on it.

Task-number: QTBUG-137465
Pick-to: 6.10 6.9 6.8 6.5
Change-Id: Ic22d0766bcffb967a86c8ec28b63ee480aebd4a0
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
Marc Mutz 2025-06-06 19:39:58 +02:00
parent 4896448ffd
commit 49db71bb19
2 changed files with 2 additions and 5 deletions

View File

@ -22,7 +22,8 @@ void QContiguousCacheData::dump() const
QContiguousCacheData *QContiguousCacheData::allocateData(qsizetype size, qsizetype alignment)
{
return static_cast<QContiguousCacheData *>(qMallocAligned(size_t(size), size_t(alignment)));
void *mem = qMallocAligned(size_t(size), size_t(alignment));
return new (mem) QContiguousCacheData{/*ref=*/1, 0, 0, 0, 0};
}
void QContiguousCacheData::freeData(QContiguousCacheData *data)

View File

@ -152,7 +152,6 @@ template <typename T>
void QContiguousCache<T>::detach_helper()
{
Data *x = allocateData(d->alloc);
x->ref.storeRelaxed(1);
x->count = d->count;
x->start = d->start;
x->offset = d->offset;
@ -184,7 +183,6 @@ void QContiguousCache<T>::setCapacity(qsizetype asize)
return;
detach();
Data *x = allocateData(asize);
x->ref.storeRelaxed(1);
x->alloc = asize;
x->count = qMin(d->count, asize);
x->offset = d->offset + d->count - x->count;
@ -231,7 +229,6 @@ void QContiguousCache<T>::clear()
d->count = d->start = d->offset = 0;
} else {
Data *x = allocateData(d->alloc);
x->ref.storeRelaxed(1);
x->alloc = d->alloc;
x->count = x->start = x->offset = 0;
if (!d->ref.deref())
@ -251,7 +248,6 @@ QContiguousCache<T>::QContiguousCache(qsizetype cap)
{
Q_ASSERT(cap >= 0);
d = allocateData(cap);
d->ref.storeRelaxed(1);
d->alloc = cap;
d->count = d->start = d->offset = 0;
}