Skip to content

fix(networkjobs): move processEvents after reply reads in LsColJob - #10093

Merged
mgallien merged 1 commit into
masterfrom
bugfix/lscoljob-use-after-free-on-process-events
Jun 3, 2026
Merged

fix(networkjobs): move processEvents after reply reads in LsColJob#10093
mgallien merged 1 commit into
masterfrom
bugfix/lscoljob-use-after-free-on-process-events

Conversation

@camilasan

Copy link
Copy Markdown
Member

Resolves

Users on 4.0.9/4.0.10 started hitting a SIGSEGV at reply()->request().url().path() inside LsColJob::finished(). Crash address 0x8 (null pointer + 8 bytes) — the QPointer was zeroed by the time that line ran.

Summay

e9a0dbd (Jan 2024) added a QCoreApplication::processEvents() call inside LsColJob::finished() for UI responsiveness, placing it before the reply was read. The code even warned about this in a comment, but left the reply() access after processEvents() unguarded.

A pending deleteLater() on the reply — triggered by the network timeout timer — can be drained inside that processEvents() call, zeroing the QPointer. The function then crashes reading from null.

ee899a8 (March 2026) flipped enableTimeout = false → true, re-enabling the request timeout feature. With the timer active again, timeouts fire regularly during the 100 ms processEvents() window, making the race consistently reproducible in production.

This PR moves processEvents() to after all reply() accesses. The parse and signal emissions complete while the pointer is still valid. processEvents() still runs for UI responsiveness, just after parsing instead of before it.

Tests

Added to testremotediscovery:

  • testLsColJobDoesNotCrashWhenReplyIsDeletedDuringProcessEvents — uses a fake reply that schedules its own deleteLater() via a zero-timeout timer, reproducing the deletion-during-processEvents condition. Verifies no crash and that unaffected folders sync normally.
  • testLsColJobSucceedsNormally — confirms the happy path (successful listing + local state matches remote) is unaffected by the change.

Checklist

AI (if applicable)

  • The content of this PR was partly or fully generated using AI

@camilasan camilasan added this to the 33.0.6 milestone Jun 1, 2026
@camilasan camilasan added the bug label Jun 1, 2026
@camilasan

Copy link
Copy Markdown
Member Author

/backport to stable-33.0

@camilasan
camilasan force-pushed the bugfix/lscoljob-use-after-free-on-process-events branch from 48b97f9 to 653f0b3 Compare June 1, 2026 13:12
@camilasan
camilasan marked this pull request as ready for review June 1, 2026 14:21
@camilasan

Copy link
Copy Markdown
Member Author

/backport to stable-4.0

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes a reproducible crash in LsColJob::finished() caused by calling QCoreApplication::processEvents() before reading from the QNetworkReply, which could drain a pending deleteLater() and null the underlying QPointer.

Changes:

  • Move QCoreApplication::processEvents(..., 100) to run after all reply() reads/accesses in LsColJob::finished().
  • Add a regression test that forces a QNetworkReply to schedule deleteLater() such that it can be processed during processEvents(), ensuring no crash.
  • Add a “happy path” test to ensure normal listing/sync behavior remains unchanged.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
src/libsync/networkjobs.cpp Reorders processEvents() to avoid reply() use-after-free/null deref during LsColJob::finished().
test/testremotediscovery.cpp Adds regression + sanity tests covering reply deletion during processEvents() and normal listing behavior.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

LsColJob::finished() called QCoreApplication::processEvents() before
reading the reply. A pending deleteLater() processed during that
call would zero the QPointer<QNetworkReply>, causing a SIGSEGV
on the subsequent reply()->request().url().path() access.

Fix: move processEvents to after all reply() accesses so the pointer
cannot be invalidated before it is used.

Signed-off-by: Camila Ayres <[email protected]>
@mgallien
mgallien enabled auto-merge June 3, 2026 07:38
@mgallien
mgallien force-pushed the bugfix/lscoljob-use-after-free-on-process-events branch from 653f0b3 to 8925d0a Compare June 3, 2026 07:38
@github-actions

github-actions Bot commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

Artifact containing the AppImage: nextcloud-appimage-pr-10093.zip

Digest: sha256:1a886355fc183ee862ba50ed816c6cf06b5a51306eca2fcf7e4ef25429a98f07

To test this change/fix you can download the above artifact file, unzip it, and run it.

Please make sure to quit your existing Nextcloud app and backup your data.

@mgallien
mgallien merged commit 1c458ac into master Jun 3, 2026
21 checks passed
@mgallien
mgallien deleted the bugfix/lscoljob-use-after-free-on-process-events branch June 3, 2026 09:04
@sonarqubecloud

sonarqubecloud Bot commented Jun 3, 2026

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
21 Security Hotspots
E Maintainability Rating on New Code (required ≥ A)
15 New Code Smells (required ≤ 0)

See analysis details on SonarQube Cloud

Catch issues before they fail your Quality Gate with our IDE extension SonarQube for IDE

@mgallien mgallien modified the milestones: 33.0.6, 34.0.0 Jun 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants