From 36760514a928b546ab5a944e60955361e6645d6a Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Wed, 4 Aug 2021 10:17:11 +0200 Subject: QXpmHandler: fix re-entrancy bug in xpm_color_name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The xpm_color_name() function returned a pointer to a function-static buffer. This is infamously non-reentrant, and an actual problem, because we explicitly allow QImage operations (incl. saving to an .xpm) from non-GUI-threads. Fix by using the CSS pattern (Caller-Supplied Storage; also used in the QAnyStringView(char32_t) and QAnyStringView(QStringBuilder) ctors) to force the caller to allocate storage in its own stack frame. As a consequence, we re-gain re-entrancy, but the returned pointer is now only valid until the end of the full-expression, which necessitated simplifying one caller (sorry!). To see why said simplification is valid, observe that xpm_color_name() writes a (now-explicit) NUL into returnable[cpp] and the old code read max(cpp, 4) characters from xpm_color_name()'s result. NB: cpp can be 5, even though the code comments say otherwise! :( [ChangeLog][QtGui][QImage] Fixed a race condition when concurrently writing .xpm files. Change-Id: I36d7173d53839a52f5cdf58324474c1b32c71f33 Reviewed-by: MÃ¥rten Nordheim (cherry picked from commit 73fabadcee71af858388fb245fccf4e96d4ead4e) Reviewed-by: Qt Cherry-pick Bot --- src/gui/image/qxpmhandler.cpp | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/gui/image/qxpmhandler.cpp b/src/gui/image/qxpmhandler.cpp index 8ec09f2480..ecfce93ee5 100644 --- a/src/gui/image/qxpmhandler.cpp +++ b/src/gui/image/qxpmhandler.cpp @@ -52,6 +52,7 @@ #include #include +#include QT_BEGIN_NAMESPACE @@ -1063,15 +1064,23 @@ bool qt_read_xpm_image_or_array(QIODevice *device, const char * const * source, return read_xpm_body(device, source, index, state, cpp, ncols, w, h, image); } -static const char* xpm_color_name(int cpp, int index) +namespace { +template +struct CharBuffer : std::array +{ + CharBuffer() {} // avoid value-initializing the whole array +}; +} + +static const char* xpm_color_name(int cpp, int index, CharBuffer<5> && returnable = {}) { - static char returnable[5]; static const char code[] = ".#abcdefghijklmnopqrstuvwxyzABCD" "EFGHIJKLMNOPQRSTUVWXYZ0123456789"; // cpp is limited to 4 and index is limited to 64^cpp if (cpp > 1) { if (cpp > 2) { if (cpp > 3) { + returnable[4] = '\0'; returnable[3] = code[index % 64]; index /= 64; } else @@ -1091,7 +1100,7 @@ static const char* xpm_color_name(int cpp, int index) returnable[1] = '\0'; returnable[0] = code[index]; - return returnable; + return returnable.data(); } @@ -1157,16 +1166,7 @@ static bool write_xpm_image(const QImage &sourceImage, QIODevice *device, const const QRgb *yp = reinterpret_cast(image.constScanLine(y)); for(x=0; x 1) { - line.append(chars[1]); - if (cpp > 2) { - line.append(chars[2]); - if (cpp > 3) - line.append(chars[3]); - } - } + line.append(xpm_color_name(cpp, colorMap[color])); } s << ',' << Qt::endl << '\"' << line << '\"'; } -- cgit v1.2.3