Documentation / FAQ Request
This is not a bug report against Fast-DDS itself — this is a request to add a troubleshooting entry for a well-known Linux ecosystem issue that frequently affects Fast-DDS users, since Fast-DDS relies heavily on C++ exception handling.
We are submitting a documentation PR to eProsima/Fast-DDS-docs with the troubleshooting entry.
Problem Description
When libunwind is loaded into a process before libgcc_s.so.1, C++ exception handling breaks. The _Unwind_* symbols provided by libunwind shadow those from libgcc_s, but the two libraries use incompatible _Unwind_Context struct layouts. This causes segfaults or crashes whenever C++ exceptions are thrown or caught.
Because Fast-DDS makes extensive use of C++ exceptions, it is one of the most visible victims of this conflict — users see crashes originating in Fast-DDS exception handling code, even though the root cause is in the unwinder layer beneath it.
How It Manifests
- Segmentation faults during C++ exception handling (throw/catch)
- Crashes in
_Unwind_RaiseException, __cxa_throw, or related frames
- Intermittent or immediate crashes in Fast-DDS participant creation or discovery
Environment
- Architecture: x86_64 (the struct layout mismatch is architecture-specific)
- OS: Linux, particularly in Docker containers
- Common trigger: ROS 2 environments where GStreamer (or other multimedia/profiling packages) transitively pulls in
libunwind, which gets loaded before libgcc_s.so.1
Root Cause
glibc's pthread_exit (and pthread_cancel) implementation hardcodes dlopen("libgcc_s.so.1") to obtain _Unwind_* symbols for stack unwinding. However, if libunwind is already loaded in the process (e.g., as a transitive dependency), the dynamic linker resolves _Unwind_* symbols to libunwind's versions instead. The two libraries define _Unwind_Context with different struct layouts, so passing one library's context to the other's functions causes memory corruption and crashes.
This is a long-standing ecosystem issue, documented since at least 2004.
Workaround
Force libgcc_s.so.1 to be loaded first using LD_PRELOAD:
export LD_PRELOAD=/lib/x86_64-linux-gnu/libgcc_s.so.1
For Docker containers:
ENV LD_PRELOAD=/lib/x86_64-linux-gnu/libgcc_s.so.1
Upstream References
- Ubuntu Bug #1960005 — libunwind conflicts with libgcc_s unwinder
- LLVM #90041 — related unwinder symbol conflicts
- GCC/glibc patches from 2004 discussing the
dlopen("libgcc_s.so.1") hardcoding in pthread_cancel/pthread_exit
Documentation / FAQ Request
This is not a bug report against Fast-DDS itself — this is a request to add a troubleshooting entry for a well-known Linux ecosystem issue that frequently affects Fast-DDS users, since Fast-DDS relies heavily on C++ exception handling.
We are submitting a documentation PR to
eProsima/Fast-DDS-docswith the troubleshooting entry.Problem Description
When
libunwindis loaded into a process beforelibgcc_s.so.1, C++ exception handling breaks. The_Unwind_*symbols provided by libunwind shadow those from libgcc_s, but the two libraries use incompatible_Unwind_Contextstruct layouts. This causes segfaults or crashes whenever C++ exceptions are thrown or caught.Because Fast-DDS makes extensive use of C++ exceptions, it is one of the most visible victims of this conflict — users see crashes originating in Fast-DDS exception handling code, even though the root cause is in the unwinder layer beneath it.
How It Manifests
_Unwind_RaiseException,__cxa_throw, or related framesEnvironment
libunwind, which gets loaded beforelibgcc_s.so.1Root Cause
glibc's
pthread_exit(andpthread_cancel) implementation hardcodesdlopen("libgcc_s.so.1")to obtain_Unwind_*symbols for stack unwinding. However, iflibunwindis already loaded in the process (e.g., as a transitive dependency), the dynamic linker resolves_Unwind_*symbols to libunwind's versions instead. The two libraries define_Unwind_Contextwith different struct layouts, so passing one library's context to the other's functions causes memory corruption and crashes.This is a long-standing ecosystem issue, documented since at least 2004.
Workaround
Force
libgcc_s.so.1to be loaded first usingLD_PRELOAD:export LD_PRELOAD=/lib/x86_64-linux-gnu/libgcc_s.so.1For Docker containers:
ENV LD_PRELOAD=/lib/x86_64-linux-gnu/libgcc_s.so.1Upstream References
dlopen("libgcc_s.so.1")hardcoding inpthread_cancel/pthread_exit