chore(safety): three unsafe-hygiene grep gates, blocking in ci.yml (WP2c gates)
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 (db659809found 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) — the972af299environ 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.
This commit is contained in:
@@ -176,7 +176,13 @@ unsafe extern "system" fn wnd_proc(
|
||||
let slice = unsafe { std::slice::from_raw_parts(cds.lpData as *const u16, len) };
|
||||
let url = String::from_utf16_lossy(slice);
|
||||
tracing::debug!(%url, "link from another instance");
|
||||
INBOX.lock().unwrap().push(url);
|
||||
// Poison-recover, never unwrap: a panic out of a window procedure is an abort since
|
||||
// Rust 1.81, and the inbox is a plain Vec that stays valid whatever a poisoned
|
||||
// writer left behind.
|
||||
INBOX
|
||||
.lock()
|
||||
.unwrap_or_else(std::sync::PoisonError::into_inner)
|
||||
.push(url);
|
||||
return LRESULT(1);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user