Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

63 changes: 55 additions & 8 deletions crates/pecos-decoder-core/src/dem.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,17 @@

use crate::errors::DecoderError;

fn dimension_count(max_index: Option<u32>, kind: &str) -> Result<usize, DecoderError> {
max_index.map_or(Ok(0), |index| {
let count = u64::from(index) + 1;
usize::try_from(count).map_err(|_| {
DecoderError::InvalidConfiguration(format!(
"{kind} count for index {index} does not fit usize on this platform"
))
})
})
}

/// Trait for decoders that can be constructed from detector error models
pub trait DemDecoder: super::Decoder {
/// Configuration type for DEM construction
Expand Down Expand Up @@ -173,8 +184,20 @@ pub mod utils {
}
}

let detector_count = max_detector.map_or(0, |m| m + 1);
let observable_count = max_observable.map_or(0, |m| m + 1);
let detector_count = max_detector.map_or(Ok(0), |index| {
index.checked_add(1).ok_or_else(|| {
DecoderError::InvalidConfiguration(format!(
"detector count for index {index} does not fit usize on this platform"
))
})
})?;
let observable_count = max_observable.map_or(Ok(0), |index| {
index.checked_add(1).ok_or_else(|| {
DecoderError::InvalidConfiguration(format!(
"observable count for index {index} does not fit usize on this platform"
))
})
})?;

Ok((detector_count, observable_count))
}
Expand Down Expand Up @@ -398,8 +421,8 @@ impl SparseDem {
Ok(Self {
mechanisms,
detector_coords,
num_detectors: max_detector.map_or(0, |m| m as usize + 1),
num_observables: max_observable.map_or(0, |m| m as usize + 1),
num_detectors: dimension_count(max_detector, "detector")?,
num_observables: dimension_count(max_observable, "observable")?,
})
}
}
Expand Down Expand Up @@ -552,8 +575,8 @@ impl DemCheckMatrix {
mechanisms.push((probability, detectors, observables));
}

let num_detectors = max_detector.map_or(0, |m| m as usize + 1);
let num_observables = max_observable.map_or(0, |m| m as usize + 1);
let num_detectors = dimension_count(max_detector, "detector")?;
let num_observables = dimension_count(max_observable, "observable")?;
let num_mechanisms = mechanisms.len();

// Build matrices.
Expand Down Expand Up @@ -839,8 +862,8 @@ impl DemMatchingGraph {
fault_id += 1;
}

let num_detectors = max_detector.map_or(0, |m| m as usize + 1);
let num_observables = max_observable.map_or(0, |m| m as usize + 1);
let num_detectors = dimension_count(max_detector, "detector")?;
let num_observables = dimension_count(max_observable, "observable")?;

let edges = Self::merge_parallel_edges(edges);

Expand Down Expand Up @@ -1262,6 +1285,30 @@ mod tests {
assert_eq!(dets, 8, "parse_dem_metadata must count bare detector D7");
}

#[test]
fn sparse_dem_max_u32_detector_index_is_platform_checked() {
let dem = "error(0.01) D4294967295\n";
let parsed = SparseDem::from_dem_str(dem);

#[cfg(target_pointer_width = "64")]
{
assert_eq!(parsed.unwrap().num_detectors, 4_294_967_296);
assert_eq!(utils::parse_dem_metadata(dem).unwrap().0, 4_294_967_296);
}

#[cfg(target_pointer_width = "32")]
{
// On 32-bit targets, the promoted u64 count reaches the fallible
// usize::try_from branch instead of wrapping or panicking.
let error = parsed.unwrap_err();
assert!(matches!(error, DecoderError::InvalidConfiguration(_)));
assert!(error.to_string().contains("4294967295"));

let metadata_error = utils::parse_dem_metadata(dem).unwrap_err();
assert!(metadata_error.to_string().contains("4294967295"));
}
}

#[test]
fn test_parsers_reject_malformed_detector_token() {
// A `D<bad>` / `L<bad>` token in an error line is malformed. All three
Expand Down
1 change: 1 addition & 0 deletions python/pecos-rslib/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ nalgebra.workspace = true
num-complex.workspace = true
parking_lot.workspace = true
serde_json.workspace = true
sha2.workspace = true
tempfile.workspace = true
log.workspace = true
libc.workspace = true
Expand Down
Loading
Loading