Skip to content

Fix ChObjectExplorer leaking every ChValue allocated by a search - #788

Open
DanNegrut wants to merge 1 commit into
mainfrom
fix/objectexplorer-clearsearch-leak
Open

Fix ChObjectExplorer leaking every ChValue allocated by a search#788
DanNegrut wants to merge 1 commit into
mainfrom
fix/objectexplorer-clearsearch-leak

Conversation

@DanNegrut

Copy link
Copy Markdown
Contributor

ChObjectExplorer::ClearSearch() deletes the ChValue objects allocated by the previous search, but the delete loop was placed after this->results.clear(). By the time the loop was reached, results.size() was already zero, so the loop ran no iterations and deleted nothing.

ClearSearch() runs at the start of every search (via PrepareSearch) and again from the destructor, so every ChValue ever allocated by out(), out_array_pre() and out_ref() was leaked. A single FetchValues("*") over a container leaks one ChValue per matched property, and the Irrlicht object tree in ChIrrGUI builds a fresh explorer per node per frame, so the leak grows with runtime.

Moving the loop above results.clear() is the whole fix. The loop counter is also changed from int to size_t to match results.size() and drop the signed/unsigned comparison warning.

The pointers in results are owned by the explorer: they come from new ChValueSpecific<>(...) in the out() overloads and from bVal.new_clone() in out_array_pre() and out_ref(). Deleting them here is therefore correct, and no caller retains them across a search boundary. Both in-tree consumers were checked: demo_CH_archive.cpp reuses one explorer for several sequential searches but consumes each result set before starting the next search, and ChIrrGUI.cpp constructs a fresh explorer per call and per loop iteration, including on its recursive path, so each instance performs exactly one search.

Reported in #779, which also covers a separate dangling-pointer defect in the enum overload that is not addressed here.

ChObjectExplorer::ClearSearch() deletes the ChValue objects allocated by the
previous search, but the delete loop was placed after this->results.clear().
By the time the loop was reached, results.size() was already zero, so the loop
ran no iterations and deleted nothing.

ClearSearch() runs at the start of every search (via PrepareSearch) and again
from the destructor, so every ChValue ever allocated by out(), out_array_pre()
and out_ref() was leaked. A single FetchValues("*") over a container leaks one
ChValue per matched property, and the Irrlicht object tree in ChIrrGUI builds a
fresh explorer per node per frame, so the leak grows with runtime.

Moving the loop above results.clear() is the whole fix. The loop counter is
also changed from int to size_t to match results.size() and drop the
signed/unsigned comparison warning.

The pointers in results are owned by the explorer: they come from
new ChValueSpecific<>(...) in the out() overloads and from bVal.new_clone() in
out_array_pre() and out_ref(). Deleting them here is therefore correct, and no
caller retains them across a search boundary. Both in-tree consumers were
checked: demo_CH_archive.cpp reuses one explorer for several sequential
searches but consumes each result set before starting the next search, and
ChIrrGUI.cpp constructs a fresh explorer per call and per loop iteration,
including on its recursive path, so each instance performs exactly one search.

Reported in #779, which also covers a separate dangling-pointer defect in the
enum overload that is not addressed here.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant