From 7d021e3173a03d384ac4b987545f8fdf52593a61 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Thu, 11 Aug 2022 11:15:05 +0200 Subject: QUnicodeTools: fix data race in initialization of libthai symbols MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The facilities of qunicodetools.cpp are not limited to the GUI thread, so initialization must be thread-safe. The old code wasn't, though, and contained several data races - non-atomic initialized was read while another thead may write it - th_brk and th_next_cell were read while another thead may write them Fix by using Double-Checked Locking. This also prepares the code for an eventual port to th_brk_find_breaks() (th_brk is deprecated). The function pointers don't need to be atomic, because all reads from them are guaranteed to happen-after the writes to them (as long as all users call init_libthai() and don't proceeed if it returns false; this could be ensured by returning a struct with the function pointers from init_libthai() instead of maintaining them as statically-visible globals, but that's outsize the scope of this patch). As a drive-by, remove a pointless static_cast(~~int expression~~). Fixes: QTBUG-105543 Pick-to: 6.4 6.3 6.2 Change-Id: I492acd7e9a257e5c4b91f576e9bc448b6bb96ad1 Reviewed-by: Ievgenii Meshcheriakov Reviewed-by: Lars Knoll Reviewed-by: MÃ¥rten Nordheim --- src/corelib/text/qunicodetools.cpp | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) (limited to 'src/corelib/text/qunicodetools.cpp') diff --git a/src/corelib/text/qunicodetools.cpp b/src/corelib/text/qunicodetools.cpp index a2a080d4ae..9d6590c6b8 100644 --- a/src/corelib/text/qunicodetools.cpp +++ b/src/corelib/text/qunicodetools.cpp @@ -3,12 +3,15 @@ #include "qunicodetools_p.h" +#include "qmutex.h" #include "qunicodetables_p.h" #include "qvarlengtharray.h" #if QT_CONFIG(library) #include "qlibrary.h" #endif +#include + #include #define FLAG(x) (1 << (x)) @@ -1405,11 +1408,15 @@ Q_CONSTINIT static th_next_cell_def th_next_cell = nullptr; static int init_libthai() { #if QT_CONFIG(library) - Q_CONSTINIT static bool initialized = false; - if (!initialized && (!th_brk || !th_next_cell)) { - th_brk = reinterpret_cast(QLibrary::resolve("thai"_L1, static_cast(LIBTHAI_MAJOR), "th_brk")); - th_next_cell = (th_next_cell_def)QLibrary::resolve("thai"_L1, LIBTHAI_MAJOR, "th_next_cell"); - initialized = true; + Q_CONSTINIT static QBasicAtomicInt initialized = Q_BASIC_ATOMIC_INITIALIZER(false); + Q_CONSTINIT static QBasicMutex mutex; + if (!initialized.loadAcquire()) { + const auto locker = std::scoped_lock(mutex); + if (!initialized.loadAcquire()) { + th_brk = reinterpret_cast(QLibrary::resolve("thai"_L1, LIBTHAI_MAJOR, "th_brk")); + th_next_cell = (th_next_cell_def)QLibrary::resolve("thai"_L1, LIBTHAI_MAJOR, "th_next_cell"); + initialized.storeRelease(true); + } } if (th_brk && th_next_cell) return 1; -- cgit v1.2.3