Skip to content

Startup-cache save worker can outlive shared-file list owner

Summary

The shared startup-cache save path starts a background worker with a raw CSharedFileList* owner pointer, posts that raw owner pointer back to the UI, and has failure paths that can still touch owner state from the worker. Shutdown waits only a bounded interval before abandoning the save, so late completion can cross object lifetime boundaries.

This is a critical Beta 0.7.3 blocker because it is the same lifetime class as the background refresh owner fixes, but on the shared-files startup-cache path. A release build must not rely on a leak-or-assert convention to prevent a late worker from dereferencing deleted state.

Evidence

  • srchybrid/SharedFileList.cpp:2236 allocates the worker request.
  • srchybrid/SharedFileList.cpp:2240 stores pOwner = this.
  • srchybrid/SharedFileList.cpp:3047 dereferences pOwner in the worker.
  • srchybrid/SharedFileList.cpp:3054 posts the raw owner pointer through UM_STARTUP_CACHE_SAVE_COMPLETE.
  • srchybrid/SharedFileList.cpp:3058 handles failed UI notification by touching owner state from the worker path.
  • srchybrid/EmuleDlg.cpp:2338 waits only briefly during shutdown before abandoning the startup-cache save.
  • srchybrid/EmuleDlg.cpp:3908 trusts the raw pointer received in the UI completion message.

Execution Plan

  1. Revalidate the current startup-cache save ownership model against current main, including normal save, shutdown save, timeout abandon, and failed UI post.
  2. Replace the worker request's raw owner pointer with an explicitly owned save-operation state object or lifetime token.
  3. Ensure the worker can complete, fail, or be abandoned without dereferencing CSharedFileList after the owner begins destruction.
  4. Make successful PostMessage transfer only the completion payload ownership needed by the UI; do not send a raw owner pointer as the authority for object lifetime.
  5. Make failed PostMessage a terminal cleanup path that does not call back into deleted or potentially deleting owner state from the worker thread.
  6. Define shutdown behavior explicitly: either join the save worker before CSharedFileList destruction or keep the worker-owned state alive until the worker exits without requiring the owner to remain allocated.
  7. Preserve current startup-cache file format, save timing, skip behavior after interrupted hashing, and successful startup performance behavior.
  8. Add targeted coverage or a deterministic seam for late save completion after shutdown abandon and for failed UI notification.
  9. Validate Debug and Release x64 app builds through the supported workspace entrypoints.

Acceptance Criteria

  • No startup-cache save worker path dereferences a raw CSharedFileList* after shutdown abandon or owner destruction begins.
  • UI completion does not depend on a raw owner pointer carried through WPARAM.
  • Failed completion delivery performs deterministic cleanup without worker-thread UI calls or owner-state mutation after destruction.
  • Shutdown remains bounded and does not leave unsafe global or owner state.
  • Startup-cache save success behavior and cache compatibility remain unchanged.
  • The item has commit evidence and targeted validation in this file before Beta 0.7.3.

Validation

  • 2026-05-08: Done in app commit bde9f16.
  • python -m emule_workspace validate --workspace-root . passed.
  • python -m emule_workspace build app --workspace-root . --config Debug --platform x64 --variant main passed; log root workspaces\v0.72a\state\build-logs\20260508-105211.
  • python -m emule_workspace build app --workspace-root . --config Release --platform x64 --variant main passed; log root workspaces\v0.72a\state\build-logs\20260508-105242.
  • Code validation: the startup-cache save worker now carries an owner-independent operation token and completion payload. The worker no longer receives or posts a raw CSharedFileList*, failed completion delivery discards persisted worker output without touching owner state, and shutdown abandon detaches the owner from the in-flight operation before destruction.