Skip to content

Commit 7e45551

Browse files
HEnquistclaude
andcommitted
Fix out-of-bounds read on short final chunk; harden example file read
Address two review findings: - Slip::process_into_buffer copied `input_len`/`output_len` frames from the input buffer, but validate_buffers only guarantees `frames_to_read` frames are present. On a short final chunk (Indexing::partial_len set) that read past the validated region. Copy only `frames_to_read` frames; the remainder of the scratch is already zero-padded. - The adjust_ratio_f64 example read samples with Read::read, which may return a short read and decode a corrupt trailing sample from leftover bytes. Use read_exact and stop on UnexpectedEof. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent e3fc87c commit 7e45551

2 files changed

Lines changed: 13 additions & 8 deletions

File tree

examples/adjust_ratio_f64.rs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,15 @@ fn read_file<R: Read + Seek>(inbuffer: &mut R) -> Vec<f64> {
4040
let mut buffer = vec![0u8; BYTE_PER_SAMPLE];
4141
let mut data = Vec::new();
4242
loop {
43-
let bytes_read = inbuffer.read(&mut buffer).unwrap();
44-
if bytes_read == 0 {
45-
break;
43+
match inbuffer.read_exact(&mut buffer) {
44+
Ok(()) => {
45+
let value = f64::from_le_bytes(buffer.as_slice().try_into().unwrap());
46+
data.push(value);
47+
}
48+
// A clean end of file stops the loop; a partial trailing read means a malformed file.
49+
Err(e) if e.kind() == std::io::ErrorKind::UnexpectedEof => break,
50+
Err(e) => panic!("Error reading input file: {}", e),
4651
}
47-
let value = f64::from_le_bytes(buffer.as_slice().try_into().unwrap());
48-
data.push(value);
4952
}
5053
data
5154
}

src/slip.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -413,11 +413,12 @@ where
413413
}
414414
if self.correction == 0 {
415415
// No slip this chunk: read straight into the output scratch, skipping the
416-
// input scratch and the redundant scratch-to-scratch copy.
416+
// input scratch and the redundant scratch-to-scratch copy. Only `frames_to_read`
417+
// frames are guaranteed present in `buffer_in` (see `validate_buffers`).
417418
buffer_in.copy_from_channel_to_slice(
418419
chan,
419420
input_offset,
420-
&mut self.output_scratch[..output_len],
421+
&mut self.output_scratch[..frames_to_read],
421422
);
422423
// Zero pad if this is a short final chunk.
423424
if frames_to_read < output_len {
@@ -426,10 +427,11 @@ where
426427
}
427428
}
428429
} else {
430+
// Only `frames_to_read` frames are guaranteed present in `buffer_in`.
429431
buffer_in.copy_from_channel_to_slice(
430432
chan,
431433
input_offset,
432-
&mut self.input_scratch[..input_len],
434+
&mut self.input_scratch[..frames_to_read],
433435
);
434436
// Zero pad if this is a short final chunk.
435437
if frames_to_read < input_len {

0 commit comments

Comments
 (0)