fix(format): overflow-checked sizes and fallible allocation on chunked reads
Dataspace and chunk dimensions are untrusted 64-bit fields, but the chunked read paths computed `num_elements() as usize * elem_size` and `chunk_dims.product() * elem_size` with plain arithmetic and fed the result to `vec![0u8; n]`. A crafted file could wrap the product (under-sizing the output buffer that chunks are then copied into) or request an allocation large enough to abort the process. - Dataspace::checked_num_elements, checked_byte_len, checked_chunk_byte_len and alloc_output (try_reserve_exact) replace the plain products and vec![0; n] at every chunked read site, plus the VDS and hyperslab paths. Overflow and allocation failure are FormatError::Overflow. - Dataspace::num_elements saturates instead of wrapping. - A zero-element dataset returns early, which also keeps the stride products in range when another dimension is huge. - parallel_read.rs: the three `c_addr + size > len` bounds checks used a raw add; they now use checked_add like the rest of the crate. Co-Authored-By: Claude Fable 5.1 <[email protected]>
This commit is contained in:
co-authored by
Claude Fable 5.1
parent
3ed0489faa
commit
6e84f31ed6
@@ -475,8 +475,10 @@ fn read_virtual_data(
|
||||
use crate::selection::Selection;
|
||||
|
||||
let elem_size = datatype.type_size() as usize;
|
||||
let total_elems = dataspace.num_elements() as usize;
|
||||
let mut out = vec![0u8; total_elems.saturating_mul(elem_size)];
|
||||
let mut out = crate::chunked_read::alloc_output(crate::chunked_read::checked_byte_len(
|
||||
dataspace.checked_num_elements()?,
|
||||
elem_size,
|
||||
)?)?;
|
||||
|
||||
let virtual_dims = &dataspace.dimensions;
|
||||
|
||||
@@ -616,12 +618,14 @@ fn extract_selection_from_buffer(
|
||||
block,
|
||||
} => {
|
||||
let rank = dims.len();
|
||||
let output_elements: usize = count
|
||||
let output_elements = count
|
||||
.iter()
|
||||
.zip(block.iter())
|
||||
.map(|(&c, &b)| (c * b) as usize)
|
||||
.product();
|
||||
let mut output = vec![0u8; output_elements * elem_size];
|
||||
.try_fold(1u64, |acc, (&c, &b)| acc.checked_mul(c.checked_mul(b)?))
|
||||
.ok_or_else(|| FormatError::Overflow("hyperslab count x block overflows".into()))?;
|
||||
let mut output = crate::chunked_read::alloc_output(
|
||||
crate::chunked_read::checked_byte_len(output_elements, elem_size)?,
|
||||
)?;
|
||||
|
||||
// Compute dataset strides (row-major)
|
||||
let mut ds_strides = vec![1usize; rank];
|
||||
|
||||
Reference in New Issue
Block a user