Skip to content

Commit 10636bb

Browse files
committed
Fix segfault during shutdown caused by UnsharedNamespaceInitializer static destruction order
The simulation crashed with a segfault during program shutdown. The crash occurred in cEnvir::removeLifecycleListener(), called from the ~cISimulationLifecycleListener() destructor, which dereferences the envir returned by getEnvir(). Root cause: UnsharedNamespaceInitializer::singleton was a file-scope static object registered as a lifecycle listener via EXECUTE_ON_STARTUP. This added it to the static 'bootstrap' envir (StaticEnv), which is also a file-scope static (in csimulation.cc). During static destruction, C++ does not guarantee destruction order across translation units. If StaticEnv was destroyed before the singleton, the singleton's destructor called getEnvir() on an already- destroyed object, causing a use-after-free. Alternatives considered: - Having the listener destructor check getLifecycleListeners() before calling remove: doesn't help because the envir itself may already be destroyed. - Reordering setActiveSimulation(nullptr) and delete simulation in startup.cc: the ~cSimulation destructor panics if the simulation is still active, and moving deletion before deactivation caused a different crash. - Storing a back-pointer to the envir each listener was registered with: invasive API change for a problem specific to static-lifetime listeners. Chosen fix: change the singleton from a static object to a heap-allocated pointer that is intentionally leaked (never deleted). This matches the existing pattern used by OMNeT++'s own LocalLifecycleListener in csoftowner.cc, which is also registered via EXECUTE_ON_STARTUP and deliberately leaked. Since the listener is never destroyed, its destructor never runs, and the static destruction order problem is avoided entirely.
1 parent 1ba335e commit 10636bb

3 files changed

Lines changed: 4 additions & 4 deletions

File tree

src/inet/common/NetworkNamespaceContext.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ NetworkNamespaceContext::NetworkNamespaceContext(const char *name)
9696
#ifdef __linux__
9797
auto it = localNetworkNamespaces.find(name);
9898
if (it != localNetworkNamespaces.end()) {
99-
oldFd = UnsharedNamespaceInitializer::singleton.originalNetworkNamespaceFd;
99+
oldFd = UnsharedNamespaceInitializer::singleton->originalNetworkNamespaceFd;
100100
newFd = it->second;
101101
global = false;
102102
}

src/inet/common/UnsharedNamespaceInitializer.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,11 @@ namespace inet {
1717

1818
Register_GlobalConfigOption(CFGID_UNSHARE_NAMESPACES, "unshare-namespaces", CFG_BOOL, "false", "Unshares the user and network namespaces using the unshare() system call. The simulation continues running as the root user in the new user namespace. This allows creating new network namespaces and assign network resources without using sudo or setting capabilities for opp_run.");
1919

20-
UnsharedNamespaceInitializer UnsharedNamespaceInitializer::singleton;
20+
UnsharedNamespaceInitializer *UnsharedNamespaceInitializer::singleton = nullptr;
2121

2222
#ifdef __linux__
2323
#if OMNETPP_VERSION < 0x0700
24-
EXECUTE_ON_STARTUP(getEnvir()->addLifecycleListener(&UnsharedNamespaceInitializer::singleton));
24+
EXECUTE_ON_STARTUP(UnsharedNamespaceInitializer::singleton = new UnsharedNamespaceInitializer(); getEnvir()->addLifecycleListener(UnsharedNamespaceInitializer::singleton));
2525
#endif
2626
#endif
2727

src/inet/common/UnsharedNamespaceInitializer.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ namespace inet {
2121
class UnsharedNamespaceInitializer : public omnetpp::cISimulationLifecycleListener
2222
{
2323
public:
24-
static UnsharedNamespaceInitializer singleton;
24+
static UnsharedNamespaceInitializer *singleton;
2525

2626
int originalNetworkNamespaceFd = -1;
2727

0 commit comments

Comments
 (0)