The safety half of the rust-safety programme's §8.4: `std::env::set_var`/`remove_var` are
`unsafe fn` in edition 2024, converting the class of bug the programme found the hard way
(the 972af299 environ data race lived in a file with ZERO occurrences of the word
`unsafe`) from invisible to counted and compiler-enforced.
Manifests: [workspace.package] edition 2021→2024, rust-version 1.82→1.85 (the pinned
toolchain is 1.96.0, so no toolchain bump — only the declared floor rises); the 13 crates
pinning `edition = "2021"` literally now inherit it (Trap 1: the root bump alone reaches
only `edition.workspace = true` crates and would have left pf-encode/pf-capture/pf-inject
et al. on 2021 while reading as complete); pf-driver-proto's stale rust-version 1.82 pin
now inherits; pf-vkhdr-layer (a separate workspace, inherits nothing) bumped to 2024. The
four vendored crates (fec-rs, cros-codecs, usbip-sim, the patched ndk) stay on 2021
deliberately — upstream code stays pristine. The excluded usbip-poc standalone PoC is
untouched.
Mechanical, done textually across ALL cfg branches so no platform's half is left behind
(Trap 3 — 44% of the host's unsafe is Windows-only and a one-platform `cargo fix` misses
it): 148 `#[no_mangle]` → `#[unsafe(no_mangle)]` (83 in abi.rs); 12 bare extern blocks →
`unsafe extern`; `gen` is a reserved keyword, so pf-vdisplay's generation stamps
(registry.rs, windows/manager.rs) and the WinUI shell's animation counters rename
gen → generation (internal identifiers only, no serde/wire surface); two
match-ergonomics patterns take the compiler's suggested reference form.
env mutation: every `set_var`/`remove_var` site (20 files) now sits in an `unsafe` block
whose SAFETY comment states the real serialization argument (pf-vdisplay's ENV_LOCK,
CONFIG_DIR_TEST_LOCK, ART_ROOTS_LOCK, vkdecode's gpu_lock, the `--test-threads=1`
contracts of the hardware spikes, or single-threaded startup). Two genuine hazards
surfaced en route — exactly the WP3b-class finds this migration exists to make visible —
and are fixed here:
- windows/service.rs spawned the network-profile warner thread BEFORE `load_host_env()`,
so a child-spawning thread (child spawn snapshots the env block) was live while
`set_var` ran in a loop; the load now precedes the spawn.
- pf-console-ui's `fake_home()` re-set HOME outside its OnceLock on EVERY call, so two
parallel tests could race the write; the set now happens exactly once inside
`get_or_init`.
cbindgen (Trap 2): 0.29.4 parses `#[unsafe(no_mangle)]` — verified empirically; the
header regenerates byte-identical. The ci.yml drift check could never catch "failed to
regenerate" (build.rs demotes a cbindgen failure to a warning and writes nothing, leaving
the checked-in header untouched and the diff clean), so the step now first asserts the
"punktfunk-core: wrote" line and the absence of "cbindgen failed" (sh -e safe: no `!`
pipeline, no tee-masked exit).
rustfmt: style_edition pinned to 2021 at the root — edition 2024 would otherwise flip the
style edition and reformat ~370 untouched files inside this same commit, burying the
migration diff. The drivers workspace pins its already-current 2024 style. Adopting the
2024 style tree-wide is its own future one-line-plus-reformat commit.
Census: the primary metric moves UP BY DESIGN — 2435 → 2453 operations, unsafe blocks
1534 → 1577, and env_set_var is now a counted category (45 ops). The newly counted env
sites are a truer number, not a regression; baseline snapshot saved as punktfunk-planning
design/rust-safety-census-baseline-2026-08-12-edition-2024.txt. Gate C's env ratchet is
now compiler-enforced (the hygiene-script header says so); the two shrunk file counts
(nvenc_cuda 49→2 via the test helpers, shell/tests 2→1) are lowered in the same commit
per the gate's own rule.
Drop order (the semantic change most likely to bite this codebase): the migration lint
`-W tail-expr-drop-order` reports zero findings on the macOS-visible halves of
pf-encode / pf-zerocopy / pf-capture / pf-frame; the Linux and Windows halves run the
same lint on the gate boxes. The four #[ignore]d alloc/drop-cycle tests on the hardware
boxes remain owed, as before this change.
68 lines
3.0 KiB
TOML
68 lines
3.0 KiB
TOML
# Frame capture (plan §7 / §W6): the Linux xdg-ScreenCast/PipeWire portal capturer and the Windows
|
|
# IDD direct-push capturer, plus the synthetic sources + the Capturer trait, extracted into a
|
|
# subsystem crate. Depends on the shared frame vocabulary (pf-frame), the zero-copy plumbing
|
|
# (pf-zerocopy), and the display leaves (pf-win-display) — never on pf-encode: the encode-backend
|
|
# facts arrive pre-resolved (ZeroCopyPolicy) and the sealed-channel delivery as a closure
|
|
# (FrameChannelSender), so the capture→encode edge is one-way (plan §2.4).
|
|
[package]
|
|
name = "pf-capture"
|
|
version.workspace = true
|
|
edition.workspace = true
|
|
rust-version.workspace = true
|
|
license = "MIT OR Apache-2.0"
|
|
description = "punktfunk host frame capture: Linux PipeWire portal + Windows IDD direct-push capturers behind one Capturer trait."
|
|
publish = false
|
|
|
|
[dependencies]
|
|
punktfunk-core = { path = "../punktfunk-core", features = ["quic"] }
|
|
pf-frame = { path = "../pf-frame" }
|
|
pf-zerocopy = { path = "../pf-zerocopy" }
|
|
pf-win-display = { path = "../pf-win-display" }
|
|
pf-gpu = { path = "../pf-gpu" }
|
|
pf-host-config = { path = "../pf-host-config" }
|
|
anyhow = "1"
|
|
tracing = "0.1"
|
|
|
|
[target.'cfg(target_os = "linux")'.dependencies]
|
|
# The xdg ScreenCast + RemoteDesktop portals, and the PipeWire consumer for the capture frames.
|
|
ashpd = { version = "0.13", features = ["screencast", "remote_desktop"] }
|
|
pipewire = "0.9"
|
|
libc = "0.2"
|
|
# ashpd 0.13 uses the tokio runtime for the one-time portal handshake (control plane).
|
|
tokio = { version = "1", features = ["rt", "rt-multi-thread", "net", "time"] }
|
|
# XFixes cursor source for gamescope (remote-desktop-sweep Phase C): gamescope paints no
|
|
# `SPA_META_Cursor`, so the pointer never reaches the PipeWire node. We read the shape/hotspot/
|
|
# visibility from gamescope's nested Xwayland via XFixes instead and feed the existing cursor slot.
|
|
# `RustConnection` is the pure-Rust default (no libxcb link → no new C dependency on the host); the
|
|
# `xfixes` feature (auto-pulls `render` + `shape`) is what exposes GetCursorImage/SelectCursorInput.
|
|
x11rb = { version = "0.13", default-features = false, features = ["xfixes"] }
|
|
|
|
[target.'cfg(target_os = "windows")'.dependencies]
|
|
# The host<->driver wire contract for the sealed frame channel (control IOCTL structs + frame header).
|
|
pf-driver-proto = { path = "../pf-driver-proto" }
|
|
windows = { version = "0.62", features = [
|
|
"Win32_Foundation",
|
|
"Win32_Security",
|
|
"Win32_Security_Authorization",
|
|
"Win32_Graphics_Direct3D",
|
|
"Win32_Graphics_Direct3D11",
|
|
"Win32_Graphics_Direct3D_Fxc",
|
|
"Win32_Graphics_Dwm",
|
|
"Win32_Graphics_Dxgi",
|
|
"Win32_Graphics_Dxgi_Common",
|
|
"Win32_Graphics_Gdi",
|
|
"Win32_System_Diagnostics_Etw",
|
|
"Win32_System_LibraryLoader",
|
|
"Win32_System_StationsAndDesktops",
|
|
"Win32_System_Memory",
|
|
"Win32_System_Performance",
|
|
"Win32_System_Threading",
|
|
"Win32_System_Time",
|
|
"Win32_UI_HiDpi",
|
|
"Win32_UI_Input_KeyboardAndMouse",
|
|
"Win32_UI_WindowsAndMessaging",
|
|
] }
|
|
|
|
[lints]
|
|
workspace = true
|