From cd0b5bba9a1a76e03d4b9b5105c4d16d1e1dfd1e Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Fri, 2 Oct 2020 16:33:33 +0200 Subject: Make the named QColorSpace constructor thread-safe Avoid accessing the shared pointer table without using atomic. Cleans up the shared table on exit for leak tracking utilities. Pick-to: 5.15 Change-Id: Ia2d6d79dea1c8be02bae2d8111e290f49eedf409 Reviewed-by: Giuseppe D'Angelo --- src/gui/painting/qcolorspace.cpp | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) (limited to 'src/gui/painting') diff --git a/src/gui/painting/qcolorspace.cpp b/src/gui/painting/qcolorspace.cpp index 5ae071f480..5657a90b9b 100644 --- a/src/gui/painting/qcolorspace.cpp +++ b/src/gui/painting/qcolorspace.cpp @@ -46,6 +46,7 @@ #include "qcolortransform_p.h" #include "qicc_p.h" +#include #include #include @@ -55,6 +56,18 @@ QT_BEGIN_NAMESPACE QBasicMutex QColorSpacePrivate::s_lutWriteLock; +static QAtomicPointer s_predefinedColorspacePrivates[QColorSpace::ProPhotoRgb] = {}; +static void cleanupPredefinedColorspaces() +{ + for (QAtomicPointer &ptr : s_predefinedColorspacePrivates) { + QColorSpacePrivate *prv = ptr.fetchAndStoreAcquire(nullptr); + if (prv && !prv->ref.deref()) + delete prv; + } +} + +Q_DESTRUCTOR_FUNCTION(cleanupPredefinedColorspaces) + QColorSpacePrimaries::QColorSpacePrimaries(QColorSpace::Primaries primaries) { switch (primaries) { @@ -426,12 +439,18 @@ QColorSpace::QColorSpace(NamedColorSpace namedColorSpace) qWarning() << "QColorSpace attempted constructed from invalid QColorSpace::NamedColorSpace: " << int(namedColorSpace); return; } - static QColorSpacePrivate *predefinedColorspacePrivates[QColorSpace::ProPhotoRgb + 1]; - if (!predefinedColorspacePrivates[namedColorSpace]) { - predefinedColorspacePrivates[namedColorSpace] = new QColorSpacePrivate(namedColorSpace); - predefinedColorspacePrivates[namedColorSpace]->ref.ref(); + // The defined namespaces start at 1: + auto &atomicRef = s_predefinedColorspacePrivates[static_cast(namedColorSpace) - 1]; + QColorSpacePrivate *cspriv = atomicRef.loadAcquire(); + if (!cspriv) { + auto *tmp = new QColorSpacePrivate(namedColorSpace); + tmp->ref.ref(); + if (atomicRef.testAndSetOrdered(nullptr, tmp, cspriv)) + cspriv = tmp; + else + delete tmp; } - d_ptr = predefinedColorspacePrivates[namedColorSpace]; + d_ptr = cspriv; d_ptr->ref.ref(); Q_ASSERT(isValid()); } -- cgit v1.2.3