Skip to content

Commit dd2a131

Browse files
Capture QPointer in queued cloud upload callbacks.
Avoid use-after-free when the session is destroyed while worker callbacks are still queued. Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent ef4f30d commit dd2a131

1 file changed

Lines changed: 40 additions & 37 deletions

File tree

src/QtMeshCloudSession.cpp

Lines changed: 40 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,10 @@
1414

1515
namespace {
1616

17-
void invokeUploadProgress(QtMeshCloudSession* self, int current, int total, const QString& label)
17+
void invokeUploadProgress(const QPointer<QtMeshCloudSession>& self,
18+
int current,
19+
int total,
20+
const QString& label)
1821
{
1922
if (!self)
2023
return;
@@ -26,7 +29,7 @@ void invokeUploadProgress(QtMeshCloudSession* self, int current, int total, cons
2629
Qt::QueuedConnection);
2730
}
2831

29-
void invokeUploadFinished(QtMeshCloudSession* self,
32+
void invokeUploadFinished(const QPointer<QtMeshCloudSession>& self,
3033
bool ok,
3134
const QString& error,
3235
const QString& projectUrl,
@@ -42,7 +45,7 @@ void invokeUploadFinished(QtMeshCloudSession* self,
4245
Qt::QueuedConnection);
4346
}
4447

45-
void invokeUploadCanceled(QtMeshCloudSession* self)
48+
void invokeUploadCanceled(const QPointer<QtMeshCloudSession>& self)
4649
{
4750
if (!self)
4851
return;
@@ -54,7 +57,7 @@ void invokeUploadCanceled(QtMeshCloudSession* self)
5457
Qt::QueuedConnection);
5558
}
5659

57-
void invokePrepareWarning(QtMeshCloudSession* self, const QString& warning)
60+
void invokePrepareWarning(const QPointer<QtMeshCloudSession>& self, const QString& warning)
5861
{
5962
if (!self || warning.isEmpty())
6063
return;
@@ -117,22 +120,22 @@ void QtMeshCloudSession::uploadPackageFromAssets(const CloudPackageUploadRequest
117120

118121
QThread* worker = QThread::create([self, token, req, canceled = &m_canceled]() {
119122
if (canceled->load()) {
120-
invokeUploadCanceled(self.data());
123+
invokeUploadCanceled(self);
121124
return;
122125
}
123126

124-
invokeUploadProgress(self.data(), 0, 1, QStringLiteral("Preparing package…"));
127+
invokeUploadProgress(self, 0, 1, QStringLiteral("Preparing package…"));
125128

126129
QJsonObject scanSummary;
127130
if (req.runLocalScan) {
128-
invokeUploadProgress(self.data(), 0, 1, QStringLiteral("Scanning assets…"));
131+
invokeUploadProgress(self, 0, 1, QStringLiteral("Scanning assets…"));
129132
const QFileInfo mainAssetInfo(req.mainAssetPath);
130133
QString scanError;
131134
const QByteArray scanJson = AssetScanController::runIsolatedScanJsonSync(
132135
mainAssetInfo.absolutePath(), mainAssetInfo.fileName(), &scanError);
133136
if (scanJson.isEmpty()) {
134137
invokePrepareWarning(
135-
self.data(),
138+
self,
136139
scanError.isEmpty()
137140
? QStringLiteral("Local scan failed; continuing without scan summary.")
138141
: QStringLiteral("Local scan failed; continuing without scan summary.\n\n%1")
@@ -142,7 +145,7 @@ void QtMeshCloudSession::uploadPackageFromAssets(const CloudPackageUploadRequest
142145
const QJsonDocument doc = QJsonDocument::fromJson(scanJson, &parseError);
143146
if (parseError.error != QJsonParseError::NoError || !doc.isObject()) {
144147
invokePrepareWarning(
145-
self.data(),
148+
self,
146149
QStringLiteral("Local scan returned invalid JSON; continuing without scan summary.\n\n%1")
147150
.arg(parseError.errorString()));
148151
} else {
@@ -152,21 +155,21 @@ void QtMeshCloudSession::uploadPackageFromAssets(const CloudPackageUploadRequest
152155
}
153156

154157
if (canceled->load()) {
155-
invokeUploadCanceled(self.data());
158+
invokeUploadCanceled(self);
156159
return;
157160
}
158161

159162
const PackageMetadata package = CloudUploadDialog::buildManifestForUpload(
160163
req.mainAssetPath, req.selectedAbsolutePaths, req.projectName, scanSummary);
161164
if (package.files.isEmpty()) {
162-
invokeUploadFinished(self.data(), false,
165+
invokeUploadFinished(self, false,
163166
QStringLiteral("Select at least one file to upload."), {}, {});
164167
return;
165168
}
166169

167170
for (const PackageEntry& entry : package.files) {
168171
if (!QFileInfo::exists(entry.absolutePath)) {
169-
invokeUploadFinished(self.data(), false,
172+
invokeUploadFinished(self, false,
170173
QStringLiteral("Missing file: %1")
171174
.arg(QFileInfo(entry.absolutePath).fileName()),
172175
{}, {});
@@ -202,11 +205,11 @@ void QtMeshCloudSession::uploadPackageFromAssets(const CloudPackageUploadRequest
202205
}
203206

204207
if (canceled->load()) {
205-
invokeUploadCanceled(self.data());
208+
invokeUploadCanceled(self);
206209
return;
207210
}
208211
if (!project.ok) {
209-
invokeUploadFinished(self.data(), false, project.errorString, {}, {});
212+
invokeUploadFinished(self, false, project.errorString, {}, {});
210213
return;
211214
}
212215

@@ -223,11 +226,11 @@ void QtMeshCloudSession::uploadPackageFromAssets(const CloudPackageUploadRequest
223226
const auto uploadUrls = QtMeshCloudClient::requestUploadUrls(
224227
token, project.ownerSlug, project.projectSlug, descriptors);
225228
if (canceled->load()) {
226-
invokeUploadCanceled(self.data());
229+
invokeUploadCanceled(self);
227230
return;
228231
}
229232
if (!uploadUrls.ok) {
230-
invokeUploadFinished(self.data(), false, uploadUrls.errorString, {}, {});
233+
invokeUploadFinished(self, false, uploadUrls.errorString, {}, {});
231234
return;
232235
}
233236

@@ -237,20 +240,20 @@ void QtMeshCloudSession::uploadPackageFromAssets(const CloudPackageUploadRequest
237240
const int total = uploadUrls.uploads.size();
238241
for (int i = 0; i < total; ++i) {
239242
if (canceled->load()) {
240-
invokeUploadCanceled(self.data());
243+
invokeUploadCanceled(self);
241244
return;
242245
}
243246

244-
invokeUploadProgress(self.data(), i + 1, total + 1, descriptors.at(i).uploadName);
247+
invokeUploadProgress(self, i + 1, total + 1, descriptors.at(i).uploadName);
245248

246249
const auto result = QtMeshCloudClient::uploadFileContent(
247250
token, uploadUrls.uploads.at(i), descriptors.at(i).path, canceled);
248251
if (result.canceled) {
249-
invokeUploadCanceled(self.data());
252+
invokeUploadCanceled(self);
250253
return;
251254
}
252255
if (!result.ok) {
253-
invokeUploadFinished(self.data(), false, result.errorString, {}, {});
256+
invokeUploadFinished(self, false, result.errorString, {}, {});
254257
return;
255258
}
256259

@@ -264,16 +267,16 @@ void QtMeshCloudSession::uploadPackageFromAssets(const CloudPackageUploadRequest
264267
mainFileId = fallbackMainFileId;
265268

266269
if (canceled->load()) {
267-
invokeUploadCanceled(self.data());
270+
invokeUploadCanceled(self);
268271
return;
269272
}
270273

271-
invokeUploadProgress(self.data(), total + 1, total + 1, QString());
274+
invokeUploadProgress(self, total + 1, total + 1, QString());
272275

273276
const auto completed = QtMeshCloudClient::completeUpload(
274277
token, project.ownerSlug, project.projectSlug, uploadedFileIds, mainFileId);
275278
if (!completed.ok) {
276-
invokeUploadFinished(self.data(), false, completed.errorString, {}, {});
279+
invokeUploadFinished(self, false, completed.errorString, {}, {});
277280
return;
278281
}
279282

@@ -293,7 +296,7 @@ void QtMeshCloudSession::uploadPackageFromAssets(const CloudPackageUploadRequest
293296

294297
SentryReporter::addBreadcrumb(QStringLiteral("cloud.upload"),
295298
QStringLiteral("QtMesh Cloud package upload completed"));
296-
invokeUploadFinished(self.data(), true, reportWarning, project.projectUrl, completed.scanStatus);
299+
invokeUploadFinished(self, true, reportWarning, project.projectUrl, completed.scanStatus);
297300
});
298301

299302
connect(worker, &QThread::finished, worker, &QObject::deleteLater);
@@ -311,7 +314,7 @@ void QtMeshCloudSession::startUploadWorker(const PackageMetadata& package,
311314
QThread* worker = QThread::create([self, token, package, ownerSlug, projectSlug, createNewProject,
312315
canceled = &m_canceled]() {
313316
if (canceled->load()) {
314-
invokeUploadCanceled(self.data());
317+
invokeUploadCanceled(self);
315318
return;
316319
}
317320

@@ -335,11 +338,11 @@ void QtMeshCloudSession::startUploadWorker(const PackageMetadata& package,
335338
}
336339

337340
if (canceled->load()) {
338-
invokeUploadCanceled(self.data());
341+
invokeUploadCanceled(self);
339342
return;
340343
}
341344
if (!project.ok) {
342-
invokeUploadFinished(self.data(), false, project.errorString, {}, {});
345+
invokeUploadFinished(self, false, project.errorString, {}, {});
343346
return;
344347
}
345348

@@ -356,11 +359,11 @@ void QtMeshCloudSession::startUploadWorker(const PackageMetadata& package,
356359
const auto uploadUrls = QtMeshCloudClient::requestUploadUrls(
357360
token, project.ownerSlug, project.projectSlug, descriptors);
358361
if (canceled->load()) {
359-
invokeUploadCanceled(self.data());
362+
invokeUploadCanceled(self);
360363
return;
361364
}
362365
if (!uploadUrls.ok) {
363-
invokeUploadFinished(self.data(), false, uploadUrls.errorString, {}, {});
366+
invokeUploadFinished(self, false, uploadUrls.errorString, {}, {});
364367
return;
365368
}
366369

@@ -370,20 +373,20 @@ void QtMeshCloudSession::startUploadWorker(const PackageMetadata& package,
370373
const int total = uploadUrls.uploads.size();
371374
for (int i = 0; i < total; ++i) {
372375
if (canceled->load()) {
373-
invokeUploadCanceled(self.data());
376+
invokeUploadCanceled(self);
374377
return;
375378
}
376379

377-
invokeUploadProgress(self.data(), i + 1, total + 1, descriptors.at(i).uploadName);
380+
invokeUploadProgress(self, i + 1, total + 1, descriptors.at(i).uploadName);
378381

379382
const auto result = QtMeshCloudClient::uploadFileContent(
380383
token, uploadUrls.uploads.at(i), descriptors.at(i).path, canceled);
381384
if (result.canceled) {
382-
invokeUploadCanceled(self.data());
385+
invokeUploadCanceled(self);
383386
return;
384387
}
385388
if (!result.ok) {
386-
invokeUploadFinished(self.data(), false, result.errorString, {}, {});
389+
invokeUploadFinished(self, false, result.errorString, {}, {});
387390
return;
388391
}
389392

@@ -397,16 +400,16 @@ void QtMeshCloudSession::startUploadWorker(const PackageMetadata& package,
397400
mainFileId = fallbackMainFileId;
398401

399402
if (canceled->load()) {
400-
invokeUploadCanceled(self.data());
403+
invokeUploadCanceled(self);
401404
return;
402405
}
403406

404-
invokeUploadProgress(self.data(), total + 1, total + 1, QString());
407+
invokeUploadProgress(self, total + 1, total + 1, QString());
405408

406409
const auto completed = QtMeshCloudClient::completeUpload(
407410
token, project.ownerSlug, project.projectSlug, uploadedFileIds, mainFileId);
408411
if (!completed.ok) {
409-
invokeUploadFinished(self.data(), false, completed.errorString, {}, {});
412+
invokeUploadFinished(self, false, completed.errorString, {}, {});
410413
return;
411414
}
412415

@@ -426,7 +429,7 @@ void QtMeshCloudSession::startUploadWorker(const PackageMetadata& package,
426429

427430
SentryReporter::addBreadcrumb(QStringLiteral("cloud.upload"),
428431
QStringLiteral("QtMesh Cloud package upload completed"));
429-
invokeUploadFinished(self.data(), true, reportWarning, project.projectUrl, completed.scanStatus);
432+
invokeUploadFinished(self, true, reportWarning, project.projectUrl, completed.scanStatus);
430433
});
431434

432435
connect(worker, &QThread::finished, worker, &QObject::deleteLater);

0 commit comments

Comments
 (0)