Ports the fix from luxus/punktfunk-overlay#9 into our gamescope patch set as patch 0009 (his authorship kept).
The bug
On client disconnect the host keeps the headless gamescope lingering so a reconnect resumes the same session — and gamescope could SIGSEGV in exactly that window, so the kept display was dead and reconnect silently got a fresh compositor with the game lost. Journal signature: linger line → coredump → kept display was dead — recreating.
Root cause (luxus's diagnosis, verified against our tree): stream_handle_remove_buffer — and the stale-push path in dispatch_nudge — destroyed idle capture buffers on the PipeWire thread. Dropping the last CVulkanTexture reference there calls into the Vulkan driver while steamcompmgr can still be inside vulkan_screenshot on another buffer of the same 4-buffer pool; on NVIDIA the race lands as a SIGSEGV in CVulkanCmdBuffer::insertBarrier. It fires at stream end, which is why it selectively killed linger.
Our 0007 does not cover this — same file, different bug (the user_data use-after-free on renegotiation). Crash #1 in the issue's coredump table (~CVulkanDevice during exit) is 0006's already-fixed static-destruction bug, not this race.
The fix
The PipeWire thread only queues the corpse (bury_buffer, mutex-guarded); steamcompmgr reaps on every vblank, including while the stream is paused — the linger state itself. Field-proven on the reporter's NVIDIA host: 4 coredumps in one evening (BG3, 4K60 HDR, --pipewire-composite-cursor), zero after; disconnect/reconnect confirmed live (2026-08-13) to reuse the lingered session.
Ours differs from the overlay's original only by the meson.build banner hunk: +pfhdr6 → +pfhdr7, PKGBUILD 3.16.25.pfhdr7-1. No new capability — same rule as pfhdr5/6: "reconnect lost my game" triage has to read a box's exposure off its banner, and every host probe is >=. Known residual, deliberately untouched: add_buffer's error path still deletes on the PW thread (reachable only when an add fails mid-renegotiation, which no field coredump shows) — the patch stays byte-identical with what was proven on-glass.
Verification
Full 0001..0009 series applies onto the bare 5fb8dce4 pin with plain git am (the build script's exact invocation, no -3, no fuzz).
Full build in the fc44 CI image (punktfunk-fedora44-rpm, rpm.yml's exact dep recipe): green, banner 3.16.25-20-g40fe8b5+pfhdr7 (gcc 16.1.1).
After 0009, destroy_buffer has exactly two callers — pipewire_reap_dead_buffers (vblank) and pipewire_destroy_buffer (copy-completion) — both on the compositor thread.
Nix, deb, rpm and sysext all glob patches/*.patch and read the level off the banner, so no other packaging file moves.
Note: #210 also touches packaging/gamescope/ files — worst case is a trivial comment-block merge in the PKGBUILD, whichever lands second.
Ports the fix from [luxus/punktfunk-overlay#9](https://github.com/luxus/punktfunk-overlay/issues/9) into our gamescope patch set as **patch 0009** (his authorship kept).
## The bug
On client disconnect the host keeps the headless gamescope **lingering** so a reconnect resumes the same session — and gamescope could SIGSEGV in exactly that window, so the kept display was dead and reconnect silently got a fresh compositor with the game lost. Journal signature: linger line → coredump → `kept display was dead — recreating`.
Root cause (luxus's diagnosis, verified against our tree): `stream_handle_remove_buffer` — and the stale-push path in `dispatch_nudge` — destroyed idle capture buffers on the **PipeWire thread**. Dropping the last `CVulkanTexture` reference there calls into the Vulkan driver while steamcompmgr can still be inside `vulkan_screenshot` on another buffer of the same 4-buffer pool; on NVIDIA the race lands as a SIGSEGV in `CVulkanCmdBuffer::insertBarrier`. It fires at stream **end**, which is why it selectively killed linger.
Our 0007 does **not** cover this — same file, different bug (the `user_data` use-after-free on renegotiation). Crash #1 in the issue's coredump table (`~CVulkanDevice` during `exit`) is 0006's already-fixed static-destruction bug, not this race.
## The fix
The PipeWire thread only queues the corpse (`bury_buffer`, mutex-guarded); steamcompmgr reaps on every vblank, **including while the stream is paused** — the linger state itself. Field-proven on the reporter's NVIDIA host: 4 coredumps in one evening (BG3, 4K60 HDR, `--pipewire-composite-cursor`), zero after; disconnect/reconnect confirmed live (2026-08-13) to reuse the lingered session.
Ours differs from the overlay's original only by the `meson.build` banner hunk: **`+pfhdr6` → `+pfhdr7`**, PKGBUILD `3.16.25.pfhdr7-1`. No new capability — same rule as pfhdr5/6: "reconnect lost my game" triage has to read a box's exposure off its banner, and every host probe is `>=`. Known residual, deliberately untouched: `add_buffer`'s error path still deletes on the PW thread (reachable only when an add *fails* mid-renegotiation, which no field coredump shows) — the patch stays byte-identical with what was proven on-glass.
## Verification
- Full `0001..0009` series applies onto the bare `5fb8dce4` pin with plain `git am` (the build script's exact invocation, no `-3`, no fuzz).
- Full build in the fc44 CI image (`punktfunk-fedora44-rpm`, rpm.yml's exact dep recipe): green, banner `3.16.25-20-g40fe8b5+pfhdr7 (gcc 16.1.1)`.
- After 0009, `destroy_buffer` has exactly two callers — `pipewire_reap_dead_buffers` (vblank) and `pipewire_destroy_buffer` (copy-completion) — both on the compositor thread.
- Nix, deb, rpm and sysext all glob `patches/*.patch` and read the level off the banner, so no other packaging file moves.
Note: #210 also touches `packaging/gamescope/` files — worst case is a trivial comment-block merge in the PKGBUILD, whichever lands second.
Patch 0009, reported, written and proven live by luxus (punktfunk-overlay#9): when the capture
consumer leaves, stream_handle_remove_buffer — and the stale-push path in dispatch_nudge —
destroyed idle buffers on the PipeWire thread. Dropping the last CVulkanTexture reference there
calls into the Vulkan driver (vkDestroyImage / FreeMemory / dmabuf fds) while steamcompmgr can
still be inside vulkan_screenshot on another buffer of the same 4-buffer pool; on NVIDIA the race
lands as a SIGSEGV in CVulkanCmdBuffer::insertBarrier. The timing is what made it selectively
lethal: it fires at stream END — exactly the window where the host keeps the headless display
lingering for a reconnect. So the kept display was already dead (journal: linger line → coredump →
"kept display was dead — recreating") and the "resumed" session was a fresh compositor with the
game lost.
The fix queues the corpses (bury_buffer, mutex-guarded) and steamcompmgr reaps them on every
vblank, including while the stream is only paused — the linger state itself. Field-proven on the
reporter's NVIDIA host: 4 coredumps in one evening of BG3 at 4K60 HDR with --pipewire-composite-
cursor (the heaviest paint path we ship), zero after; disconnect/reconnect confirmed live to reuse
the lingered session (2026-08-13). Three of the four stacks are this race; the fourth
(~CVulkanDevice during exit) is patch 0006's already-fixed static-destruction bug — do not
re-diagnose it as part of this.
Ours differs from the overlay's original only by the meson.build banner hunk: +pfhdr6 → +pfhdr7,
PKGBUILD 3.16.25.pfhdr7-1. No new capability — same rule as pfhdr5/6: "reconnect lost my game"
triage has to read a box's exposure off its banner, and every probe is >=. Known residual,
deliberately untouched: add_buffer's error path still deletes on the PW thread. By the later
`goto error`s a texture may be attached, so the race is reachable there in theory — but only when
an add FAILS mid-renegotiation, which no field coredump shows; the patch stays byte-identical with
what was proven on-glass.
Verified: the full 0001..0009 series applies onto the bare 5fb8dce4 pin with plain `git am` (the
build script's own invocation, no -3, no fuzz) and with `git am -3`; the fc44 CI image
(punktfunk-fedora44-rpm) builds the result with rpm.yml's exact dep recipe to a binary whose
banner reads `3.16.25-20-g40fe8b5+pfhdr7 (gcc 16.1.1)`. After 0009, destroy_buffer has exactly
two callers left —
pipewire_reap_dead_buffers (steamcompmgr vblank) and pipewire_destroy_buffer (steamcompmgr's
copy-completion path) — both on the compositor thread. Nix, deb, sysext and rpm all glob
patches/*.patch and read the level off the banner, so no other packaging file moves.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Ports the fix from luxus/punktfunk-overlay#9 into our gamescope patch set as patch 0009 (his authorship kept).
The bug
On client disconnect the host keeps the headless gamescope lingering so a reconnect resumes the same session — and gamescope could SIGSEGV in exactly that window, so the kept display was dead and reconnect silently got a fresh compositor with the game lost. Journal signature: linger line → coredump →
kept display was dead — recreating.Root cause (luxus's diagnosis, verified against our tree):
stream_handle_remove_buffer— and the stale-push path indispatch_nudge— destroyed idle capture buffers on the PipeWire thread. Dropping the lastCVulkanTexturereference there calls into the Vulkan driver while steamcompmgr can still be insidevulkan_screenshoton another buffer of the same 4-buffer pool; on NVIDIA the race lands as a SIGSEGV inCVulkanCmdBuffer::insertBarrier. It fires at stream end, which is why it selectively killed linger.Our 0007 does not cover this — same file, different bug (the
user_datause-after-free on renegotiation). Crash #1 in the issue's coredump table (~CVulkanDeviceduringexit) is 0006's already-fixed static-destruction bug, not this race.The fix
The PipeWire thread only queues the corpse (
bury_buffer, mutex-guarded); steamcompmgr reaps on every vblank, including while the stream is paused — the linger state itself. Field-proven on the reporter's NVIDIA host: 4 coredumps in one evening (BG3, 4K60 HDR,--pipewire-composite-cursor), zero after; disconnect/reconnect confirmed live (2026-08-13) to reuse the lingered session.Ours differs from the overlay's original only by the
meson.buildbanner hunk:+pfhdr6→+pfhdr7, PKGBUILD3.16.25.pfhdr7-1. No new capability — same rule as pfhdr5/6: "reconnect lost my game" triage has to read a box's exposure off its banner, and every host probe is>=. Known residual, deliberately untouched:add_buffer's error path still deletes on the PW thread (reachable only when an add fails mid-renegotiation, which no field coredump shows) — the patch stays byte-identical with what was proven on-glass.Verification
0001..0009series applies onto the bare5fb8dce4pin with plaingit am(the build script's exact invocation, no-3, no fuzz).punktfunk-fedora44-rpm, rpm.yml's exact dep recipe): green, banner3.16.25-20-g40fe8b5+pfhdr7 (gcc 16.1.1).destroy_bufferhas exactly two callers —pipewire_reap_dead_buffers(vblank) andpipewire_destroy_buffer(copy-completion) — both on the compositor thread.patches/*.patchand read the level off the banner, so no other packaging file moves.Note: #210 also touches
packaging/gamescope/files — worst case is a trivial comment-block merge in the PKGBUILD, whichever lands second.