Skip to content

fix: prevent segfault when using MuJoCo viewer Reload button#120

Open
SHABRAWii wants to merge 2 commits into
unitreerobotics:mainfrom
SHABRAWii:fix/reload-segfault
Open

fix: prevent segfault when using MuJoCo viewer Reload button#120
SHABRAWii wants to merge 2 commits into
unitreerobotics:mainfrom
SHABRAWii:fix/reload-segfault

Conversation

@SHABRAWii
Copy link
Copy Markdown

Two race conditions crash the simulator on Reload:

  1. PhysicsLoop calls mj_deleteData/mj_deleteModel while the bridge threads are still reading from those pointers. Fix: add two std::atomic globals (g_bridge_pause_request / g_bridge_paused) as a pause/resume handshake. PhysicsLoop waits for the bridge to stop before freeing memory. UnitreeSdk2BridgeThread destroys and recreates the bridge on each reload instead of holding stale pointers forever.

  2. RecurrentThread::~RecurrentThread() destroys mFunc (the run() lambda) before sending pthread_cancel, and never sets mQuit. If the thread wakes between those two steps it calls the destroyed std::function and hits std::terminate(). Fix: replace RecurrentThread with a std::thread owned by RobotBridge, controlled by a std::atomic stop_flag_. pre_destroy() sets the flag and joins the thread — guaranteed clean exit before any destructor runs.

SHABRAWii added 2 commits May 22, 2026 04:32
Two race conditions crash the simulator on Reload:

1. PhysicsLoop calls mj_deleteData/mj_deleteModel while the bridge
   threads are still reading from those pointers. Fix: add two
   std::atomic<bool> globals (g_bridge_pause_request / g_bridge_paused)
   as a pause/resume handshake. PhysicsLoop waits for the bridge to stop
   before freeing memory. UnitreeSdk2BridgeThread destroys and recreates
   the bridge on each reload instead of holding stale pointers forever.

2. RecurrentThread::~RecurrentThread() destroys mFunc (the run() lambda)
   before sending pthread_cancel, and never sets mQuit. If the thread
   wakes between those two steps it calls the destroyed std::function and
   hits std::terminate(). Fix: replace RecurrentThread with a std::thread
   owned by RobotBridge, controlled by a std::atomic<bool> stop_flag_.
   pre_destroy() sets the flag and joins the thread — guaranteed clean
   exit before any destructor runs.
…mbers

The private section still declared the old `thread_` after the method
bodies were updated to use `stop_flag_` and `run_thread_`, leaving the
class in a non-compiling state.
@SHABRAWii SHABRAWii force-pushed the fix/reload-segfault branch from bf7fbf3 to c4870a5 Compare May 24, 2026 16:50
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