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:776stores&m_lBackgroundRefreshQueuedin the worker context.srchybrid/IPFilterUpdater.cpp:383stores&m_lBackgroundRefreshQueuedin the worker context.srchybrid/GeoLocation.cpp:65can write through the context flag pointer when completion delivery falls back locally.srchybrid/IPFilterUpdater.cpp:101can write through the context flag pointer when completion delivery falls back locally.srchybrid/EmuleDlg.cpp:2442deletestheApp.ipfilterUpdaterduring shutdown.srchybrid/EmuleDlg.cpp:2445deletestheApp.geolocationduring shutdown.
Execution Plan¶
- Revalidate the current lifetime of GeoLocation, IPFilterUpdater, and their
refresh worker contexts on current
main. - 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.
- Add a shutdown path that cancels and joins outstanding refresh workers before deleting the owner, if ownership remains with the owner.
- Ensure failed UI notification, normal completion, and shutdown completion all release the same context exactly once.
- Preserve current manual and automatic refresh serialization semantics.
- Add a targeted seam that forces completion after owner shutdown or failed notification delivery and verifies no dangling owner write occurs.
- 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 mainpassed; log rootworkspaces\v0.72a\state\build-logs\20260508-101442.python -m emule_workspace build app --workspace-root . --config Debug --platform x64 --variant mainpassed; log rootworkspaces\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.