|
FhSim
3.1.0
Marine systems simulation
|
| ID | 0041 |
| Class | ARCHITECTURE |
| Severity | 2 |
| Status | blocked |
| Models | Auv/Vehicle, Auv/Echosounder |
| Found | 2026-09-23 |
| Decision needed | Whether FhSim core should gain a RenderRelease hook, or whether every SimObject is expected to guard its own destructor. |
The visualisation interface in fhsim/include/fhsim/simobject/SimObjectInclude.h:303-317 is exactly two virtuals:
There is no counterpart to RenderInit, so the only place a SimObject can release the scene nodes and movable objects it created is its destructor. That destructor runs too late. Adding the obvious release to Auv::~Auv and running the AUV survey scenario under FhVis segfaults on the way out:
The null vtable entry is the Ogre::SceneManager the SimObject cached in RenderInit: the visualisation observer, and with it the Ogre root, is destroyed before ModelStructure destroys the SimObjects, so every scene pointer a SimObject holds is dangling by the time its destructor runs.
fhsim_environment/src/environment/visual/ScalarVolume.cpp:101-119 releases its node and its ManualObject the same unguarded way, and is reachable from the same teardown, so the same crash is latent there.
Any SimObject that creates Ogre resources and then frees them the way the rest of the code base does crashes the host at shutdown — after a successful run, so the simulation results are not affected, but the process exits on a signal and any exit code a script reads is meaningless. The alternative, not freeing anything, leaks the geometry for the lifetime of the process, which is harmless for a one-shot run and is not harmless for a host that builds and tears down several models.
Auv and SensorEchosounder work around it with a SceneIsStillAlive() guard (src/auv/Auv.cpp:31-50, src/auv/SensorEchosounder.cpp:57-79) that asks Ogre::Root::getSingletonPtr() whether it still has the "main" scene manager and does nothing when it does not. That is correct but it is a workaround every library has to rediscover, and it silently becomes a leak rather than a release.
RenderRelease() virtual to the SimObject interface, called by ModelStructure before the visualisation observer drops the Ogre root, with an empty default so that no existing model has to change. This is the fix that makes the guard unnecessary.ScalarVolume too.The choice belongs to the FhSim core owner, which is why this is blocked rather than ready.
Run FhVis on a scenario containing an Auv with the guard removed, with <Visualization/> as an observer, and check the exit status. It is 139 with the release unguarded and 0 with it guarded. A core test would assert that RenderRelease is called while Ogre::Root::getSingletonPtr() is still non-null.
Leaving it as it stands risks nothing in the simulation and costs a workaround in every visualised SimObject. Changing the teardown order in the host is the riskier of the two fixes; adding a hook is additive.