Crash on exit: double free or corruption #7

Open
opened 2026-09-27 03:40:57 +00:00 by backspace119 · 1 comment
Owner

Viewer sometimes aborts at shutdown with 'double free or corruption (out)' and hangs while dumping core. Suspected boost::wave/spirit static destructors (LSL preprocessor). Binaries are now archived per launch (~/.cache/alchemy-bins) so the next occurrence can be symbolized.

Viewer sometimes aborts at shutdown with 'double free or corruption (out)' and hangs while dumping core. Suspected boost::wave/spirit static destructors (LSL preprocessor). Binaries are now archived per launch (~/.cache/alchemy-bins) so the next occurrence can be symbolized.
Author
Owner

Symbolized occurrence (2026-09-27, build with GL-B8, SIGSEGV exit 139 at logout). It confirms the suspicion:

libc exit() -> static destructors
  boost::shared_ptr<spirit::classic::impl::object_with_id_base_supply<unsigned long>>::~shared_ptr
  sp_counted_base::release -> checked_delete
  object_with_id_base_supply<unsigned long>::~object_with_id_base_supply   (object_with_id.ipp:33)
  boost::mutex::~mutex -> pthread_mutex_destroy   <- SIGSEGV

object_with_id_base_supply is Boost.Spirit Classic's grammar/rule ID pool, a function-local static shared_ptr shared by every grammar instance. The only Spirit/Wave user in the viewer is the LSL preprocessor (fslslpreproc / boost::wave). At exit the pool is released during static destruction after (or while) the objects that reference it are torn down, so its mutex is already gone. That's a static-destruction-order problem, and the same mutex family as the old Ctrl+S deadlock (#8).

Fix options:

  1. Skip static destructors after an orderly shutdown: once LLAppViewer::cleanup() has finished (settings saved, logs flushed, threads joined), end the process with _exit(0) / std::quick_exit. It removes this whole class of exit crashes (Boost.Spirit, other third-party statics), and the OS reclaims memory anyway. Needs a check that nothing important runs in static dtors (log file close: flush explicitly first).
  2. Scope fix: make the preprocessor's Wave context and grammar objects die before main returns (explicit teardown in LLAppViewer::cleanup), so the ID pool isn't released during static destruction. More surgical, but other library statics can still bite.

Recommend (1), with (2) if a problem shows up.

**Symbolized occurrence (2026-09-27, build with GL-B8, SIGSEGV exit 139 at logout).** It confirms the suspicion: ``` libc exit() -> static destructors boost::shared_ptr<spirit::classic::impl::object_with_id_base_supply<unsigned long>>::~shared_ptr sp_counted_base::release -> checked_delete object_with_id_base_supply<unsigned long>::~object_with_id_base_supply (object_with_id.ipp:33) boost::mutex::~mutex -> pthread_mutex_destroy <- SIGSEGV ``` `object_with_id_base_supply` is Boost.Spirit Classic's grammar/rule ID pool, a function-local static `shared_ptr` shared by every grammar instance. The only Spirit/Wave user in the viewer is the LSL preprocessor (fslslpreproc / boost::wave). At exit the pool is released during static destruction after (or while) the objects that reference it are torn down, so its mutex is already gone. That's a static-destruction-order problem, and the same mutex family as the old Ctrl+S deadlock (#8). **Fix options:** 1. **Skip static destructors after an orderly shutdown:** once `LLAppViewer::cleanup()` has finished (settings saved, logs flushed, threads joined), end the process with `_exit(0)` / `std::quick_exit`. It removes this whole class of exit crashes (Boost.Spirit, other third-party statics), and the OS reclaims memory anyway. Needs a check that nothing important runs in static dtors (log file close: flush explicitly first). 2. **Scope fix:** make the preprocessor's Wave context and grammar objects die before `main` returns (explicit teardown in LLAppViewer::cleanup), so the ID pool isn't released during static destruction. More surgical, but other library statics can still bite. Recommend (1), with (2) if a problem shows up.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
backspace119/Slipstream#7
No description provided.