summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMarc Mutz <marc.mutz@kdab.com>2021-08-04 10:17:11 +0200
committerQt Cherry-pick Bot <cherrypick_bot@qt-project.org>2021-08-05 04:33:20 +0000
commit36760514a928b546ab5a944e60955361e6645d6a (patch)
treec3e73b269441e2fba59a78c50fb1f3b2e746ca6c /src
parentaa23eb493cf020692972dd3d69bb63d7f2bc9db8 (diff)
QXpmHandler: fix re-entrancy bug in xpm_color_name
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 <marten.nordheim@qt.io> (cherry picked from commit 73fabadcee71af858388fb245fccf4e96d4ead4e) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
Diffstat (limited to 'src')
-rw-r--r--src/gui/image/qxpmhandler.cpp26
1 files changed, 13 insertions, 13 deletions
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 <private/qcolor_p.h>
#include <algorithm>
+#include <array>
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 <size_t N>
+struct CharBuffer : std::array<char, N>
+{
+ 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<const QRgb *>(image.constScanLine(y));
for(x=0; x<w; x++) {
int color = (int)(*(yp + x));
- const QByteArray chars(xpm_color_name(cpp, colorMap[color]));
- line.append(chars[0]);
- if (cpp > 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 << '\"';
}