From e9b771829246794a33574ed2a44e7f15567152c6 Mon Sep 17 00:00:00 2001 From: Fabian Loeschner Date: Tue, 9 Nov 2021 14:07:57 +0100 Subject: [PATCH] Fix panic in SparsityPattern::try_from_* if major index is out of bounds --- nalgebra-sparse/src/csc.rs | 3 +++ nalgebra-sparse/src/csr.rs | 3 +++ nalgebra-sparse/src/pattern.rs | 11 +++++++++-- nalgebra-sparse/tests/serde.rs | 7 +++---- nalgebra-sparse/tests/unit_tests/pattern.rs | 11 +++++++++++ 5 files changed, 29 insertions(+), 6 deletions(-) diff --git a/nalgebra-sparse/src/csc.rs b/nalgebra-sparse/src/csc.rs index fccc6146..e6eb1589 100644 --- a/nalgebra-sparse/src/csc.rs +++ b/nalgebra-sparse/src/csc.rs @@ -606,6 +606,9 @@ fn pattern_format_error_to_csc_error(err: SparsityPatternFormatError) -> SparseF K::InvalidStructure, "Row indices are not monotonically increasing (sorted) within each column.", ), + MajorIndexOutOfBounds => { + E::from_kind_and_msg(K::IndexOutOfBounds, "Column indices are out of bounds.") + } MinorIndexOutOfBounds => { E::from_kind_and_msg(K::IndexOutOfBounds, "Row indices are out of bounds.") } diff --git a/nalgebra-sparse/src/csr.rs b/nalgebra-sparse/src/csr.rs index 31375340..7bd996da 100644 --- a/nalgebra-sparse/src/csr.rs +++ b/nalgebra-sparse/src/csr.rs @@ -677,6 +677,9 @@ fn pattern_format_error_to_csr_error(err: SparsityPatternFormatError) -> SparseF K::InvalidStructure, "Column indices are not monotonically increasing (sorted) within each row.", ), + MajorIndexOutOfBounds => { + E::from_kind_and_msg(K::IndexOutOfBounds, "Row indices are out of bounds.") + } MinorIndexOutOfBounds => { E::from_kind_and_msg(K::IndexOutOfBounds, "Column indices are out of bounds.") } diff --git a/nalgebra-sparse/src/pattern.rs b/nalgebra-sparse/src/pattern.rs index 4243543d..1f9dde84 100644 --- a/nalgebra-sparse/src/pattern.rs +++ b/nalgebra-sparse/src/pattern.rs @@ -156,7 +156,9 @@ impl SparsityPattern { return Err(NonmonotonicOffsets); } - let minor_indices = &minor_indices[range_start..range_end]; + let minor_indices = minor_indices + .get(range_start..range_end) + .ok_or(MajorIndexOutOfBounds)?; // We test for in-bounds, uniqueness and monotonicity at the same time // to ensure that we only visit each minor index once @@ -277,6 +279,8 @@ pub enum SparsityPatternFormatError { InvalidOffsetFirstLast, /// Indicates that the major offsets are not monotonically increasing. NonmonotonicOffsets, + /// One or more major indices are out of bounds. + MajorIndexOutOfBounds, /// One or more minor indices are out of bounds. MinorIndexOutOfBounds, /// One or more duplicate entries were detected. @@ -349,7 +353,7 @@ impl From for SparseFormatError { | NonmonotonicMinorIndices => { SparseFormatError::from_kind_and_error(InvalidStructure, Box::from(err)) } - MinorIndexOutOfBounds => { + MajorIndexOutOfBounds | MinorIndexOutOfBounds => { SparseFormatError::from_kind_and_error(IndexOutOfBounds, Box::from(err)) } PatternDuplicateEntry => SparseFormatError::from_kind_and_error( @@ -373,6 +377,9 @@ impl fmt::Display for SparsityPatternFormatError { SparsityPatternFormatError::NonmonotonicOffsets => { write!(f, "Offsets are not monotonically increasing.") } + SparsityPatternFormatError::MajorIndexOutOfBounds => { + write!(f, "A major index is out of bounds.") + } SparsityPatternFormatError::MinorIndexOutOfBounds => { write!(f, "A minor index is out of bounds.") } diff --git a/nalgebra-sparse/tests/serde.rs b/nalgebra-sparse/tests/serde.rs index 1ce1953f..7842fd1e 100644 --- a/nalgebra-sparse/tests/serde.rs +++ b/nalgebra-sparse/tests/serde.rs @@ -58,6 +58,7 @@ fn pattern_deserialize_invalid() { assert!(serde_json::from_str::(r#"{"major_dim":3,"minor_dim":6,"major_offsets":[0, 2, 2, 5],"minor_indices":[0, 2, 3, 1, 4]}"#).is_err()); assert!(serde_json::from_str::(r#"{"major_dim":3,"minor_dim":6,"major_offsets":[0, 2, 2, 5],"minor_indices":[0, 6, 1, 2, 3]}"#).is_err()); assert!(serde_json::from_str::(r#"{"major_dim":3,"minor_dim":6,"major_offsets":[0, 2, 2, 5],"minor_indices":[0, 5, 2, 2, 3]}"#).is_err()); + assert!(serde_json::from_str::(r#"{"major_dim":3,"minor_dim":6,"major_offsets":[0, 10, 2, 5],"minor_indices":[0, 5, 1, 2, 3]}"#).is_err()); } #[test] @@ -148,8 +149,7 @@ fn csc_deserialize_invalid() { assert!(serde_json::from_str::>(r#"{"nrows":6,"ncols":3,"col_offsets":[0,2,2,5],"row_indices":[0,5,1,2,3],"values":[0,1,2,3,4,5]}"#).is_err()); assert!(serde_json::from_str::>(r#"{"nrows":6,"ncols":3,"col_offsets":[0,2,2,5],"row_indices":[0,5,1,8,3],"values":[0,1,2,3,4]}"#).is_err()); assert!(serde_json::from_str::>(r#"{"nrows":6,"ncols":3,"col_offsets":[0,2,2,5],"row_indices":[0,5,1,2,3,1,1],"values":[0,1,2,3,4]}"#).is_err()); - // The following actually panics ('range end index 10 out of range for slice of length 5', nalgebra-sparse\src\pattern.rs:156:38) - //assert!(serde_json::from_str::>(r#"{"nrows":6,"ncols":3,"col_offsets":[0,10,2,5],"row_indices":[0,5,1,2,3],"values":[0,1,2,3,4]}"#).is_err()); + assert!(serde_json::from_str::>(r#"{"nrows":6,"ncols":3,"col_offsets":[0,10,2,5],"row_indices":[0,5,1,2,3],"values":[0,1,2,3,4]}"#).is_err()); assert!(serde_json::from_str::>(r#"{"nrows":3,"ncols":6,"row_offsets":[0,2,2,5],"col_indices":[0,5,1,2,3],"values":[0,1,2,3,4]}"#).is_err()); } @@ -188,8 +188,7 @@ fn csr_deserialize_invalid() { assert!(serde_json::from_str::>(r#"{"nrows":3,"ncols":6,"row_offsets":[0,2,2,5],"col_indices":[0,5,1,2,3],"values":[0,1,2,3,4,5]}"#).is_err()); assert!(serde_json::from_str::>(r#"{"nrows":3,"ncols":6,"row_offsets":[0,2,2,5],"col_indices":[0,5,1,8,3],"values":[0,1,2,3,4]}"#).is_err()); assert!(serde_json::from_str::>(r#"{"nrows":3,"ncols":6,"row_offsets":[0,2,2,5],"col_indices":[0,5,1,2,3,1,1],"values":[0,1,2,3,4]}"#).is_err()); - // The following actually panics ('range end index 10 out of range for slice of length 5', nalgebra-sparse\src\pattern.rs:156:38) - //assert!(serde_json::from_str::>(r#"{"nrows":3,"ncols":6,"row_offsets":[0,10,2,5],"col_indices":[0,5,1,2,3],"values":[0,1,2,3,4]}"#).is_err()); + assert!(serde_json::from_str::>(r#"{"nrows":3,"ncols":6,"row_offsets":[0,10,2,5],"col_indices":[0,5,1,2,3],"values":[0,1,2,3,4]}"#).is_err()); assert!(serde_json::from_str::>(r#"{"nrows":6,"ncols":3,"col_offsets":[0,2,2,5],"row_indices":[0,5,1,2,3],"values":[0,1,2,3,4]}"#).is_err()); } diff --git a/nalgebra-sparse/tests/unit_tests/pattern.rs b/nalgebra-sparse/tests/unit_tests/pattern.rs index 310cffae..e2706ee5 100644 --- a/nalgebra-sparse/tests/unit_tests/pattern.rs +++ b/nalgebra-sparse/tests/unit_tests/pattern.rs @@ -133,6 +133,17 @@ fn sparsity_pattern_try_from_invalid_data() { ); } + { + // Major index out of bounds + let offsets = vec![0, 10, 2, 5]; + let indices = vec![0, 1, 2, 3, 4]; + let pattern = SparsityPattern::try_from_offsets_and_indices(3, 6, offsets, indices); + assert_eq!( + pattern, + Err(SparsityPatternFormatError::MajorIndexOutOfBounds) + ); + } + { // Minor index out of bounds let offsets = vec![0, 2, 2, 5];