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 const int depth = qt_depthForFormat(h->format);
108 if (h->bpl < (qint64(h->width) * depth + 7) / 8)
109 return false;
110
111 qint64 availSize = size - h->offset;
112 if (qint64(h->height) * h->bpl > availSize)
113 return false;
114
115 return true;
116}
117
118
119QImage QSharedImageLoaderPrivate::createImageFromMem(const void *data, void *cleanupInfo)
120{
121 const SharedImageHeader *h = static_cast<const SharedImageHeader *>(data);
122 const uchar *p = static_cast<const uchar *>(data) + h->offset;
123
124 QImage img(p, h->width, h->height, h->bpl, h->format, cleanupSharedImage, cleanupInfo);
125 return img;
126}
127
128
129QImage QSharedImageLoaderPrivate::load(const QString &path, QSharedImageLoader::ImageParameters *params)
130{
131#if QT_CONFIG(sharedmemory)
132 Q_Q(QSharedImageLoader);
133
134 QImage nil;
135 if (path.isEmpty())
136 return nil;
137
138 auto shm = std::make_unique<QSharedMemory>(QSharedMemory::legacyNativeKey(q->key(path, params)));
139 bool locked = false;
140
141 if (!shm->attach(QSharedMemory::ReadOnly)) {
142 QImage img = q->loadFile(path, params);
143 if (img.isNull())
144 return nil;
145 size_t size = sizeof(SharedImageHeader) + img.sizeInBytes();
146 if (size > size_t(std::numeric_limits<int>::max())) {
147 qCDebug(lcSharedImage) << "Image" << path << "to large to load";
148 return nil;
149 } else if (shm->create(int(size))) {
150 qCDebug(lcSharedImage) << "Created new shm segment of size" << size << "for image" << path;
151 if (!shm->lock()) {
152 qCDebug(lcSharedImage) << "Lock1 failed!?" << shm->errorString();
153 return nil;
154 }
155 locked = true;
156 storeImageToMem(shm->data(), img);
157 } else if (shm->error() == QSharedMemory::AlreadyExists) {
158 // race handling: other process may have created the share while
159 // we loaded the image, so try again to just attach
160 if (!shm->attach(QSharedMemory::ReadOnly)) {
161 qCDebug(lcSharedImage) << "Attach to existing failed?" << shm->errorString();
162 return nil;
163 }
164 } else {
165 qCDebug(lcSharedImage) << "Create failed?" << shm->errorString();
166 return nil;
167 }
168 }
169
170 Q_ASSERT(shm->isAttached());
171
172 if (!locked) {
173 if (!shm->lock()) {
174 qCDebug(lcSharedImage) << "Lock2 failed!?" << shm->errorString();
175 return nil;
176 }
177 locked = true;
178 }
179
180 if (!verifyMem(shm->constData(), shm->size())) {
181 qCDebug(lcSharedImage) << "Verifymem failed!?";
182 shm->unlock();
183 return nil;
184 }
185
186 QSharedMemory *shmp = shm.release();
187 SharedImageInfo *sii = new SharedImageInfo;
188 sii->path = path;
189 sii->shmp = shmp;
190 QImage shImg = createImageFromMem(shmp->constData(), sii);
191
192 if (!shmp->unlock()) {
193 qCDebug(lcSharedImage) << "UnLock failed!?";
194 }
195
196 return shImg;
197#else
198 Q_UNUSED(path);
199 Q_UNUSED(params);
200 return QImage();
201#endif
202}
203
204
205QSharedImageLoader::QSharedImageLoader(QObject *parent)
206 : QObject(*new QSharedImageLoaderPrivate, parent)
207{
208}
209
210QSharedImageLoader::~QSharedImageLoader()
211{
212}
213
214QImage QSharedImageLoader::load(const QString &path, ImageParameters *params)
215{
216 Q_D(QSharedImageLoader);
217
218 return d->load(path, params);
219}
220
221QImage QSharedImageLoader::loadFile(const QString &path, ImageParameters *params)
222{
223 Q_UNUSED(params);
224
225 return QImage(path);
226}
227
228QString QSharedImageLoader::key(const QString &path, ImageParameters *params)
229{
230 Q_UNUSED(params);
231
232 return path;
233}
234
235
236QT_END_NAMESPACE
237
238#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 *)