Skip to content

PipeWire backend: process() can run before the local port exists — null port token, segfault in release builds - #249

Closed
ryanatseolaudio wants to merge 1 commit into
celtera:masterfrom
ryanatseolaudio:bimac-patches
Closed

ryanatseolaudio wants to merge 1 commit into
celtera:masterfrom
ryanatseolaudio:bimac-patches

Conversation

@ryanatseolaudio

Copy link
Copy Markdown
Contributor

Environment: libremidi @ 8b12bce · libpipewire 1.0.5 · Ubuntu 24.04.4 LTS

What happens:

midi_in_pipewire::process() (and the out/UMP variants) can run while this->port is not a valid token:

  1. Open sequence: open() calls create_filter(), which calls flt->start() (helpers.hpp:142) — from this moment the
    PipeWire data loop may fire process() — and only then does create_local_port() (midi_in.hpp:55) set this->port. A
    process() in that window calls pw.filter_dequeue_buffer(this->port.opaque) with port.opaque == nullptr.
  2. Close sequence: destroy_filter() invalidates the port while a queued/running process() can still fire.

Symptoms:

  • Debug: Assertion 'this->port.valid()' failed at backends/pipewire/midi_in.hpp:95 — abort at startup (open path) and
    at shutdown (close path). The shutdown variant is intermittent (~1-in-3 on our machine).
  • Release (asserts compiled out): segfault on the null token.

Repro: open/close PipeWire midi_in/midi_out ports repeatedly (e.g. an app that creates and destroys ports at
startup); the open-path race is timing-dependent and appeared after repeated cycles.

Proposed fix:

Early-return in all four process() implementations (pipewire in/out, pipewire_ump in/out) when the filter or port
token is invalid:

  if (!flt || !port.valid())
    return;            // out variants: return 1;  (report idle)

We ran some initial testing on this guard and it seems to eliminate both the startup and shutdown aborts in
debug and release.

The filter can start before the local port exists (open sequence) or
run after the port was removed (close sequence). With no valid port
token there is no buffer to process; skip instead of dereferencing a
null token. With asserts compiled out (release build) the old code
segfaulted (pw.filter_dequeue_buffer on a null token).
@jcelerier

Copy link
Copy Markdown
Member

thanks for the PR ! checking that

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.

2 participants