The lint ratchets (WP2b + WP2c): crate-level gaps closed, the three-workspace hoist, three blocking grep gates #171

Merged
enricobuehler merged 7 commits from worktree-lint-ratchets into main 2026-08-11 21:57:30 +00:00
Owner

Finishes the rust-safety programme's §4 WP2 from design/rust-safety-lint-ratchets-handoff.md. Moves the primary unsafe metric by ~zero, by design — everything here is a permanent structural control that stops new undisciplined code accruing.

The three crate-level gaps (WP2b) — 23fa03b0

  • pf-vkhdr-layer — the sharpest gap: a Vulkan implicit layer injected into every Vulkan game process, 32 unsafe usages, zero SAFETY comments, its own workspace so no lint table reached it, plus an explicit missing_safety_doc allow. Now: a [lints] table (unsafe_op_in_unsafe_fn + clippy::undocumented_unsafe_blocks, both deny), every unsafe operation in an explicit block with a written proof (loader layer protocol / Vulkan valid-usage / the two hand-computed struct offsets), # Safety docs on the contract-carrying fns, const layout asserts on the SurfaceFormat2Raw mirror, five contract-free helpers demoted to safe fns, and both redundant unsafe impl Send deleted (fn pointers are Send intrinsically — the type-check proves it).
  • wdk-probe — the 9 missing SAFETY proofs written (the iddcx_rt.rs DDI slot-dispatch ones argue table population and PFN/index pairing, not pattern fill), sibling denies added, and the crate joins windows-drivers.yml's clippy list — it was the only driver crate not in it.
  • pf-clipboard — the deny moves from host/windows.rs to the crate root, so wayland.rs, mutter.rs, and any future backend under host/ are covered on creation. Free today (all six blocks already carried proofs).

The hoist (WP2c part 1) — dfebb9df + 5f097d53 + abec2a14

undocumented_unsafe_blocks = "deny" joins unsafe_op_in_unsafe_fn in [workspace.lints], and ~100 scattered per-file #![deny(...)] attributes across 85 files are deleted. There are three workspaces, so the claim is made three times (main, packaging/windows/drivers + [lints] workspace = true in all seven members, packaging/windows/pf-vkhdr-layer). pf-update now inherits workspace lints; the vendored member snapshots (cros-codecs, usbip-sim) stay out deliberately and both now say so. Newly-covered fallout: two link-sanity tests (proofs written) and the two bindings-only sys crates (bindgen output in OUT_DIR can't carry hand-written proofs — crate-wide allow with rationale).

nvenc_core.rs is carved out of the unsafe_op_in_unsafe_fn fence: its exemption rationale ("raw entry-table calls almost line for line") was false — the file makes zero FFI calls. It now runs the strictest discipline in the crate: clippy::multiple_unsafe_ops_per_block at deny, every union read/borrow/bitfield-setter call in its own block naming its codec guard — exactly the surface the shipped 4:4:4 bug (hevcConfig stamped onto an AV1 config) lived on. Plain union-arm writes stay bare: the .25 gate corrected me — they're safe by language rule (the hazard is the mismatched read).

The grep gates (WP2c part 2) — 2bfd1cd2, blocking in ci.yml

scripts/ci/check-unsafe-hygiene.sh, three classes no lint covers:

  • A. unsafe fn markers carrying no contract (the db659809 class). Waivable for contract-deferring fns (set_len shape) with // unsafe-fn-no-op-ok: <reason>; fenced files and signature-mandated unsafe extern "ABI" fn callbacks skipped structurally.
  • B. unwrap/expect/panic! in extern "C"/"system" bodies — an abort since Rust 1.81 (the 8b98d0b3 class). catch_unwind bodies exempt.
  • C. Process-global safe APIs (env::set_var, sigaction, …) — the 972af299 class, invisible to the unsafe census. Per-file count ratchet; any increase or new file fails.

Making gate B clean surfaced 14 real instances of exactly its class.lock().unwrap() in unguarded extern fns, where a poisoned mutex aborts the embedding process: six punktfunk-core abi.rs entry points, seven Android JNI entry points, and the Windows client's deeplink wnd_proc. All fixed with poison-recovering locks + Option::insert for the set-then-unwrap shape. Gate A's six findings were genuine contract-deferring fns — waived with reasons.

Gate-of-the-gate: all three shown to fail on deliberately planted instances (and re-shown after the mawk-portability rewrite — the awk originally used a gawk-only empty-separator split, which Debian's mawk would have made silently vacuous), and to run clean, before the ci.yml step made them blocking.

Verification

  • .25cargo clippy --workspace --all-targets --locked -- -D warnings exit 0 on the final tree (GTK client excluded: box lacks GTK dev packages, real CI installs them), plus the ci.yml feature-gated encode leg: clippy exit 0, 120 tests pass (covers nvenc_core under its new lint).
  • .133 — the full lint suite, extract-first with sentinels + cargo clean so a stale upload can't pass: all 12 steps exit 0 — host/encode (nvenc,amf-qsv,qsv), capture, vdisplay, tray, the Windows client, pf-vkhdr-layer fmt+clippy, and the drivers workspace clippy including wdk-probe under the real WDK + drivers fmt.
  • punktfunk-core's 203 lib tests pass locally; native macOS clippy clean for everything that compiles there (three pre-existing mac-native failures reproduce on the clean tree).
Finishes the rust-safety programme's §4 WP2 from `design/rust-safety-lint-ratchets-handoff.md`. Moves the primary unsafe metric by ~zero, by design — everything here is a permanent structural control that stops *new* undisciplined code accruing. ## The three crate-level gaps (WP2b) — `23fa03b0` - **pf-vkhdr-layer** — the sharpest gap: a Vulkan implicit layer injected into every Vulkan game process, 32 unsafe usages, zero SAFETY comments, its own workspace so no lint table reached it, plus an explicit `missing_safety_doc` allow. Now: a `[lints]` table (`unsafe_op_in_unsafe_fn` + `clippy::undocumented_unsafe_blocks`, both deny), every unsafe operation in an explicit block with a written proof (loader layer protocol / Vulkan valid-usage / the two hand-computed struct offsets), `# Safety` docs on the contract-carrying fns, const layout asserts on the `SurfaceFormat2Raw` mirror, five contract-free helpers demoted to safe fns, and both redundant `unsafe impl Send` deleted (fn pointers are `Send` intrinsically — the type-check proves it). - **wdk-probe** — the 9 missing SAFETY proofs written (the `iddcx_rt.rs` DDI slot-dispatch ones argue table population and PFN/index pairing, not pattern fill), sibling denies added, and the crate joins `windows-drivers.yml`'s clippy list — it was the only driver crate not in it. - **pf-clipboard** — the deny moves from `host/windows.rs` to the crate root, so `wayland.rs`, `mutter.rs`, and any *future* backend under `host/` are covered on creation. Free today (all six blocks already carried proofs). ## The hoist (WP2c part 1) — `dfebb9df` + `5f097d53` + `abec2a14` `undocumented_unsafe_blocks = "deny"` joins `unsafe_op_in_unsafe_fn` in `[workspace.lints]`, and ~100 scattered per-file `#![deny(...)]` attributes across 85 files are deleted. There are **three workspaces**, so the claim is made three times (main, `packaging/windows/drivers` + `[lints] workspace = true` in all seven members, `packaging/windows/pf-vkhdr-layer`). `pf-update` now inherits workspace lints; the vendored member snapshots (cros-codecs, usbip-sim) stay out deliberately and both now say so. Newly-covered fallout: two link-sanity tests (proofs written) and the two bindings-only sys crates (bindgen output in OUT_DIR can't carry hand-written proofs — crate-wide allow with rationale). **nvenc_core.rs is carved out of the `unsafe_op_in_unsafe_fn` fence**: its exemption rationale ("raw entry-table calls almost line for line") was false — the file makes zero FFI calls. It now runs the strictest discipline in the crate: `clippy::multiple_unsafe_ops_per_block` at deny, every union read/borrow/bitfield-setter call in its own block naming its codec guard — exactly the surface the shipped 4:4:4 bug (`hevcConfig` stamped onto an AV1 config) lived on. Plain union-arm *writes* stay bare: the `.25` gate corrected me — they're safe by language rule (the hazard is the mismatched read). ## The grep gates (WP2c part 2) — `2bfd1cd2`, blocking in ci.yml `scripts/ci/check-unsafe-hygiene.sh`, three classes no lint covers: - **A. `unsafe fn` markers carrying no contract** (the `db659809` class). Waivable for contract-deferring fns (`set_len` shape) with `// unsafe-fn-no-op-ok: <reason>`; fenced files and signature-mandated `unsafe extern "ABI" fn` callbacks skipped structurally. - **B. `unwrap`/`expect`/`panic!` in `extern "C"`/`"system"` bodies** — an abort since Rust 1.81 (the `8b98d0b3` class). `catch_unwind` bodies exempt. - **C. Process-global safe APIs** (`env::set_var`, `sigaction`, …) — the `972af299` class, invisible to the unsafe census. Per-file count ratchet; any increase or new file fails. Making gate B clean surfaced **14 real instances of exactly its class** — `.lock().unwrap()` in unguarded extern fns, where a poisoned mutex aborts the embedding process: six `punktfunk-core` `abi.rs` entry points, seven Android JNI entry points, and the Windows client's deeplink `wnd_proc`. All fixed with poison-recovering locks + `Option::insert` for the set-then-unwrap shape. Gate A's six findings were genuine contract-deferring fns — waived with reasons. Gate-of-the-gate: all three shown to **fail on deliberately planted instances** (and re-shown after the mawk-portability rewrite — the awk originally used a gawk-only empty-separator `split`, which Debian's mawk would have made silently vacuous), and to run clean, before the ci.yml step made them blocking. ## Verification - **`.25`** — `cargo clippy --workspace --all-targets --locked -- -D warnings` exit 0 on the final tree (GTK client excluded: box lacks GTK dev packages, real CI installs them), plus the ci.yml feature-gated encode leg: clippy exit 0, **120 tests pass** (covers nvenc_core under its new lint). - **`.133`** — the full lint suite, extract-first with sentinels + `cargo clean` so a stale upload can't pass: **all 12 steps exit 0** — host/encode (`nvenc,amf-qsv,qsv`), capture, vdisplay, tray, the Windows client, pf-vkhdr-layer fmt+clippy, and the drivers workspace clippy **including wdk-probe under the real WDK** + drivers fmt. - punktfunk-core's 203 lib tests pass locally; native macOS clippy clean for everything that compiles there (three pre-existing mac-native failures reproduce on the clean tree).
enricobuehler added 6 commits 2026-08-11 21:55:35 +00:00
pf-vkhdr-layer — the sharpest gap: an implicit layer injected into every
Vulkan game process, 32 unsafe usages, zero SAFETY comments, own workspace so
no lint table reached it, and an explicit missing_safety_doc allow. Now: a
[lints] table (unsafe_op_in_unsafe_fn + clippy::undocumented_unsafe_blocks,
both deny), the allow removed, every unsafe operation in an explicit block
with a real proof (loader layer protocol / Vulkan valid-usage), # Safety docs
on the contract-carrying fns, const layout asserts for the SurfaceFormat2Raw
mirror, the five helpers with no caller-facing contract demoted to safe fns,
and the two redundant `unsafe impl Send` deleted (fn pointers and vk handles
are Send intrinsically — the type-check proves it).

wdk-probe — 21 unsafe blocks, 12 proofs: the 9 missing SAFETY comments are
written (the iddcx_rt.rs DDI slot-dispatch ones are about table population
and PFN/index pairing, not pattern fill), the sibling denies added at the
crate root, missing_safety_doc allow dropped, # Safety on DriverEntry, and
the crate joins windows-drivers.yml's clippy list — it was the only driver
crate not in it.

pf-clipboard — the undocumented_unsafe_blocks deny moves from host/windows.rs
to the crate root so host/wayland.rs (4 blocks), host/mutter.rs (2) and any
future backend under host/ are covered on creation. All existing blocks
already carry proofs; free today, structural tomorrow.

Verified here: pf-vkhdr-layer cargo fmt --check + clippy --release
-D warnings at x86_64-pc-windows-msvc. wdk-probe and pf-clipboard compile
checks need the WDK/Linux boxes and ride the .133/.25 gate.
undocumented_unsafe_blocks joins unsafe_op_in_unsafe_fn in
[workspace.lints], and the ~100 scattered per-file #![deny(...)] attributes
(85 files) are deleted — a new crate, or a new module in an old one, is now
covered on creation rather than on remembering. The per-file form is how
pf-vkhdr-layer, wdk-probe and half of pf-clipboard stayed uncovered.

There are THREE workspaces, so the claim is made three times: the main
Cargo.toml, packaging/windows/drivers (workspace table + [lints]
workspace = true in all seven members), and packaging/windows/pf-vkhdr-layer
(its [lints] table, previous commit). pf-update now opts into workspace
lints; the two vendored member snapshots (cros-codecs, usbip-sim) stay out
deliberately and now both say so.

Newly-covered fallout was two link-sanity tests (pyrowave-sys, libvpl-sys)
— proofs written. Stale prose that claimed the workspace held
unsafe_op_in_unsafe_fn at "warn" (it has been deny) or pointed at the
deleted attributes is corrected.

nvenc_core.rs is carved OUT of the unsafe_op_in_unsafe_fn fence: its
exemption rationale ("raw entry-table calls almost line for line") was
false — the file makes zero FFI calls. Its unsafe surface is C-union writes
whose soundness hangs on which codec arm is active, and its own 4:4:4 note
records the shipped bug (hevcConfig bytes stamped onto an AV1 config) that
per-operation blocks make visible. It now runs the strictest discipline in
the crate: clippy::multiple_unsafe_ops_per_block at deny, one union access
per block, each naming its codec guard.

Verified here: cargo fmt clean in all three workspaces; native clippy
-D warnings clean for everything that compiles on macOS (the three
pre-existing mac-native failures — pf-client-core wol.rs, pf-encode
dead-code/closure-call, probe mic_burst — reproduce on the clean tree).
Linux/Windows legs ride the .25/.133 gate.
scripts/ci/check-unsafe-hygiene.sh — textual gates for three classes no lint
covers:

A. unsafe fn markers carrying no contract. unsafe_op_in_unsafe_fn forces real
   ops into blocks, so an unsafe fn with no `unsafe` in its body is a marker
   with no contract (db659809 found two by hand). Contract-deferring fns
   (Vec::set_len shape) waive with `// unsafe-fn-no-op-ok: <reason>`; fenced
   files and `unsafe extern "ABI" fn` (signature-mandated markers) are
   skipped structurally.

B. unwrap/expect/panic! inside extern "C"/"system" bodies — an abort since
   Rust 1.81, not linted, not fuzzable (8b98d0b3). catch_unwind bodies are
   exempt; `// panic-in-extern-ok: <reason>` waives a deliberate abort.

C. Safe-but-process-global APIs (env::set_var/remove_var, sigaction,
   setlocale, set_current_dir) — the 972af299 environ race lived in a file
   with zero occurrences of the word `unsafe`. Per-file count ratchet with
   the baseline in the script; any increase or new file fails.

Making gate B clean on main surfaced 14 real instances of exactly its class —
`.lock().unwrap()` in unguarded extern fns, where a poisoned mutex aborts the
embedding process: six punktfunk-core abi.rs entry points (poll_frame,
next_au, next_audio, next_audio_pcm, next_cursor_shape, next_clipboard),
seven Android JNI entry points, and the Windows client's deeplink wnd_proc.
All fixed with poison-recovering locks (the slots are last-value caches,
valid whatever a poisoned writer left) and Option::insert for the
set-then-unwrap shape; punktfunk-core's 203 lib tests pass. Gate A's
findings were six genuine contract-deferring fns — waived with reasons, not
fixed, because the markers are correct.

Gate-of-the-gate: all three shown to FAIL on deliberately planted instances
(marker fn, panicking extern callback, env::set_var in an unlisted file) and
to run clean on the tree, before the ci.yml step made them blocking.
Linux fallout from the hoist the mac could not see: bindgen emits unsafe
blocks (layout tests/accessors) into OUT_DIR, where nobody hand-writes
SAFETY proofs — pyrowave-sys failed clippy on .25 with 17 of them, and
libvpl-sys would do the same on the Windows leg. Both crates are
bindings-only by charter (the safe wrapper lives with the consumer), so the
allow is crate-wide with the rationale at the crate root; the hand-written
link-sanity tests keep their proofs by convention.
The .25 gate corrected the carve-out: rustc flags `unsafe { u.arm.field = x }`
as unused_unsafe — plain assignment through a union projection is safe
(writing an arm cannot itself be UB; the hazard is the mismatched READ).
The 11 plain writes go back to bare statements under their codec matches.
What stays in per-op unsafe blocks with arm-guard proofs is the real unsafe
surface: union reads, borrows, and the bindgen bitfield-setter calls — which
is exactly the surface the shipped 4:4:4 bug lived on (set_chromaFormatIDC
stamped under a wrong codec).
chore(safety): two .133 gate findings — cfg the abi lock helper, re-anchor a layer proof
ci / bun-nix (pull_request) Successful in 40s
ci / web (pull_request) Successful in 1m24s
ci / docs-site (pull_request) Successful in 1m30s
android / android (pull_request) Canceled after 1m45s
apple / swift (pull_request) Canceled after 1m41s
apple / screenshots (pull_request) Canceled after 0s
ci / rust (pull_request) Canceled after 1m43s
ci / rust-arm64 (pull_request) Canceled after 1m43s
nix / flake (pull_request) Canceled after 1m29s
windows-drivers / probe-and-proto (pull_request) Canceled after 0s
windows-drivers / driver-build (pull_request) Canceled after 1m25s
windows / build (aarch64-pc-windows-msvc) (pull_request) Canceled after 0s
windows / build (x86_64-pc-windows-msvc) (pull_request) Canceled after 0s
d67ab9ede4
The tray leg builds punktfunk-core with default-features off, where
lock_recover's only callers (the quic-gated punktfunk_connection_* entry
points) do not exist — dead code under -D warnings. The helper takes the
same feature gate.

In pf-vkhdr-layer, rustfmt had reflowed destroy_surface's lookup into a
multiline closure, leaving the SAFETY comment outside the closure that
contains its unsafe block — the box's clippy rightly stopped accepting the
adjacency. The comment moves inside, directly above the block.
enricobuehler added 1 commit 2026-08-11 21:57:19 +00:00
Merge branch 'main' into worktree-lint-ratchets
apple / swift (pull_request) Successful in 1m45s
apple / screenshots (pull_request) Skipped
windows-drivers / driver-build (pull_request) Successful in 2m1s
ci / rust-arm64 (pull_request) Successful in 1m54s
ci / web (pull_request) Successful in 1m13s
ci / docs-site (pull_request) Successful in 1m17s
windows / build (aarch64-pc-windows-msvc) (pull_request) Successful in 1m58s
ci / bun-nix (pull_request) Successful in 1m15s
ci / rust (pull_request) Successful in 6m1s
windows / build (x86_64-pc-windows-msvc) (pull_request) Successful in 2m44s
windows-drivers / probe-and-proto (pull_request) Successful in 26s
android / android (pull_request) Successful in 7m1s
nix / flake (pull_request) Successful in 16m48s
549fdf238b
enricobuehler scheduled this pull request to auto merge when all checks succeed 2026-08-11 21:57:25 +00:00
enricobuehler merged commit 6eb89b3f34 into main 2026-08-11 21:57:29 +00:00
enricobuehler deleted branch worktree-lint-ratchets 2026-08-11 21:57:36 +00:00
Sign in to join this conversation.
No Reviewers
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: unom/punktfunk#171