From 5aefe2d9a1d56f6134fcbbdff260c79082eea661 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Fri, 6 Jun 2025 16:40:48 +0200 Subject: [PATCH] QRegion: fix potential UB in QBasicAtomic initialization Until C++17 (inclusive), a default-constructed std::atomic object can, officially, only be initialized with a call to std::atomic_init, for which QBasicAtomic doesn't have API. It is even unclear whether zero-initialization of static and thread-local objects will cause the object to be initialized. QRegion is using QtPrivate::RefCount, but that's just another wrapper around QBasicAtomic, so it has the same problems: it must always be initialized. So don't default-construct and then storeRelaxed() (via initializeOwned()), use NSDMI with (newly-added) Q_REFCOUNT_INITIALIZE_OWNED to avoid this dark language corner. Task-number: QTBUG-137465 Pick-to: 6.10 6.9 6.8 6.5 Change-Id: I4b765aed329211984c35c40fbc5648bf104990ce Reviewed-by: Thiago Macieira --- src/corelib/tools/qrefcount.h | 1 + src/gui/painting/qregion.cpp | 3 --- src/gui/painting/qregion.h | 2 +- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/corelib/tools/qrefcount.h b/src/corelib/tools/qrefcount.h index 9472716a723..da0942903d0 100644 --- a/src/corelib/tools/qrefcount.h +++ b/src/corelib/tools/qrefcount.h @@ -50,6 +50,7 @@ public: } #define Q_REFCOUNT_INITIALIZE_STATIC { Q_BASIC_ATOMIC_INITIALIZER(-1) } +#define Q_REFCOUNT_INITIALIZE_OWNED { Q_BASIC_ATOMIC_INITIALIZER(1) } QT_END_NAMESPACE diff --git a/src/gui/painting/qregion.cpp b/src/gui/painting/qregion.cpp index 0d39ee05437..2b8c86ad84a 100644 --- a/src/gui/painting/qregion.cpp +++ b/src/gui/painting/qregion.cpp @@ -3812,7 +3812,6 @@ QRegion::QRegion(const QRect &r, RegionType t) d = const_cast(&shared_empty); } else { d = new QRegionData; - d->ref.initializeOwned(); if (t == Rectangle) { d->qt_rgn = new QRegionPrivate(r); } else if (t == Ellipse) { @@ -3831,7 +3830,6 @@ QRegion::QRegion(const QPolygon &a, Qt::FillRule fillRule) fillRule == Qt::WindingFill ? WindingRule : EvenOddRule); if (qt_rgn) { d = new QRegionData; - d->ref.initializeOwned(); d->qt_rgn = qt_rgn; } else { d = const_cast(&shared_empty); @@ -3854,7 +3852,6 @@ QRegion::QRegion(const QBitmap &bm) d = const_cast(&shared_empty); } else { d = new QRegionData; - d->ref.initializeOwned(); d->qt_rgn = qt_bitmapToRegion(bm); } } diff --git a/src/gui/painting/qregion.h b/src/gui/painting/qregion.h index 4b852815f32..f7f35a8725b 100644 --- a/src/gui/painting/qregion.h +++ b/src/gui/painting/qregion.h @@ -121,7 +121,7 @@ Q_GUI_EXPORT void exec(const QByteArray &ba, int ver = 0, QDataStream::ByteOrder byteOrder = QDataStream::BigEndian); #endif struct QRegionData { - QtPrivate::RefCount ref; + QtPrivate::RefCount ref = Q_REFCOUNT_INITIALIZE_OWNED; QRegionPrivate *qt_rgn; }; struct QRegionData *d;