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.9 6.8 6.5
Change-Id: I4b765aed329211984c35c40fbc5648bf104990ce
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
(cherry picked from commit 5aefe2d9a1d56f6134fcbbdff260c79082eea661)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
Marc Mutz 2025-06-06 16:40:48 +02:00 committed by Qt Cherry-pick Bot
parent ee0cb525cd
commit 2b0ec367c7
3 changed files with 2 additions and 4 deletions

View File

@ -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

View File

@ -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);
}
}

View File

@ -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;