Round 4: fix 26 defects across crypto, resource use and codec paths

Twenty-six confirmed findings from the fourth audit round, landed as one
cluster because they were found by agents working over disjoint file sets.

The one worth calling out is a pair of AACS tests that could not fail.
Both asserted CBC behaviour against a hand-rolled expectation that
happened to be IV-independent, so replacing AACS_IV with sixteen zero
bytes left them passing — they were pinning the code's own arithmetic,
not the published constant. Replaced with a literal witness of the
published IV plus the NIST SP 800-38A F.2.2 CBC-AES128 vector, and
verified the other way round: zeroing AACS_IV now fails three tests.

The rest are allocation and correctness work on hot paths: the Annex-B
writer in demux_sink allocated and freed a whole-frame Vec per frame,
which for a UHD title is ~200,000 allocations over the mmap threshold
plus the page faults to first-touch each one; it now reuses a buffer on
the writer, and still takes the NAL prefix width from the configuration
record rather than assuming four.

Six findings whose real fix lives in a consumer crate are recorded for
re-filing rather than patched here.
This commit is contained in:
Matthew Jackson
2026-07-29 22:09:52 -07:00
parent 4fcd28b487
commit 0bbceed985
19 changed files with 1342 additions and 126 deletions
+4 -1
View File
@@ -125,7 +125,10 @@ fn consumer_panicked(payload: Box<dyn std::any::Any + Send>) -> Error {
/// caller reporting the rip as interrupted while a fully finalised MKV (Cues
/// written, Segment size patched) landed on disk, indistinguishable from a
/// complete one. The two transitions are therefore a single compare-exchange each,
/// out of [`ST_RUNNING`]: whoever wins decides, and the loser observes the winner.
/// out of [`state::RUNNING`]: whoever wins decides, and the loser observes the
/// winner. (`ST_RUNNING` does not exist anywhere in the crate — the constants are
/// `state::RUNNING` / `state::ABANDONED` / `state::CLOSING` below, and both
/// compare-exchange sites that must stay in step with this argument name them.)
mod state {
/// Consumer is running; neither side has committed yet.
pub const RUNNING: u8 = 0;
+20 -2
View File
@@ -112,8 +112,26 @@ pub(super) fn durable_sync(file: &File) -> io::Result<()> {
);
Ok(())
}
Err(crate::io::bounded::BoundedError::Halted) => Ok(()),
Err(crate::io::bounded::BoundedError::WorkerLost) => Ok(()),
// Both arms below used to map to `Ok(())` with NO diagnostic at all, while
// the Linux sibling logs the identical failures (writeback_file/linux.rs).
// A lost F_FULLFSYNC worker at the end of a UHD mux therefore reported
// `completed = true` with an empty log, leaving an operator investigating a
// truncated/corrupt output file after a power loss no record that the final
// fsync never ran — on Linux the same failure is at error level.
Err(crate::io::bounded::BoundedError::Halted) => {
tracing::warn!(
target: "mux",
"WritebackFile::sync_all F_FULLFSYNC skipped (halt requested); data not durably flushed, kernel will flush on close"
);
Ok(())
}
Err(crate::io::bounded::BoundedError::WorkerLost) => {
tracing::error!(
target: "mux",
"WritebackFile::sync_all F_FULLFSYNC worker lost before completion; data not durably flushed, kernel will flush on close"
);
Ok(())
}
}
}