Skip to content

Background refresh workers can write through freed owner memory after shutdown

Summary

GeoLocation and IPFilter background refresh workers carry a raw pointer back to the owning object's queued flag. During shutdown the owners are deleted without joining those workers. If a worker is blocked in WinInet or file I/O and then finishes after the owner is gone, fallback cleanup can write through freed memory.

This is a critical Beta 0.7.3 blocker because it is a silent shutdown race: it can surface as heap corruption, a delayed crash, or unrelated memory damage rather than a deterministic failure at the refresh call site.

Evidence

  • srchybrid/GeoLocation.cpp:776 stores &m_lBackgroundRefreshQueued in the worker context.
  • srchybrid/IPFilterUpdater.cpp:383 stores &m_lBackgroundRefreshQueued in the worker context.
  • srchybrid/GeoLocation.cpp:65 can write through the context flag pointer when completion delivery falls back locally.
  • srchybrid/IPFilterUpdater.cpp:101 can write through the context flag pointer when completion delivery falls back locally.
  • srchybrid/EmuleDlg.cpp:2442 deletes theApp.ipfilterUpdater during shutdown.
  • srchybrid/EmuleDlg.cpp:2445 deletes theApp.geolocation during shutdown.

Execution Plan

  1. Revalidate the current lifetime of GeoLocation, IPFilterUpdater, and their refresh worker contexts on current main.
  2. Remove the raw pointer from worker context back into owner storage, or replace it with an explicitly owned lifetime token whose storage outlives the worker.
  3. Add a shutdown path that cancels and joins outstanding refresh workers before deleting the owner, if ownership remains with the owner.
  4. Ensure failed UI notification, normal completion, and shutdown completion all release the same context exactly once.
  5. Preserve current manual and automatic refresh serialization semantics.
  6. Add a targeted seam that forces completion after owner shutdown or failed notification delivery and verifies no dangling owner write occurs.
  7. Run the smallest relevant app validation plus focused GeoLocation/IPFilter refresh tests.

Acceptance Criteria

  • Refresh worker completion never writes through memory owned by a deleted GeoLocation or IPFilterUpdater instance.
  • Shutdown cannot delete either owner while a worker still has a live raw pointer into that owner.
  • Normal successful refresh behavior remains unchanged.
  • Failed refresh and failed notification cleanup leave the refresh state reusable.
  • The item has commit evidence and targeted validation in this file before Beta 0.7.3.

Validation

  • 2026-05-08: Done in app commit cfb0625.
  • python -m emule_workspace validate --workspace-root . passed.
  • python -m emule_workspace build app --workspace-root . --config Release --platform x64 --variant main passed; log root workspaces\v0.72a\state\build-logs\20260508-101442.
  • python -m emule_workspace build app --workspace-root . --config Debug --platform x64 --variant main passed; log root workspaces\v0.72a\state\build-logs\20260508-101508.
  • Code validation: GeoLocation and IPFilter refresh workers now hold shared heap-owned refresh state instead of raw pointers into their owning objects, so worker fallback cleanup cannot write through freed owner memory after shutdown.