Hacktoberfest 2026:メンテナが10月に向けて印を付けた、オープンで初心者向けの issue。 Hacktoberfest の issue を見る

sniper: bundled PipeWire 0.3.65 segfaults/deadlocks games on Bluetooth profile switch (fixed upstream in 1.2.2)

オープン
#853 コメント 6 件 リアクション 0 件 担当者 0 名 GitHub で見る

まだ誰も着手していません。

評価

難易度
4/5
見積もり時間
3〜5日
初心者へのやさしさ
55/100
issue の種類
バグ
明瞭さ
明確に書かれている
活発さ
活発

調査の方向性

steamrt README のバックポートポリシーと、sniper_platform_3.0.20260805.254768/files/manifest.dpkg に含まれるパッケージバージョンから始めます。PipeWire の修正 628f292fb877440f9531cc452f81b59ac3471637 と 0d7c20760e56fc60db13f7d972baed4bc0760767 を確認し、その後 runtime のパッケージ更新プロセスを追跡します。完了条件は、含まれる PipeWire が 1.2.2 の修正を含みつつ安定版 SONAME を維持し、Bluetooth profile-switch の再現でクラッシュやデッドロックが発生しなくなることです。

索引モデルが issue の本文から書いたものです。

説明

Need Retest

Summary

The sniper runtime bundles pipewire 0.3.65-3+deb12u1~steamrt3.3+bsrt3.1 (upstream 0.3.65, released 2023-01-24). That version contains a known data race on SPA_IO_Buffers between the main thread and the pw-data-loop RT thread during port/format renegotiation, fixed upstream in PipeWire 1.2.2 (2024-07-29).

On a host with a modern PipeWire daemon, a Bluetooth headset switching profile (A2DP 48 kHz stereo <-> HSP/HFP 16 kHz mono) forces a mid-stream format renegotiation. The bundled 0.3.65 client then either SIGSEGVs in libspa-audioconvert.so or deadlocks the game.

In CS2 this reproduces on demand: with the headset connected, open Settings -> Audio and click the audio device selector dropdown. Enumerating devices re-creates the streams and drives the renegotiation straight into the racy window.

Observed with Counter-Strike 2, but this is a runtime-level defect and should affect any sniper game using audio with a Bluetooth headset.

Environment

Component Version
OS Fedora 44
Kernel 7.1.8-200.fc44.x86_64
CPU / GPU Ryzen 9 5900X / Radeon RX 6700 XT (Mesa 26.1.7)
Host PipeWire 1.6.8
Host WirePlumber 0.5.14
Host BlueZ 5.87
sniper 3.0.20260805.254768, pressure-vessel 0.20260805.0
Bundled PipeWire 0.3.65-3+deb12u1~steamrt3.3+bsrt3.1

From sniper_platform_3.0.20260805.254768/files/manifest.dpkg:

libpipewire-0.3-0:amd64       0.3.65-3+deb12u1~steamrt3.3+bsrt3.1
libpipewire-0.3-modules:amd64 0.3.65-3+deb12u1~steamrt3.3+bsrt3.1
libspa-0.2-modules:amd64      0.3.65-3+deb12u1~steamrt3.3+bsrt3.1
pipewire-bin                  0.3.65-3+deb12u1~steamrt3.3+bsrt3.1

The host daemon flags the client as outdated on every stream creation:

pipewire[2300]: mod.client-node: detected old client version 4

Failure mode 1: SIGSEGV in libspa-audioconvert

kernel: pw-data-loop[1044288]: segfault at 21 ip 00007fdd599bba71 sp 00007fdd2c3fa270 \
  error 4 in libspa-audioconvert.so[31a71,7fdd5999a000+3f000]
systemd-coredump: Process 1044176 (cs2) of user 1000 dumped core.
  #0  0x00007fdd599bba71 n/a (/usr/lib/x86_64-linux-gnu/spa-0.2/audioconvert/libspa-audioconvert.so + 0x31a71)

Note the path /usr/lib/x86_64-linux-gnu/...: inside the pressure-vessel container, i.e. the runtime's bundled SPA plugin, not the host's /usr/lib64/.

objdump -d of the bundled libspa-audioconvert.so at the faulting offset:

31a54: cmp    %r15d,0x463c(%r12)   ; loop bound (port->blocks)
31a5e: mov    0x18(%r14),%rsi
31a65: lea    (%rax,%rax,4),%rdx   ; i * 5
31a69: mov    0x10(%rsi),%rax      ; -> datas array base
31a6d: lea    (%rax,%rdx,8),%rbx   ; &datas[i], stride 40 == sizeof(struct spa_data)
31a71: mov    0x20(%rbx),%rax      ; <-- FAULTS reading spa_data.chunk
31a75: movl   $0x0,(%rax)          ; chunk->offset = 0
31a7f: movl   $0x0,0x4(%rax)       ; chunk->size = 0

This is impl_node_process() in spa/plugins/audioconvert/audioconvert.c:

for (j = 0; j < port->blocks; j++) {
    bd = &buf->buf->datas[j];
    bd->chunk->offset = 0;
    bd->chunk->size = 0;

Fault address 0x21 with error 4 (userspace read of an unmapped page): the datas array base resolved to 1, i.e. a stale/freed buffer touched during renegotiation.

Failure mode 2: deadlock (same trigger)

On a subsequent launch the game hangs instead of crashing:

1044793 cs2          [S] futex_do_wait
1044924 pw-data-loop [S] ep_poll
1044926 pw-data-loop [S] ep_poll
1044930 pw-data-loop [S] ep_poll

Three pw-data-loop threads in a single client, consistent with repeated stream re-creation without teardown. Server side:

pipewire-pulse: mod.protocol-pulse: [] timeout on stream ... channel:0
... channels 0-7 all time out

This also wedges the host audio graph: host-side wpctl status hangs, and the desktop volume applet shows two simultaneously-selected default sinks until wireplumber/pipewire are restarted.

Trigger evidence

kernel: Bluetooth: hci0: SCO packet for unknown connection handle 257
bluetoothd: btd_service_connect() a2dp-source profile connect failed for XX:XX:XX:XX:XX:XX: Device or resource busy
wireplumber: <WpSiStandardLink> link failed: item deactivated before format was set

At crash time the card was stuck in the voice profile, with A2DP not offered at all:

Active Profile: headset-head-unit
  off                    : Off
  headset-head-unit-cvsd : Headset Head Unit (HSP/HFP, codec CVSD)
  headset-head-unit      : Headset Head Unit (HSP/HFP, codec MSBC)

Upstream fix

Upstream issue: https://gitlab.freedesktop.org/pipewire/pipewire/-/work_items/4094 (closed 2024-08-01). Different surface trigger (EasyEffects creating a new output stream), same underlying race.

The defect is not a missing null check at the crash site. It is a race on port->io / SPA_IO_Buffers between the main thread performing format renegotiation and the RT data loop running impl_node_process(). Fix commits, all dated 2024-07-29:

Commit First release Subject
628f292fb877440f9531cc452f81b59ac3471637 1.2.2 audioconvert: set IO_Buffers only when buffers are negotiated
0d7c20760e56fc60db13f7d972baed4bc0760767 1.2.2 impl-port: improve IO_Buffers management on ports
61dcd8dedec3c56375e333113156ec7fbd0cd372 1.3.81 / 1.4.0 audioconvert: set IO_Buffers only when buffers are negotiated (mainline)

The fix routes port->io assignment through the RT data loop, and clears SPA_IO_Buffers on SPA_PARAM_Format change before the port leaves the data-thread schedule, closing exactly the window an A2DP <-> HFP switch hits.

Verified by ancestry check against the upstream repo:

$ git merge-base --is-ancestor 628f292fb 0.3.65   # -> false (0.3.65 predates the fix)
$ git merge-base --is-ancestor 61dcd8ded 1.6.8    # -> true

0.3.65 is dated 2023-01-24, roughly 18 months before the fix landed.

Steps to reproduce

Deterministic path, via CS2's in-game device enumeration:

  1. Host running a modern PipeWire (1.2.2+) and WirePlumber, with bluetooth.autoswitch-to-headset-profile at its default true.
  2. Pair a Bluetooth headset exposing both A2DP and HSP/HFP, and connect it.
  3. Launch CS2 (sniper runtime).
  4. Open Settings -> Audio and click the audio device selector dropdown.
  5. The game segfaults in libspa-audioconvert.so, or deadlocks with orphaned pw-data-loop threads.

Opening that dropdown makes the game enumerate and open the available audio devices, which tears down and re-creates streams and drives the port/format renegotiation into the racy window. This is consistent with the three orphaned pw-data-loop threads observed in failure mode 2: repeated stream re-creation without teardown.

The same crash also occurs without touching the menu, whenever the headset microphone is acquired and the profile autoswitches A2DP -> HSP/HFP mid-stream. The dropdown is simply the reliable way to trigger it on demand.

Workaround

Prevent the renegotiation entirely by disabling profile autoswitching on the host:

wpctl settings --save bluetooth.autoswitch-to-headset-profile false

Then reconnect the headset so it returns to a2dp-sink. This costs the headset microphone, since HFP is what was disabled, so it is not viable for players who need headset voice chat.

Request

Backport a current PipeWire into sniper. The steamrt README's backporting policy already names PipeWire as suitable for this (stable SONAME libpipewire-0.3.so.0), and recent sniper releases have carried updates for SDL, Vulkan-Loader, nss and others while PipeWire has stayed at the 0.3.65 baseline.

Possibly related, never root-caused: https://github.com/ValveSoftware/csgo-osx-linux/issues/3349 ("Game Freeze when bluetooth headset is connected", closed 2023), which matches failure mode 2 and was closed after the reporter removed PipeWire entirely.

主要言語
Shell
スター
1.5k
フォーク
98
PR マージ指標
30日以内にマージされた PR はありません

環境構築

このプロジェクトには開発コンテナ、Dockerfile、コントリビューションガイドがありません。まず README を読み、一般的な手順ははじめてのコントリビューションガイドを参照してください。

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

ValveSoftware/steam-runtime のほかの issue

ValveSoftware/steam-runtime の issue をすべて見る

似ている issue

Shell/Bash の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。