Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qsharedimageloader.cpp
Go to the documentation of this file.
1// Copyright (C) 2017 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
6#include <private/qobject_p.h>
7#include <private/qimage_p.h>
8
9#include <QtCore/qpointer.h>
10#include <QSharedMemory>
11
12#include <memory>
13
15
16Q_LOGGING_CATEGORY(lcSharedImage, "qt.quick.sharedimage");
17
28
29#if QT_CONFIG(sharedmemory)
30struct SharedImageInfo {
31 QString path;
32 QPointer<QSharedMemory> shmp;
33};
34
35void cleanupSharedImage(void *cleanupInfo)
36{
37 if (!cleanupInfo)
38 return;
39 SharedImageInfo *sii = static_cast<SharedImageInfo *>(cleanupInfo);
40 qCDebug(lcSharedImage) << "Cleanup called for" << sii->path;
41 if (sii->shmp.isNull()) {
42 qCDebug(lcSharedImage) << "shm is 0 for" << sii->path;
43 return;
44 }
45 QSharedMemory *shm = sii->shmp.data();
46 sii->shmp.clear();
47 delete shm; // destructor detaches
48 delete sii;
49}
50#else
51void cleanupSharedImage(void *) {}
52#endif
53
55{
56 Q_DECLARE_PUBLIC(QSharedImageLoader)
57
58public:
60
62
63 void storeImageToMem(void *data, const QImage &img);
64
65 bool verifyMem(const void *data, int size);
66
67 QImage createImageFromMem(const void *data, void *cleanupInfo);
68
69};
70
71
72void QSharedImageLoaderPrivate::storeImageToMem(void *data, const QImage &img)
73{
74 Q_ASSERT(data && !img.isNull());
75
76 SharedImageHeader *h = static_cast<SharedImageHeader *>(data);
77 h->magic = 'Q';
78 h->version = 1;
79 h->offset = sizeof(SharedImageHeader);
80 h->width = img.width();
81 h->height = img.height();
82 h->bpl = img.bytesPerLine();
83 h->format = img.format();
84
85 uchar *p = static_cast<uchar *>(data) + sizeof(SharedImageHeader);
86 memcpy(p, img.constBits(), img.sizeInBytes());
87}
88
89
90bool QSharedImageLoaderPrivate::verifyMem(const void *data, int size)
91{
92 if (!data || size < int(sizeof(SharedImageHeader)))
93 return false;
94
95 const SharedImageHeader *h = static_cast<const SharedImageHeader *>(data);
96 if ((h->magic != 'Q')
97 || (h->version < 1)
98 || (h->offset < sizeof(SharedImageHeader))
99 || (h->width <= 0)
100 || (h->height <= 0)
101 || (h->bpl <= 0)
102 || (h->format <= QImage::Format_Invalid)
103 || (h->format >= QImage::NImageFormats)) {
104 return false;
105 }
106
107 int availSize = size - h->offset;
108 if (h->height * h->bpl > availSize)
109 return false;
110 if ((qt_depthForFormat(h->format) * h->width * h->height) > (8 * availSize))
111 return false;
112
113 return true;
114}
115
116
117QImage QSharedImageLoaderPrivate::createImageFromMem(const void *data, void *cleanupInfo)
118{
119 const SharedImageHeader *h = static_cast<const SharedImageHeader *>(data);
120 const uchar *p = static_cast<const uchar *>(data) + h->offset;
121
122 QImage img(p, h->width, h->height, h->bpl, h->format, cleanupSharedImage, cleanupInfo);
123 return img;
124}
125
126
127QImage QSharedImageLoaderPrivate::load(const QString &path, QSharedImageLoader::ImageParameters *params)
128{
129#if QT_CONFIG(sharedmemory)
130 Q_Q(QSharedImageLoader);
131
132 QImage nil;
133 if (path.isEmpty())
134 return nil;
135
136 auto shm = std::make_unique<QSharedMemory>(QSharedMemory::legacyNativeKey(q->key(path, params)));
137 bool locked = false;
138
139 if (!shm->attach(QSharedMemory::ReadOnly)) {
140 QImage img = q->loadFile(path, params);
141 if (img.isNull())
142 return nil;
143 size_t size = sizeof(SharedImageHeader) + img.sizeInBytes();
144 if (size > size_t(std::numeric_limits<int>::max())) {
145 qCDebug(lcSharedImage) << "Image" << path << "to large to load";
146 return nil;
147 } else if (shm->create(int(size))) {
148 qCDebug(lcSharedImage) << "Created new shm segment of size" << size << "for image" << path;
149 if (!shm->lock()) {
150 qCDebug(lcSharedImage) << "Lock1 failed!?" << shm->errorString();
151 return nil;
152 }
153 locked = true;
154 storeImageToMem(shm->data(), img);
155 } else if (shm->error() == QSharedMemory::AlreadyExists) {
156 // race handling: other process may have created the share while
157 // we loaded the image, so try again to just attach
158 if (!shm->attach(QSharedMemory::ReadOnly)) {
159 qCDebug(lcSharedImage) << "Attach to existing failed?" << shm->errorString();
160 return nil;
161 }
162 } else {
163 qCDebug(lcSharedImage) << "Create failed?" << shm->errorString();
164 return nil;
165 }
166 }
167
168 Q_ASSERT(shm->isAttached());
169
170 if (!locked) {
171 if (!shm->lock()) {
172 qCDebug(lcSharedImage) << "Lock2 failed!?" << shm->errorString();
173 return nil;
174 }
175 locked = true;
176 }
177
178 if (!verifyMem(shm->constData(), shm->size())) {
179 qCDebug(lcSharedImage) << "Verifymem failed!?";
180 shm->unlock();
181 return nil;
182 }
183
184 QSharedMemory *shmp = shm.release();
185 SharedImageInfo *sii = new SharedImageInfo;
186 sii->path = path;
187 sii->shmp = shmp;
188 QImage shImg = createImageFromMem(shmp->constData(), sii);
189
190 if (!shmp->unlock()) {
191 qCDebug(lcSharedImage) << "UnLock failed!?";
192 }
193
194 return shImg;
195#else
196 Q_UNUSED(path);
197 Q_UNUSED(params);
198 return QImage();
199#endif
200}
201
202
203QSharedImageLoader::QSharedImageLoader(QObject *parent)
204 : QObject(*new QSharedImageLoaderPrivate, parent)
205{
206}
207
208QSharedImageLoader::~QSharedImageLoader()
209{
210}
211
212QImage QSharedImageLoader::load(const QString &path, ImageParameters *params)
213{
214 Q_D(QSharedImageLoader);
215
216 return d->load(path, params);
217}
218
219QImage QSharedImageLoader::loadFile(const QString &path, ImageParameters *params)
220{
221 Q_UNUSED(params);
222
223 return QImage(path);
224}
225
226QString QSharedImageLoader::key(const QString &path, ImageParameters *params)
227{
228 Q_UNUSED(params);
229
230 return path;
231}
232
233
234QT_END_NAMESPACE
235
236#include "moc_qsharedimageloader_p.cpp"
void storeImageToMem(void *data, const QImage &img)
bool verifyMem(const void *data, int size)
QImage createImageFromMem(const void *data, void *cleanupInfo)
Q_LOGGING_CATEGORY(lcEventDispatcher, "qt.eventdispatcher")
Q_STATIC_ASSERT(sizeof(SharedImageHeader) % 4==0)
void cleanupSharedImage(void *)