diff --git a/Cargo.toml b/Cargo.toml index e953f212..64440cd5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -60,11 +60,30 @@ repository = "https://git.unom.io/unom/punktfunk" # workspace. `unsafe fn` marks a CONTRACT the caller must uphold; it is not a licence for the whole # body to skip checking. Without this lint an `unsafe fn` body is unchecked end to end, so a 600-line # function hides which handful of lines are actually the unsafe ones — exactly the reviewer-hostile -# shape we are working down. `warn` while the remaining sites are cleared crate by crate; flip to -# `deny` once they are, so it can never regress. (This is the Rust 2024 default; adopting it early -# also pays off the edition migration.) +# shape we are working down. (This is the Rust 2024 default; adopting it early also pays off the +# edition migration.) +# +# `deny`, not `warn`. `warn` was never actually a softer setting: CI runs `cargo clippy … -D +# warnings`, which promotes it to a hard error anyway — that is how adopting this lint turned main +# red on every platform for a day without the level in this file ever saying `deny`. A level that +# lies about its own severity is worse than a strict one, so this now states what CI already does, +# and the exemptions are written down per file instead of hiding in a 689-warning wall nobody reads. +# +# THE EXEMPTIONS. Fourteen GPU/FFI backend files carry `#![allow(unsafe_op_in_unsafe_fn)]` with a +# one-line reason each. They are not "not done yet" — they are where this lint stops paying: +# their bodies are ash/CUDA/AMF/libav calls almost line for line (measured: 64% of the sites are a +# single third-party FFI call, and of the 44 `unsafe fn`s in them only 4 have a body containing no +# unsafe operation at all). Narrowing them means one `unsafe {}` per line plus, since pf-encode also +# denies `clippy::undocumented_unsafe_blocks`, one hand-written SAFETY comment per line that could +# only ever restate "an ash call on a live device" — the precise noise that made `unsafe` stop +# meaning anything here before (see the header of `pf-win-display/src/win_display.rs`). +# +# Everything else in the workspace is at zero and enforced. Removing one of those allows, file by +# file, is real work with a real payoff; blanket-narrowing all fourteen is not. Prefer DELETING an +# `unsafe fn` marker over wrapping its body: keep the marker only where a caller can actually break +# something (a raw pointer, a borrowed HANDLE, a GPU object that must not be in flight). [workspace.lints.rust] -unsafe_op_in_unsafe_fn = "warn" +unsafe_op_in_unsafe_fn = "deny" [profile.release] opt-level = 3 diff --git a/clients/linux/src/ui_settings.rs b/clients/linux/src/ui_settings.rs index 91714191..0bde119f 100644 --- a/clients/linux/src/ui_settings.rs +++ b/clients/linux/src/ui_settings.rs @@ -732,10 +732,6 @@ fn group(title: &str, description: &str) -> adw::PreferencesGroup { g } -/// `on_closed` runs after the settings are saved (the app shell refreshes the hosts grid -/// there so the library toggle takes effect without a nav round-trip). `probes` is the -/// shell's startup device probe (`AppModel::probes`) — may still be empty. Returns the -/// presented dialog so the screenshot harness can select a page; callers ignore it. /// The dialog in a given [`Scope`]. `on_scope` asks the app to re-open it in another one: /// switching scope closes this dialog first, so the layer being edited is committed before /// the next one is loaded, and there is exactly one place that builds the rows. diff --git a/crates/pf-client-core/src/video_pyrowave.rs b/crates/pf-client-core/src/video_pyrowave.rs index 873c5501..ce241e0b 100644 --- a/crates/pf-client-core/src/video_pyrowave.rs +++ b/crates/pf-client-core/src/video_pyrowave.rs @@ -29,6 +29,13 @@ //! rings are retired, not destroyed — the presenter may still hold their views (see //! [`RETIRE_HANDOVERS`]). +// UNSAFE-LINT EXEMPTION (rationale + exit criteria: `unsafe_op_in_unsafe_fn` in the workspace +// Cargo.toml). This body is `pyrowave-sys` C-API and ash/Vulkan compute calls almost line for line; +// narrowing it would add one `unsafe {}` plus one SAFETY comment per call that could only restate +// the signature. Clearing this file means DELETING the markers that carry no caller contract, not +// wrapping the calls — until then the lint is off HERE and enforced everywhere else. +#![allow(unsafe_op_in_unsafe_fn)] + use crate::video::{ColorDesc, VulkanDecodeDevice}; use anyhow::{bail, Context as _, Result}; use ash::vk; diff --git a/crates/pf-client-core/src/video_vulkan.rs b/crates/pf-client-core/src/video_vulkan.rs index 5aaa85e1..c3aed5df 100644 --- a/crates/pf-client-core/src/video_vulkan.rs +++ b/crates/pf-client-core/src/video_vulkan.rs @@ -1,4 +1,10 @@ //! FFmpeg Vulkan Video decode over the presenter's own VkDevice (zero-copy VkImage). +// UNSAFE-LINT EXEMPTION (rationale + exit criteria: `unsafe_op_in_unsafe_fn` in the workspace +// Cargo.toml). This body is raw libav + ash calls on the presenter's VkDevice almost line for line; +// narrowing it would add one `unsafe {}` plus one SAFETY comment per call that could only restate +// the signature. Clearing this file means DELETING the markers that carry no caller contract, not +// wrapping the calls — until then the lint is off HERE and enforced everywhere else. +#![allow(unsafe_op_in_unsafe_fn)] #![allow(clippy::unnecessary_cast)] use crate::video::{ diff --git a/crates/pf-encode/src/enc/linux/mod.rs b/crates/pf-encode/src/enc/linux/mod.rs index 50d30857..79350dcc 100644 --- a/crates/pf-encode/src/enc/linux/mod.rs +++ b/crates/pf-encode/src/enc/linux/mod.rs @@ -8,6 +8,12 @@ //! does *not* accept — we expand it to `rgb0` (one padding byte/pixel, no colour math). //! The encoder is opened *without* a global header so VPS/SPS/PPS are emitted in-band on //! every IDR — the output is both a playable raw Annex-B stream and self-contained AUs. +// UNSAFE-LINT EXEMPTION (rationale + exit criteria: `unsafe_op_in_unsafe_fn` in the workspace +// Cargo.toml). This body is raw libav (`ffmpeg-sys-next`) hwcontext calls almost line for line; +// narrowing it would add one `unsafe {}` plus one SAFETY comment per call that could only restate +// the signature. Clearing this file means DELETING the markers that carry no caller contract, not +// wrapping the calls — until then the lint is off HERE and enforced everywhere else. +#![allow(unsafe_op_in_unsafe_fn)] // Every `unsafe` block in this file carries a `// SAFETY:` proof; enforce it (unsafe-proof program). #![deny(clippy::undocumented_unsafe_blocks)] diff --git a/crates/pf-encode/src/enc/linux/nvenc_cuda.rs b/crates/pf-encode/src/enc/linux/nvenc_cuda.rs index 49340e18..2b8ffdc1 100644 --- a/crates/pf-encode/src/enc/linux/nvenc_cuda.rs +++ b/crates/pf-encode/src/enc/linux/nvenc_cuda.rs @@ -57,6 +57,12 @@ //! starts driver-less (the `.so` resolves at runtime — on an AMD/Intel box [`try_api`] fails cleanly //! and the VAAPI/software backends carry the session). +// UNSAFE-LINT EXEMPTION (rationale + exit criteria: `unsafe_op_in_unsafe_fn` in the workspace +// Cargo.toml). This body is raw CUDA driver + `nvEncodeAPI` entry-table calls almost line for line; +// narrowing it would add one `unsafe {}` plus one SAFETY comment per call that could only restate +// the signature. Clearing this file means DELETING the markers that carry no caller contract, not +// wrapping the calls — until then the lint is off HERE and enforced everywhere else. +#![allow(unsafe_op_in_unsafe_fn)] // Every `unsafe` block / impl in this file carries a `// SAFETY:` proof; enforce it. #![deny(clippy::undocumented_unsafe_blocks)] diff --git a/crates/pf-encode/src/enc/linux/pyrowave.rs b/crates/pf-encode/src/enc/linux/pyrowave.rs index f9d1fa85..1d9f0aac 100644 --- a/crates/pf-encode/src/enc/linux/pyrowave.rs +++ b/crates/pf-encode/src/enc/linux/pyrowave.rs @@ -21,6 +21,13 @@ //! on every AU. NOTE: until Phase 2 lands `CODEC_PYROWAVE` negotiation + a client decoder, //! no shipping client can decode this — the backend is reachable only via an explicit //! `PUNKTFUNK_ENCODER=pyrowave` and logs that loudly. +// UNSAFE-LINT EXEMPTION (rationale + exit criteria: `unsafe_op_in_unsafe_fn` in the workspace +// Cargo.toml). This body is `pyrowave-sys` C-API and ash/Vulkan compute calls almost line for line; +// narrowing it would add one `unsafe {}` plus one SAFETY comment per call that could only restate +// the signature. Clearing this file means DELETING the markers that carry no caller contract, not +// wrapping the calls — until then the lint is off HERE and enforced everywhere else. +#![allow(unsafe_op_in_unsafe_fn)] + // Every unsafe block in this module carries a `// SAFETY:` proof (parent module enforces it). use super::vk_util::{ diff --git a/crates/pf-encode/src/enc/linux/vaapi.rs b/crates/pf-encode/src/enc/linux/vaapi.rs index d7b24114..3fe46461 100644 --- a/crates/pf-encode/src/enc/linux/vaapi.rs +++ b/crates/pf-encode/src/enc/linux/vaapi.rs @@ -19,6 +19,13 @@ //! hwdevice/hwframes/buffersrc/buffersink calls go through `ffmpeg::ffi` (= `ffmpeg_sys_next`), //! as the CUDA encode path and the clients' decode paths already do. The encoder is opened //! *without* a global header, so VPS/SPS/PPS are in-band on every IDR. +// UNSAFE-LINT EXEMPTION (rationale + exit criteria: `unsafe_op_in_unsafe_fn` in the workspace +// Cargo.toml). This body is raw libav (`ffmpeg-sys-next`) calls on borrowed AVFrame/AVBuffer +// pointers almost line for line; narrowing it would add one `unsafe {}` plus one SAFETY comment per +// call that could only restate the signature. Clearing this file means DELETING the markers that +// carry no caller contract, not wrapping the calls — until then the lint is off HERE and enforced +// everywhere else. +#![allow(unsafe_op_in_unsafe_fn)] // Every `unsafe` block in this file carries a `// SAFETY:` proof; enforce it (unsafe-proof program). #![deny(clippy::undocumented_unsafe_blocks)] diff --git a/crates/pf-encode/src/enc/linux/vk_build.rs b/crates/pf-encode/src/enc/linux/vk_build.rs index b7dad17c..403f9678 100644 --- a/crates/pf-encode/src/enc/linux/vk_build.rs +++ b/crates/pf-encode/src/enc/linux/vk_build.rs @@ -6,6 +6,13 @@ //! visibility churn, and ~800 lines of construction `unsafe` get their own review surface. //! Steady-state encode logic stays in the parent. +// UNSAFE-LINT EXEMPTION (rationale + exit criteria: `unsafe_op_in_unsafe_fn` in the workspace +// Cargo.toml). This body is raw ash/Vulkan object construction and bitstream writing almost line +// for line; narrowing it would add one `unsafe {}` plus one SAFETY comment per call that could only +// restate the signature. Clearing this file means DELETING the markers that carry no caller +// contract, not wrapping the calls — until then the lint is off HERE and enforced everywhere else. +#![allow(unsafe_op_in_unsafe_fn)] + // The parent's whole item namespace (Frame, the consts, sibling helpers) — the point of the // child-module shape. External imports are this file's own; `vk_util` is a crate-root sibling, // so the path is `crate::`, not the parent-relative `super::` the parent uses. diff --git a/crates/pf-encode/src/enc/linux/vk_util.rs b/crates/pf-encode/src/enc/linux/vk_util.rs index 81b6256f..e1455dac 100644 --- a/crates/pf-encode/src/enc/linux/vk_util.rs +++ b/crates/pf-encode/src/enc/linux/vk_util.rs @@ -1,6 +1,13 @@ //! Small ash/Vulkan leaf helpers shared by the Linux Vulkan encode backends //! (`vulkan_video.rs`, `pyrowave.rs`) — extracted verbatim from `vulkan_video.rs` //! when the PyroWave backend arrived so the two don't fork copies. +// UNSAFE-LINT EXEMPTION (rationale + exit criteria: `unsafe_op_in_unsafe_fn` in the workspace +// Cargo.toml). This body is raw ash/Vulkan object construction almost line for line; narrowing it +// would add one `unsafe {}` plus one SAFETY comment per call that could only restate the signature. +// Clearing this file means DELETING the markers that carry no caller contract, not wrapping the +// calls — until then the lint is off HERE and enforced everywhere else. +#![allow(unsafe_op_in_unsafe_fn)] + // Every unsafe block carries a `// SAFETY:` proof (parent module enforces it). use anyhow::Result; diff --git a/crates/pf-encode/src/enc/linux/vulkan_video.rs b/crates/pf-encode/src/enc/linux/vulkan_video.rs index 172a142f..7545f624 100644 --- a/crates/pf-encode/src/enc/linux/vulkan_video.rs +++ b/crates/pf-encode/src/enc/linux/vulkan_video.rs @@ -10,6 +10,12 @@ //! VAAPI instead). Proven end-to-end in `punktfunk-planning/design/vkenc-probe-harness`. //! Opt-in via `PUNKTFUNK_VULKAN_ENCODE`; gated to HEVC/AV1 + a device that advertises the encode op. //! The AV1 encode structs our pinned `ash 0.38` predates are vendored in `vk_av1_encode.rs`. +// UNSAFE-LINT EXEMPTION (rationale + exit criteria: `unsafe_op_in_unsafe_fn` in the workspace +// Cargo.toml). This body is raw ash/Vulkan Video calls against an app-owned DPB almost line for +// line; narrowing it would add one `unsafe {}` plus one SAFETY comment per call that could only +// restate the signature. Clearing this file means DELETING the markers that carry no caller +// contract, not wrapping the calls — until then the lint is off HERE and enforced everywhere else. +#![allow(unsafe_op_in_unsafe_fn)] #![allow(clippy::too_many_arguments)] use super::vk_util::{ diff --git a/crates/pf-encode/src/enc/nvenc_core.rs b/crates/pf-encode/src/enc/nvenc_core.rs index 3b2ba46b..31e51f84 100644 --- a/crates/pf-encode/src/enc/nvenc_core.rs +++ b/crates/pf-encode/src/enc/nvenc_core.rs @@ -5,6 +5,13 @@ //! `libloading`), the device binding (D3D11 vs CUDA), input-surface registration, and the //! Windows-only async retrieve — stay in their backends. Sibling of [`super::nvenc_status`]. +// UNSAFE-LINT EXEMPTION (rationale + exit criteria: `unsafe_op_in_unsafe_fn` in the workspace +// Cargo.toml). This body is raw `nvEncodeAPI` entry-table calls almost line for line; narrowing it +// would add one `unsafe {}` plus one SAFETY comment per call that could only restate the signature. +// Clearing this file means DELETING the markers that carry no caller contract, not wrapping the +// calls — until then the lint is off HERE and enforced everywhere else. +#![allow(unsafe_op_in_unsafe_fn)] + use super::Codec; use nvidia_video_codec_sdk::sys::nvEncodeAPI as nv; diff --git a/crates/pf-encode/src/enc/windows/amf.rs b/crates/pf-encode/src/enc/windows/amf.rs index 8f72cdf2..4ad8063c 100644 --- a/crates/pf-encode/src/enc/windows/amf.rs +++ b/crates/pf-encode/src/enc/windows/amf.rs @@ -43,6 +43,12 @@ //! fallback + `PUNKTFUNK_AMF_FFMPEG` hatch are gone). 4:4:4 is **permanently** out: VCN hardware //! does not encode 4:4:4. +// UNSAFE-LINT EXEMPTION (rationale + exit criteria: `unsafe_op_in_unsafe_fn` in the workspace +// Cargo.toml). This body is raw AMF COM-style vtable calls through `*mut AmfComponent` almost line +// for line; narrowing it would add one `unsafe {}` plus one SAFETY comment per call that could only +// restate the signature. Clearing this file means DELETING the markers that carry no caller +// contract, not wrapping the calls — until then the lint is off HERE and enforced everywhere else. +#![allow(unsafe_op_in_unsafe_fn)] // Every `unsafe` block / impl in this file carries a `// SAFETY:` proof; enforce it. #![deny(clippy::undocumented_unsafe_blocks)] diff --git a/crates/pf-encode/src/enc/windows/ffmpeg_win.rs b/crates/pf-encode/src/enc/windows/ffmpeg_win.rs index 21eca14a..2c269374 100644 --- a/crates/pf-encode/src/enc/windows/ffmpeg_win.rs +++ b/crates/pf-encode/src/enc/windows/ffmpeg_win.rs @@ -37,6 +37,13 @@ //! through `ffmpeg::ffi` (= `ffmpeg_sys_next`), exactly as the Linux CUDA/VAAPI paths do. The //! `AVD3D11VADeviceContext`/`AVD3D11VAFramesContext` layouts are mirrored (the bindings don't //! allowlist `hwcontext_d3d11va.h`), as [`super::linux`] mirrors `AVCUDADeviceContext`. +// UNSAFE-LINT EXEMPTION (rationale + exit criteria: `unsafe_op_in_unsafe_fn` in the workspace +// Cargo.toml). This body is raw libav (`ffmpeg-sys-next`) calls on borrowed hwcontext pointers +// almost line for line; narrowing it would add one `unsafe {}` plus one SAFETY comment per call +// that could only restate the signature. Clearing this file means DELETING the markers that carry +// no caller contract, not wrapping the calls — until then the lint is off HERE and enforced +// everywhere else. +#![allow(unsafe_op_in_unsafe_fn)] // Every `unsafe` block in this file carries a `// SAFETY:` proof; enforce it (unsafe-proof program). #![deny(clippy::undocumented_unsafe_blocks)] diff --git a/crates/pf-encode/src/enc/windows/nvenc.rs b/crates/pf-encode/src/enc/windows/nvenc.rs index 233a1743..e84227a7 100644 --- a/crates/pf-encode/src/enc/windows/nvenc.rs +++ b/crates/pf-encode/src/enc/windows/nvenc.rs @@ -33,6 +33,12 @@ //! AU completes within the same tick and `poll` picks it up); under contention completed frames //! queue instead of stalling capture — throughput recovers up to the scheduler-granted share. +// UNSAFE-LINT EXEMPTION (rationale + exit criteria: `unsafe_op_in_unsafe_fn` in the workspace +// Cargo.toml). This body is raw `nvEncodeAPI` entry-table + D3D11 calls almost line for line; +// narrowing it would add one `unsafe {}` plus one SAFETY comment per call that could only restate +// the signature. Clearing this file means DELETING the markers that carry no caller contract, not +// wrapping the calls — until then the lint is off HERE and enforced everywhere else. +#![allow(unsafe_op_in_unsafe_fn)] // Every `unsafe` block / impl in this file carries a `// SAFETY:` proof; enforce it. #![deny(clippy::undocumented_unsafe_blocks)] diff --git a/crates/pf-encode/src/enc/windows/pyrowave.rs b/crates/pf-encode/src/enc/windows/pyrowave.rs index 93fa079c..7a16f0d2 100644 --- a/crates/pf-encode/src/enc/windows/pyrowave.rs +++ b/crates/pf-encode/src/enc/windows/pyrowave.rs @@ -22,6 +22,13 @@ //! The capture side (a BGRA→YUV CSC into two shareable plane textures + a shared fence, gated on the //! pyrowave session flag) lives in `pf-capture` (`windows/idd_push.rs`); the CbCr plane + fence ride //! the frame on [`pf_frame::dxgi::D3d11Frame::pyro`], the Y plane on `D3d11Frame::texture`. +// UNSAFE-LINT EXEMPTION (rationale + exit criteria: `unsafe_op_in_unsafe_fn` in the workspace +// Cargo.toml). This body is `pyrowave-sys` C-API plus D3D11/Vulkan interop calls almost line for +// line; narrowing it would add one `unsafe {}` plus one SAFETY comment per call that could only +// restate the signature. Clearing this file means DELETING the markers that carry no caller +// contract, not wrapping the calls — until then the lint is off HERE and enforced everywhere else. +#![allow(unsafe_op_in_unsafe_fn)] + // Every `unsafe` block in this module carries a `// SAFETY:` proof (the crate root enforces it). use crate::pyrowave_wire; diff --git a/crates/punktfunk-host/src/windows/service.rs b/crates/punktfunk-host/src/windows/service.rs index d7c1ee62..ff53a499 100644 --- a/crates/punktfunk-host/src/windows/service.rs +++ b/crates/punktfunk-host/src/windows/service.rs @@ -658,11 +658,14 @@ unsafe fn spawn_host( // Take ownership of the process + thread handles the API filled into `pi`; the returned `Child` // closes BOTH on drop, so the supervise loop no longer hand-closes them in its match arms. - // SAFETY: `created` was `Ok`, so `pi` holds two distinct owned handles that nothing else closes; - // wrapping each transfers that ownership to an `OwnedHandle`, which closes it exactly once. + // SAFETY: `created` was `Ok`, so `pi.hProcess` is an owned handle nothing else closes; wrapping + // it transfers that ownership to the `OwnedHandle`, which closes it exactly once. + let process = unsafe { OwnedHandle::from_raw_handle(pi.hProcess.0) }; + // SAFETY: the same, for the distinct thread handle `CreateProcessAsUserW` filled in. + let thread = unsafe { OwnedHandle::from_raw_handle(pi.hThread.0) }; Ok(Child { - process: unsafe { OwnedHandle::from_raw_handle(pi.hProcess.0) }, - _thread: unsafe { OwnedHandle::from_raw_handle(pi.hThread.0) }, + process, + _thread: thread, pid: pi.dwProcessId, }) }