Audit round 1 fixes: sparse-track joins, silent drops, and two encoder wraps
A sparse passive track — a subtitle with no event near a clip's mark — was held to the dense-video crossing window, so it stayed on the previous clip's offset until its PTS passed that clip's OUT and every event in between was mistimed by the overlap. Video keeps the tight window, because its backward steps are also B-frame reorder; passive tracks have no reorder, so any backward step into the next clip's range is a join. Frames the marks exclude were dropped without a trace. Dropping is right at a join, but this codebase has shipped complete-looking wrong output before, so the count is kept per track and reported when the mux finishes, alongside the pre-cluster counter that exists for the same reason. A File Identifier Descriptor records its name length in one byte, and the length was narrowed with a cast: a 255-byte name — POSIX NAME_MAX, entirely ordinary — encodes to 256 and wrote zero, which would read every later entry in that directory from the wrong offset. A directory's link count is 16 bits and was computed as 1 + subdirectory count, which the global entry cap alone permits overflowing. Both are refused while planning, where the tree can still be rejected cleanly. The module and struct docs described inference as the whole algorithm; they now say which path decides what.
This commit is contained in:
+12
-1
@@ -493,6 +493,14 @@ fn push_fid(buf: &mut Vec<u8>, name: &str, icb_lba: u32, is_dir: bool, is_parent
|
||||
chars |= 0x08;
|
||||
}
|
||||
fid[18] = chars;
|
||||
// The planner refuses any name whose encoding exceeds what this byte can
|
||||
// hold (`layout::MAX_CS0_NAME_BYTES`), so this cannot wrap in practice. The
|
||||
// assert states the invariant where it is relied on rather than trusting a
|
||||
// check three files away; a wrap here would desynchronise the directory.
|
||||
debug_assert!(
|
||||
l_fi <= u8::MAX as usize,
|
||||
"FID name length must fit one byte"
|
||||
);
|
||||
fid[19] = l_fi as u8;
|
||||
put_long_ad(&mut fid[20..36], SECTOR as u32, icb_lba);
|
||||
fid[36..38].copy_from_slice(&0u16.to_le_bytes()); // length of implementation use
|
||||
@@ -590,7 +598,10 @@ fn write_dir(out: &mut MetaSectors, layout: &Layout, dir: &DirNode) -> Result<()
|
||||
|
||||
// A directory's link count is 1 (its own FID in the parent) plus one for
|
||||
// each child directory's parent FID pointing back at it.
|
||||
let link_count = 1 + dir.dirs.len() as u16;
|
||||
// The planner caps subdirectory fan-out (`layout::MAX_SUBDIRS`) so this
|
||||
// cannot overflow; saturating rather than wrapping keeps a future change to
|
||||
// that cap from silently producing a wrong count.
|
||||
let link_count = (dir.dirs.len() as u16).saturating_add(1);
|
||||
let fe = file_entry(
|
||||
true,
|
||||
fids.len() as u64,
|
||||
|
||||
Reference in New Issue
Block a user