Open zannads opened 6 months ago
My suggestion and the solution I applied in my local copy is to free the localadjlists in closehyd
.
As the function openQ checks for the presence of an adjlists and creates one if none is present, the only drawback would be that of a double unnecessary free of adjlists (but I guess it is not too much of problem since it is already done within localadjlists in the creation of the sparse matrix). This means that the same call to freeadjlists should also be done in closequal
.
Alternatively, a more robust approach would consist of invalidating (and freeing) the adjencylists every time a new node or link is added to the network. This however, requires additional checks for the existence of the variable net->Adjlists
every time is used. This approach is also more robust to other possible misuse of the library, e.g., adding nodes between a call to runH and nextH.
I will create a Pull request to solve this issue, where we can further discuss which approach to take (maybe both?).
Good catch and nice analysis. I agree with your fix. The only (small) downside I see is that when a user runs a water quality analysis after running hydraulics the adjacency lists have to be re-created once again (which won't happen if quality is run concurrently with hydraulics).
There is an error in the memory management of the variable
network->Adjlist
: the list is allocated but not freed. This bug appeared in my code, where I use EPANET only for the hydraulic simulations of the network in an optimization problem. As the possible decision variables in the optimization problem (Anytown) include tank and pipe installation, I use the ability of the library to modify the network structure dynamically to respond to the changes made by the optimization algorithm. The network nodes adjacency list is allocated during openH, but it is not freed in closeH. If we evaluate a new solution with a different number of nodes (e.g., we add a tank), the for loop in the function freeadjlists is using the wrong number of nodes, i.e., the new one (with the new tank) instead of the old one that was used to create the adjlist. The functionfreeadjlists
and its counterpartsbuildadjlists
andlocaladjlists
use the variableNnodes
to manage the array of adjlists, which has size Nnodes+1. With the current version, these variables are only freed when closing a project (EN_close -> free data -> freeadjlists) or when a new hydraulic simulation is performed and the old one is deleted before starting a new simulation (EN_openH -> openhyd -> create sparse -> localadjlists -> freeadjlists). As freeadjlists iterates over the array of adjency lists using the current number of Nodes, if the number of nodes has changed since when the current adjlists have been created, it results in a memory leak (if the number of nodes is now less than before, then the last elements are never freed) of in a possible double free or some segmentation fault (if the number of nodes is now greater than before, then the for loop goes out of the boundaries of the netadjlists). This may also happen if the water quality simulations are run, as I don't see the functionfreeadjlists
being called anywhere. See the example below.The segmentation fault/double-free error is not easily replicable, as the compilers optimize the memory allocation and often when going out of boundary you end up with a zero value. However, the memory leak always happens if you keep removing nodes. I try to provide here an executable to show this error.
The same results are obtained by uncommenting the lines that call the quality solver.