From 49db71bb1995d8fa71afedb9b461d5203fbe49b1 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Fri, 6 Jun 2025 19:39:58 +0200 Subject: [PATCH] QContiguousCache: drag the initialization of atomic ref behind ABI boundary All callers of QContiguousCache::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 --- src/corelib/tools/qcontiguouscache.cpp | 3 ++- src/corelib/tools/qcontiguouscache.h | 4 ---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/corelib/tools/qcontiguouscache.cpp b/src/corelib/tools/qcontiguouscache.cpp index 4a3fd73dc1f..6ca739c3059 100644 --- a/src/corelib/tools/qcontiguouscache.cpp +++ b/src/corelib/tools/qcontiguouscache.cpp @@ -22,7 +22,8 @@ void QContiguousCacheData::dump() const QContiguousCacheData *QContiguousCacheData::allocateData(qsizetype size, qsizetype alignment) { - return static_cast(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) diff --git a/src/corelib/tools/qcontiguouscache.h b/src/corelib/tools/qcontiguouscache.h index e630b56cfa1..8dfa0874050 100644 --- a/src/corelib/tools/qcontiguouscache.h +++ b/src/corelib/tools/qcontiguouscache.h @@ -152,7 +152,6 @@ template void QContiguousCache::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::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::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::QContiguousCache(qsizetype cap) { Q_ASSERT(cap >= 0); d = allocateData(cap); - d->ref.storeRelaxed(1); d->alloc = cap; d->count = d->start = d->offset = 0; }