#1429: MPEG-1 program stream cut inside a pack header no longer panics
Problem: packet_len accepted an MPEG-1 pack header (b[4]>>4==2) with only 6 bytes available, but scan reads the SCR from head[4..9]. A file ending inside the last pack header (00 00 01 BA 21 00 00) panicked with "range end index 9 out of range". Fix: packet_len requires the full 12-byte MPEG-1 pack header; a shorter tail is not a packet and takes the normal resync path. The MPEG-2 branch already needs 14 bytes (b.get(13)) before scan reads 10, so it is fine. Tests: truncate a valid MPEG-1 and MPEG-2 program stream at every byte length, plus the minimal 7-byte input; both panicked before the fix. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
71438c627b
commit
cf9ad66732
|
|
@ -94,6 +94,9 @@ fn packet_len(b: &[u8]) -> Option<usize> {
|
|||
let stuff = (*b.get(13)? & 7) as usize;
|
||||
Some(14 + stuff)
|
||||
} else if b[4] >> 4 == 2 {
|
||||
// MPEG-1 pack header: start code, 5-byte SCR, 3-byte mux rate. A file cut inside
|
||||
// it is not a pack header yet (`scan` reads the SCR from the first 9 bytes).
|
||||
b.get(..12)?;
|
||||
Some(12)
|
||||
} else {
|
||||
None
|
||||
|
|
|
|||
|
|
@ -276,6 +276,50 @@ fn truncation_and_mutation_never_panic() {
|
|||
}
|
||||
}
|
||||
|
||||
/// Opens `data` and reads every unit; errors are fine, panics are not.
|
||||
fn open_and_read_all(data: &[u8]) {
|
||||
let data = data.to_vec();
|
||||
if let Ok(f) = open(&data) {
|
||||
for (s, st) in f.streams.iter().enumerate() {
|
||||
for i in 0..st.units.len() {
|
||||
let _ = f.read_unit(&data, s, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn program_stream_cut_inside_a_pack_header_never_panics() {
|
||||
// MPEG-1 pack header cut after the 4-byte start code + 3 bytes (once panicked in `scan`).
|
||||
open_and_read_all(&[0, 0, 1, 0xBA, 0x21, 0, 0]);
|
||||
for n in 4..=12 {
|
||||
let mpeg1 = [0u8, 0, 1, 0xBA, 0x21, 0, 1, 0, 1, 0x80, 0, 1];
|
||||
open_and_read_all(&mpeg1[..n]);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn program_stream_truncation_at_every_length_never_panics() {
|
||||
let frames: Vec<Vec<u8>> = (0..3).map(|k| mpeg2_frame(if k == 0 { 1 } else { 2 }, k as u16, false, 300)).collect();
|
||||
let es: Vec<u8> = frames.concat();
|
||||
for mpeg1 in [false, true] {
|
||||
let mut out = Vec::new();
|
||||
for (k, chunk) in es.chunks(500).enumerate() {
|
||||
if mpeg1 {
|
||||
out.extend([0, 0, 1, 0xBA, 0x21, 0, 1, 0, 1, 0x80, 0, 1]);
|
||||
} else {
|
||||
out.extend([0, 0, 1, 0xBA, 0x44, 0, 4, 0, 4, 1, 1, 0x89, 0xC3, 0xF8]);
|
||||
}
|
||||
out.extend(pes(0xE0, Some(3600 * k as i64), None, chunk, true));
|
||||
}
|
||||
out.extend([0, 0, 1, 0xB9]);
|
||||
assert!(open(&out).is_ok(), "the untruncated stream opens (mpeg1: {mpeg1})");
|
||||
for cut in 0..=out.len() {
|
||||
open_and_read_all(&out[..cut]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn timestamps_unwrap_across_the_33_bit_wrap() {
|
||||
let mut u = Unwrap::default();
|
||||
|
|
|
|||
Loading…
Reference in New Issue