Closed smcv closed 1 month ago
A theoretical crash from source code inspection that I was trying to reproduce here (but I couldn't quite work out how to do so) is:
pw_context_new()
calls pw_data_loop_new()
which also creates a thread, running do_loop()
in Pipewire's src/pipewire/data-loop.c
. This is also running Pipewire code, so it will similarly crash if the Pipewire library is unloaded.
The solution is to make sure that the PwContext
was destroyed with pw_context_destroy()
before the Pipewire library can be unloaded.
In SDL terms, the solution is to make sure that if we might have started hotplug_loop_init()
, then we must call hotplug_loop_destroy()
before the Pipewire library can be unloaded.
I can reproduce a different crash (not the same as the first one here, but possibly the same as the one in https://github.com/libsdl-org/SDL/issues/10787#issuecomment-2341871229) by forcing a failure immediately after pw_context_new()
:
diff --git a/src/audio/pipewire/SDL_pipewire.c b/src/audio/pipewire/SDL_pipewire.c
index c258ed80d..89c5ab7e0 100644
--- a/src/audio/pipewire/SDL_pipewire.c
+++ b/src/audio/pipewire/SDL_pipewire.c
@@ -718,7 +718,7 @@ static int hotplug_loop_init(void)
}
hotplug_context = PIPEWIRE_pw_context_new(PIPEWIRE_pw_thread_loop_get_loop(hotplug_loop), NULL, 0);
- if (!hotplug_context) {
+ if (1 || !hotplug_context) {
return SDL_SetError("Pipewire: Failed to create hotplug detection context (%i)", errno);
}
Unfortunately I can't tell where this crash is:
Thread 2 "dota2" received signal SIGSEGV, Segmentation fault.
[Switching to Thread 11557.11644]
0x00007fffb094d030 in ?? ()
(gdb) bt
#0 0x00007fffb094d030 in ?? ()
#1 0x0000000000000000 in ?? ()
but it's similarly happening while the main thread is unloading modules:
Thread 1 (Thread 11557.11557 "dota2"):
#0 0x00007ffff7fc91cb in _dl_close_worker (map=<optimized out>, map@entry=0x5555574b62a0, force=force@entry=false) at dl-close.c:741
#1 0x00007ffff7fc967b in _dl_close (_map=0x5555574b62a0) at dl-close.c:793
#2 0x00007ffff7fc8523 in __GI__dl_catch_exception (exception=exception@entry=0x7fffffff5dd0, operate=0x7ffff7fc9640 <_dl_close>, args=0x5555574b62a0) at dl-catch.c:241
#3 0x00007ffff7fc8679 in _dl_catch_error (objname=0x7fffffff5e38, errstring=0x7fffffff5e40, mallocedp=0x7fffffff5e37, operate=<optimized out>, args=<optimized out>) at dl-catch.c:260
#4 0x00007ffff7df59f3 in _dlerror_run (operate=<optimized out>, args=<optimized out>) at dlerror.c:138
#5 0x00007ffff7df5736 in __dlclose (handle=<optimized out>) at dlclose.c:31
#6 0x00007fffa408b229 in unref_plugin (plugin=0x55555741b020) at ../src/pipewire/pipewire.c:171
#7 0x00007fffa408b445 in unref_plugin (plugin=<optimized out>) at ../src/pipewire/pipewire.c:167
#8 unref_handle (handle=0x5555574b67c0) at ../src/pipewire/pipewire.c:212
#9 0x00007fffa408c07b in unref_handle (handle=<optimized out>) at ../src/pipewire/pipewire.c:206
#10 pw_deinit () at ../src/pipewire/pipewire.c:702
#11 0x00007ffff0a44373 in deinit_pipewire_library () from target:/home/desktop/tmp/libSDL3.so.0
#12 0x00007ffff0a4660c in PIPEWIRE_Deinitialize () from target:/home/desktop/tmp/libSDL3.so.0
#13 0x00007ffff0a46658 in PipewireInitialize () from target:/home/desktop/tmp/libSDL3.so.0
#14 0x00007ffff0a46717 in PIPEWIRE_PREFERRED_Init () from target:/home/desktop/tmp/libSDL3.so.0
#15 0x00007ffff083a536 in SDL_InitAudio () from target:/home/desktop/tmp/libSDL3.so.0
#16 0x00007ffff083270a in SDL_InitSubSystem_REAL () from target:/home/desktop/tmp/libSDL3.so.0
#17 0x00007fff8cc7c9de in ?? () from target:/home/desktop/SteamLibrary/steamapps/common/dota 2 beta/game/bin/linuxsteamrt64/libsoundsystem.so
#18 0x0000000000000070 in ?? ()
#19 0x0000000000000000 in ?? ()
I suspect that the reason I can't get a good backtrace for this is that 0x00007fffb094d030 is an address that was, until recently, occupied by a Pipewire plugin that has now been unloaded.
Thread 2 "dota2" received signal SIGSEGV, Segmentation fault. [Switching to Thread 11557.11644] 0x00007fffb094d030 in ?? () (gdb) bt #0 0x00007fffb094d030 in ?? () #1 0x0000000000000000 in ?? ()
A follow-up for this: in Pipewire ≥ 1.0.1, this thread would have been labelled pw-data-loop
, making it easier to diagnose this crash as Pipewire-related. Today's beta releases of Steam Linux Runtime 2.0 and 3.0 have a backport of that change into their older Pipewire versions.
While investigating a somewhat common crash seen in automated crash reports, I noticed a possible failure mode in SDL. If
hotplug_loop_init()
gets part way through initialization, then fails, there is a crash when libpipewire is unloaded.(All diffs here are vs. SDL3 fa2c9c46 because that's the version currently used in Dota 2, which I'm using as a convenient example of a SDL3 game to test against; and I've also cherry-picked 0eff6361 to give threads better names. I'm using
SDL3_DYNAMIC_API
to force my patched SDL3 to be used.)If I patch SDL to force
hotplug_loop_init()
to fail right at the end:then I see this crash:
Analysis: after failing
hotplug_loop_init()
, the main thread callsPIPEWIRE_Deinitialize()
, which unloads libpipewire and its plugins. However,hotplug_loop_init()
already started thehotplug_loop
thread, which is running libpipewire code. Cutting the floor out from under it is unlikely to go well.e21f70c5 would make it impossible to reproduce this bug in Dota 2 because the Steam Linux Runtime 3.0 'sniper' version of libpipewire is older than 1.0.0, but I think that's only a workaround rather than a solution.