PipeWire crashes in pw_stream_queue_buffer after stream state changes to paused
In gnome-remote-desktop (g-r-d), PipeWire is used in remote desktop sessions to handle screencast buffers.
When connecting to g-r-d using RDP or VNC and then changing the display resolution of the recorded (physical) monitor, mutter appears to pause or stop the PipeWire stream.
The buffer types handled via PipeWire are MemFds or DmaBufs.
When MemFds are used, g-r-d copies the buffer content in the PipeWire real time data thread (pw_stream_dequeue_buffer, copy, pw_stream_queue_buffer are all handled in the same process()
callback here (same thread)).
When DmaBufs are used, g-r-d only dequeues the PipeWire buffer in the PipeWire real time data thread, pushes a task to a separate (EGL) thread, where the dma-buf is downloaded, and then queues the related PipeWire buffer again using pw_stream_queue_buffer
(the queue operation happens in the EGL thread here after handling the dma-buf).
When the resolution of the recorded screen changes, mutter pauses or stops the PipeWire stream on its side (I don't know mutters exact internals here).
In g-r-d, the PipeWire stream state changes here from the streaming
to the paused
state.
When in that exact moment a PipeWire buffer is handled in the EGL thread, i.e. the PipeWire buffer with type SPA_DATA_DmaBuf
is already dequeued and in the process of being downloaded, then g-r-d will crash (with SIGSEGV) in pw_stream_queue_buffer
, when queuing the PipeWire buffer again, after the dma-buf image has been downloaded.
Stacktrace:
#0 pw_stream_queue_buffer (stream=0x55982a425f90, buffer=0x55982a426390) at ../pipewire/src/pipewire/stream.c:2300
2300 ATOMIC_DEC(b->busy->count);
[Current thread is 1 (Thread 0x7f100ffff6c0 (LWP 2663))]
(gdb) bt full
#0 pw_stream_queue_buffer (stream=0x55982a425f90, buffer=0x55982a426390) at ../pipewire/src/pipewire/stream.c:2300
impl = 0x55982a425f90
b = 0x55982a426390
res = <optimized out>
__func__ = "pw_stream_queue_buffer"
#1 0x000055982985dea5 in download_in_impl (data=0x559829c9ed30, user_data=0x7f0fd80060e0) at ../gnome-remote-desktop/src/grd-egl-thread.c:844
egl_thread = 0x559829c9ed30
task = 0x7f0fd80060e0
egl_image = 0x7f1004125af0
success = 1
buffer_size = 18662400
tex = 158
fbo = 158
#2 0x00005598298614ba in grd_thread_dispatch_in_impl (egl_thread=0x559829c9ed30) at ../gnome-remote-desktop/src/grd-egl-thread.c:429
task = 0x7f0fd80060e0
task_source = <optimized out>
egl_thread = 0x559829c9ed30
__func__ = "egl_task_source_dispatch"
#3 egl_task_source_dispatch (source=<optimized out>, callback=<optimized out>, user_data=<optimized out>) at ../gnome-remote-desktop/src/grd-egl-thread.c:474
task_source = <optimized out>
egl_thread = 0x559829c9ed30
__func__ = "egl_task_source_dispatch"
#4 0x00007f10396c20eb in g_main_context_dispatch () at /usr/lib/libglib-2.0.so.0
#5 0x00007f103971e059 in () at /usr/lib/libglib-2.0.so.0
#6 0x00007f10396c182f in g_main_loop_run () at /usr/lib/libglib-2.0.so.0
#7 0x0000559829861277 in grd_egl_thread_func (user_data=0x559829c9ed30) at ../gnome-remote-desktop/src/grd-egl-thread.c:520
egl_thread = 0x559829c9ed30
error = 0x0
#8 0x00007f10396f2485 in () at /usr/lib/libglib-2.0.so.0
#9 0x00007f10388e6bb5 in start_thread (arg=<optimized out>) at pthread_create.c:444
ret = <optimized out>
pd = <optimized out>
unwind_buf = {cancel_jmp_buf = {{jmp_buf = {139707645061360, 3958000084279794311, -1720, 11, 140728396040928, 139706956247040, -3977316305627342201, -3977288665979774329}, mask_was_saved = 0}}, priv = {pad = {0x0, 0x0, 0x0, 0x0}, data = {prev = 0x0, cleanup = 0x0, canceltype = 0}}}
not_first_call = <optimized out>
#10 0x00007f1038968d90 in clone3 () at ../sysdeps/unix/sysv/linux/x86_64/clone3.S:81
(gdb) frame 0
#0 pw_stream_queue_buffer (stream=0x55982a425f90, buffer=0x55982a426390) at ../pipewire/src/pipewire/stream.c:2300
2300 ATOMIC_DEC(b->busy->count);
(gdb) print b
$1 = (struct buffer *) 0x55982a426390
(gdb) print *b
$2 = {this = {buffer = 0x559829c971a0, user_data = 0x0, size = 0, requested = 0}, id = 0, flags = 4, busy = 0x7f100c28c000}
(gdb) print b->busy
$3 = (struct spa_meta_busy *) 0x7f100c28c000
(gdb) print *b->busy
Cannot access memory at address 0x7f100c28c000
(gdb)
PipeWire version: 0.3.65-6
Distro: Archlinux