While adding OP/DC digital-node support to NgspiceTclBridge, I found a memory leak in the shared-library event query implementation.
The attached patch is against commit a80f6e3e95d51534905b1f23410a951802666656 (master, ngspice-47) .
In src/xspice/evt/evtshared.c, delete_ret() frees the individual records in return_all->evt_dect and their values, followed by return_all, but does not free the evt_dect pointer array itself.
Repeated calls to ngGet_Evt_NodeInfo() therefore leak one pointer array per replaced query result. This becomes relevant when querying digital-node states repeatedly during DC sweeps or repeated simulations.
There is also a lifecycle issue: the final cached query result remains allocated when its circuit is destroyed.
The proposed patch:
return_all->evt_dect in delete_ret().EVTdest() in shared-library builds.EVTshareddata().To exercise the affected path, run a mixed-signal circuit containing an ADC bridge, then repeatedly call ngGet_Evt_NodeInfo() for one of its digital nodes. Each query replaces the previous cached result; the pointer array from that previous result is currently left allocated.
The patch was built and tested on Linux with the shared library. Integration tests covering OP/DC digital-node queries, repeated runs, and circuit replacement passed.
No public API or event-value changes are intended. Could you please review the cleanup and confirm whether EVTdest() is the appropriate place to release the final cached result?
Needs reproducible test case.
Test case:
./event_query_leak /path/to/digital.cm 1000
./event_query_leak /path/to/digital.cm 1000000
Results (measured peak RSS on Linux):
Now it begins to look like a decent bug report. The leak is clear, but the proposed fix contains unnecessary stuff: ckt->evt is unconditionally valid and the returned memory should not be freed in evtdest.c, as the code implicitly (doc and code) transfers ownership to the caller.
Missing is any mention of a serious documentation gap: the function is a trap for anyone who does not read the source, as each call invalidates previous results. Fix in progress.