Skip to content

Commit 06ecc68

Browse files
committed
Revert to opaque error type
1 parent 153f622 commit 06ecc68

5 files changed

Lines changed: 36 additions & 26 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
- v0.28.0
33
- Fix mismatched behavior between `PyArrayLike1` and `PyArrayLike2` when used with floats ([#520](https://github.com/PyO3/rust-numpy/pull/520))
44
- Add ownership-moving conversions into `PyReadonlyArray` and `PyReadwriteArray` ([#524](https://github.com/PyO3/rust-numpy/pull/524))
5+
- Fix UB when calling `PyArray::as_slice` and `as_slice_mut` on misaligned arrays ([#525](https://github.com/PyO3/rust-numpy/pull/525))
56

67
- v0.27.1
78
- Bump ndarray dependency to v0.17. ([#516](https://github.com/PyO3/rust-numpy/pull/516))

src/array.rs

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -749,12 +749,10 @@ pub trait PyArrayMethods<'py, T, D>: PyUntypedArrayMethods<'py> + Sized {
749749
// We can still produce a slice over zero objects regardless of whether
750750
// the underlying pointer is aligned or not.
751751
Ok(&[])
752-
} else if !self.is_aligned() {
753-
Err(AsSliceError::NotAligned)
754-
} else if !self.is_contiguous() {
755-
Err(AsSliceError::NotContiguous)
756-
} else {
752+
} else if self.is_aligned() && self.is_contiguous() {
757753
Ok(slice::from_raw_parts(self.data(), len))
754+
} else {
755+
Err(AsSliceError)
758756
}
759757
}
760758

@@ -778,12 +776,10 @@ pub trait PyArrayMethods<'py, T, D>: PyUntypedArrayMethods<'py> + Sized {
778776
// We can still produce a slice over zero objects regardless of whether
779777
// the underlying pointer is aligned or not.
780778
Ok(&mut [])
781-
} else if !self.is_aligned() {
782-
Err(AsSliceError::NotAligned)
783-
} else if !self.is_contiguous() {
784-
Err(AsSliceError::NotContiguous)
785-
} else {
779+
} else if self.is_aligned() && self.is_contiguous() {
786780
Ok(slice::from_raw_parts_mut(self.data(), len))
781+
} else {
782+
Err(AsSliceError)
787783
}
788784
}
789785

src/error.rs

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -142,25 +142,13 @@ impl fmt::Display for FromVecError {
142142
impl_pyerr!(FromVecError);
143143

144144
/// Represents that the given array is not compatible with viewing as a Rust slice.
145-
///
146-
/// If an array fails for more than one reason, it is not guaranteed which variant is returned.
147145
#[derive(Debug)]
148-
pub enum AsSliceError {
149-
/// The array is not backed by an aligned pointer.
150-
NotAligned,
151-
/// The array is not contiguous in memory.
152-
NotContiguous,
153-
}
154-
146+
pub struct AsSliceError;
155147
impl fmt::Display for AsSliceError {
156148
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
157-
match self {
158-
Self::NotAligned => write!(f, "The given array is not aligned"),
159-
Self::NotContiguous => write!(f, "The given array is not contiguous"),
160-
}
149+
write!(f, "The given array is not contiguous or is misaligned.")
161150
}
162151
}
163-
164152
impl_pyerr!(AsSliceError);
165153

166154
/// Inidcates why borrowing an array failed.

src/lib.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,11 @@ pub mod prelude {
130130
pub use crate::untyped_array::PyUntypedArrayMethods;
131131
}
132132

133+
/// Deprecated type alias to [`AsSliceError`]. The new name is preferred because arrays might also
134+
/// fail to view as a slice due to misalignment.
135+
#[deprecated(note = "use AsSliceError instead")]
136+
pub type NonContiguousError = AsSliceError;
137+
133138
#[cfg(doctest)]
134139
mod doctest {
135140
macro_rules! doc_comment {

tests/array.rs

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -192,12 +192,28 @@ fn as_slice() {
192192

193193
let not_contiguous = not_contiguous_array(py);
194194
let err = not_contiguous.readonly().as_slice().unwrap_err();
195-
assert_eq!(err.to_string(), "The given array is not contiguous");
195+
assert_eq!(
196+
err.to_string(),
197+
"The given array is not contiguous or is misaligned."
198+
);
199+
let err = not_contiguous.readwrite().as_slice_mut().unwrap_err();
200+
assert_eq!(
201+
err.to_string(),
202+
"The given array is not contiguous or is misaligned."
203+
);
196204

197205
let not_aligned = not_aligned_array(py);
198206
assert!(!not_aligned.is_aligned());
199207
let err = not_aligned.readonly().as_slice().unwrap_err();
200-
assert_eq!(err.to_string(), "The given array is not aligned");
208+
assert_eq!(
209+
err.to_string(),
210+
"The given array is not contiguous or is misaligned."
211+
);
212+
let err = not_aligned.readwrite().as_slice_mut().unwrap_err();
213+
assert_eq!(
214+
err.to_string(),
215+
"The given array is not contiguous or is misaligned."
216+
);
201217

202218
let misaligned_empty: Bound<'_, PyArray1<u16>> = {
203219
let arr = not_aligned_array(py);
@@ -214,6 +230,10 @@ fn as_slice() {
214230
misaligned_empty.readonly().as_slice().unwrap(),
215231
&[] as &[u16]
216232
);
233+
assert_eq!(
234+
misaligned_empty.readwrite().as_slice().unwrap(),
235+
&mut [] as &mut [u16]
236+
);
217237
});
218238
}
219239

0 commit comments

Comments
 (0)