sniper: bundled PipeWire 0.3.65 segfaults/deadlocks games on Bluetooth profile switch (fixed upstream in 1.2.2)
まだ誰も着手していません。
評価
- 難易度
- 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 の本文から書いたものです。
説明
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:
- Host running a modern PipeWire (1.2.2+) and WirePlumber, with
bluetooth.autoswitch-to-headset-profileat its defaulttrue. - Pair a Bluetooth headset exposing both A2DP and HSP/HFP, and connect it.
- Launch CS2 (sniper runtime).
- Open Settings -> Audio and click the audio device selector dropdown.
- The game segfaults in
libspa-audioconvert.so, or deadlocks with orphanedpw-data-loopthreads.
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 を読み、一般的な手順ははじめてのコントリビューションガイドを参照してください。
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
ValveSoftware/steam-runtime のほかの issue
-
難易度 4/5 3〜5日 初心者へのやさしさ 45/100
ValveSoftware/steam-runtime#862 ·
-
難易度 2/5 1〜3時間 初心者へのやさしさ 55/100
ValveSoftware/steam-runtime#861 · コメント 1 件 ·
-
Need Retest Pressure Vessel
難易度 4/5 3〜5日 初心者へのやさしさ 35/100
ValveSoftware/steam-runtime#854 · コメント 4 件 ·
-
難易度 4/5 3〜5日 初心者へのやさしさ 45/100
ValveSoftware/steam-runtime#851 · コメント 3 件 ·
-
難易度 3/5 1〜2日 初心者へのやさしさ 55/100
ValveSoftware/steam-runtime#847 · コメント 3 件 ·
ValveSoftware/steam-runtime の issue をすべて見る
似ている issue
-
bug
難易度 2/5 1〜3時間 初心者へのやさしさ 70/100
メンテナーはふだん 1 日以内に返信
-
Link Checker Reportオープンautomated issue report
難易度 1/5 1時間未満 初心者へのやさしさ 85/100
a2aproject/A2A#2387 ·
メンテナーはふだん 4 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 70/100
メンテナーはふだん 1 日以内に返信
-
curriculum documentation quality
難易度 2/5 1〜3時間 初心者へのやさしさ 85/100
githubnext/gh-aw-workshop#4965 ·
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 70/100
ajeetdsouza/zoxide#1350 ·
メンテナーはふだん 2 日以内に返信