Skip to content

Search tab teardown frees live result and tab-parameter objects before the UI detaches them

Historical reference only: stale-v0.72a-experimental-clean and analysis\stale-v0.72a-experimental-clean are retired reference sources, not active branch targets or current baselines. Use them only as provenance or idea-extraction sources; landed status is determined against main. See Historical References.

Summary

Current main tears down search data in the wrong order when a search tab is closed or when Close All Search Results is used.

The search list view stores raw CSearchFile* pointers in item lParam, and the tab control stores raw SSearchParams* pointers in tab lParam. Current teardown deletes those backing objects before the controls are fully cleared or before selection-change notifications are finished.

That leaves a real use-after-free/crash window on a live UI path.

Landed In Main

Fixed in eMule-main by commit 8ba6248 (BUG-026 harden search tab teardown lifetime ordering).

The landed fix:

  • clears the active results list before RemoveResults() frees backing CSearchFile objects
  • defers closed-tab SSearchParams deletion until after tab removal and reselection/show logic
  • defers DeleteAllSearches() parameter deletion until after NoTabItems()
  • reorders NoTabItems() so UI controls detach before theApp.searchlist->Clear()

Validated by supported app rebuild:

  • EMULE_WORKSPACE_ROOT\workspaces\v0.72a\state\build-logs\20260418-202603\summary.json

Evidence In Current Tree

  • srchybrid/SearchListCtrl.cpp:336-346
  • CSearchListCtrl::AddResult() inserts raw CSearchFile* into list item lParam
  • srchybrid/SearchList.cpp:94-105
  • CSearchList::RemoveResults() explicitly warns that it does not delete the window items, then immediately deletes every CSearchFile
  • srchybrid/SearchResultsWnd.cpp:1410-1418
  • DeleteSearch() calls theApp.searchlist->RemoveResults(uSearchID); before the tab/list UI is detached, then deletes the tab's SSearchParams*
  • srchybrid/SearchResultsWnd.cpp:1443-1456
  • DeleteAllSearches() deletes every SSearchParams* before NoTabItems()
  • srchybrid/SearchResultsWnd.cpp:1459-1464
  • NoTabItems() clears the controls only afterward via searchlistctrl.DeleteAllItems() and searchselect.DeleteAllItems()

Why This Is A Real Bug

Two separate ownership violations exist:

  1. DeleteSearch() frees CSearchFile objects before the list control drops the raw item pointers that reference them.
  2. DeleteAllSearches() frees SSearchParams before the tab control is cleared, even though tab selection/teardown handlers still access those lParam pointers.

This is not hypothetical. SearchList.cpp:96 documents the contract directly: RemoveResults() will not remove the window items for the caller. Current DeleteSearch() violates that contract.

User-Visible / Runtime Impact

  • crash or heap corruption when closing the active search tab
  • crash when using Close All Search Results while tabs are still open
  • unstable search window behavior during selection-change or redraw while tab teardown is in progress

Cross-Variant Status

  • workspaces\v0.72a\app\eMule-main\srchybrid\SearchResultsWnd.cpp:1410-1456
  • bug is present
  • analysis\stale-v0.72a-experimental-clean\srchybrid\SearchResultsWnd.cpp:1491-1537
  • bug is also present there
  • analysis\emuleai\srchybrid\SearchResultsWnd.cpp:1512-1585
  • partially fixed there:
  • the current-results list is cleared before RemoveResults() when closing the active tab
  • DeleteAllSearches() defers SSearchParams deletion until after NoTabItems()

The emuleai release notes also explicitly call out a crash fix for Close All Search Results, which aligns with this teardown path.

Likely Fix Shape

Any acceptable fix should do both:

  1. detach the active result list from its CSearchFile* row pointers before calling RemoveResults()
  2. defer SSearchParams deletion until after searchselect.DeleteAllItems() has finished, matching the corrected emuleai ordering

Validation Target

  • open multiple search tabs, including one active tab with visible results
  • close the active tab repeatedly and confirm no crash/redraw corruption
  • use Close All Search Results with tabs still open and confirm no crash
  • test with search tooltips/selection changes enabled to exercise re-entrant UI notifications during teardown