diff options
author | Marc Mutz <[email protected]> | 2025-06-06 16:40:48 +0200 |
---|---|---|
committer | Marc Mutz <[email protected]> | 2025-06-12 14:04:58 +0200 |
commit | 5aefe2d9a1d56f6134fcbbdff260c79082eea661 (patch) | |
tree | 805451e6af2847ef52ed9bc85257ec3d424942d7 | |
parent | 3047d6a8a19fed870597d6c482f6c1a826ffb9f2 (diff) |
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 <[email protected]>
-rw-r--r-- | src/corelib/tools/qrefcount.h | 1 | ||||
-rw-r--r-- | src/gui/painting/qregion.cpp | 3 | ||||
-rw-r--r-- | 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<QRegionData*>(&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<QRegionData*>(&shared_empty); @@ -3854,7 +3852,6 @@ QRegion::QRegion(const QBitmap &bm) d = const_cast<QRegionData*>(&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; |