Skip to content

Commit 6b38810

Browse files
jturner314bluss
authored andcommitted
Remove alignment restriction on RawArrayView/Mut
1 parent ecb7643 commit 6b38810

File tree

3 files changed

+53
-54
lines changed

3 files changed

+53
-54
lines changed

src/impl_raw_views.rs

+22-21
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,8 @@ where
3333
///
3434
/// Unsafe because caller is responsible for ensuring all of the following:
3535
///
36-
/// * `ptr` must be non-null and aligned, and it must be safe to
37-
/// [`.offset()`] `ptr` by zero.
36+
/// * `ptr` must be non-null, and it must be safe to [`.offset()`] `ptr` by
37+
/// zero.
3838
///
3939
/// * It must be safe to [`.offset()`] the pointer repeatedly along all
4040
/// axes and calculate the `count`s for the `.offset()` calls without
@@ -70,7 +70,6 @@ where
7070
let strides = shape.strides;
7171
if cfg!(debug_assertions) {
7272
assert!(!ptr.is_null(), "The pointer must be non-null.");
73-
assert!(is_aligned(ptr), "The pointer must be aligned.");
7473
dimension::max_abs_offset_check_overflow::<A, _>(&dim, &strides).unwrap();
7574
}
7675
RawArrayView::new_(ptr, dim, strides)
@@ -80,9 +79,14 @@ where
8079
///
8180
/// **Warning** from a safety standpoint, this is equivalent to
8281
/// dereferencing a raw pointer for every element in the array. You must
83-
/// ensure that all of the data is valid and choose the correct lifetime.
82+
/// ensure that all of the data is valid, ensure that the pointer is
83+
/// aligned, and choose the correct lifetime.
8484
#[inline]
8585
pub unsafe fn deref_into_view<'a>(self) -> ArrayView<'a, A, D> {
86+
debug_assert!(
87+
is_aligned(self.ptr.as_ptr()),
88+
"The pointer must be aligned."
89+
);
8690
ArrayView::new(self.ptr, self.dim, self.strides)
8791
}
8892

@@ -130,12 +134,6 @@ where
130134
"size mismatch in raw view cast"
131135
);
132136
let ptr = self.ptr.cast::<B>();
133-
debug_assert!(
134-
is_aligned(ptr.as_ptr()),
135-
"alignment mismatch in raw view cast"
136-
);
137-
/* Alignment checked with debug assertion: alignment could be dynamically correct,
138-
* and we don't have a check that compiles out for that. */
139137
unsafe { RawArrayView::new(ptr, self.dim, self.strides) }
140138
}
141139
}
@@ -167,8 +165,8 @@ where
167165
///
168166
/// Unsafe because caller is responsible for ensuring all of the following:
169167
///
170-
/// * `ptr` must be non-null and aligned, and it must be safe to
171-
/// [`.offset()`] `ptr` by zero.
168+
/// * `ptr` must be non-null, and it must be safe to [`.offset()`] `ptr` by
169+
/// zero.
172170
///
173171
/// * It must be safe to [`.offset()`] the pointer repeatedly along all
174172
/// axes and calculate the `count`s for the `.offset()` calls without
@@ -204,7 +202,6 @@ where
204202
let strides = shape.strides;
205203
if cfg!(debug_assertions) {
206204
assert!(!ptr.is_null(), "The pointer must be non-null.");
207-
assert!(is_aligned(ptr), "The pointer must be aligned.");
208205
dimension::max_abs_offset_check_overflow::<A, _>(&dim, &strides).unwrap();
209206
}
210207
RawArrayViewMut::new_(ptr, dim, strides)
@@ -220,19 +217,29 @@ where
220217
///
221218
/// **Warning** from a safety standpoint, this is equivalent to
222219
/// dereferencing a raw pointer for every element in the array. You must
223-
/// ensure that all of the data is valid and choose the correct lifetime.
220+
/// ensure that all of the data is valid, ensure that the pointer is
221+
/// aligned, and choose the correct lifetime.
224222
#[inline]
225223
pub unsafe fn deref_into_view<'a>(self) -> ArrayView<'a, A, D> {
224+
debug_assert!(
225+
is_aligned(self.ptr.as_ptr()),
226+
"The pointer must be aligned."
227+
);
226228
ArrayView::new(self.ptr, self.dim, self.strides)
227229
}
228230

229231
/// Converts to a mutable view of the array.
230232
///
231233
/// **Warning** from a safety standpoint, this is equivalent to
232234
/// dereferencing a raw pointer for every element in the array. You must
233-
/// ensure that all of the data is valid and choose the correct lifetime.
235+
/// ensure that all of the data is valid, ensure that the pointer is
236+
/// aligned, and choose the correct lifetime.
234237
#[inline]
235238
pub unsafe fn deref_into_view_mut<'a>(self) -> ArrayViewMut<'a, A, D> {
239+
debug_assert!(
240+
is_aligned(self.ptr.as_ptr()),
241+
"The pointer must be aligned."
242+
);
236243
ArrayViewMut::new(self.ptr, self.dim, self.strides)
237244
}
238245

@@ -267,12 +274,6 @@ where
267274
"size mismatch in raw view cast"
268275
);
269276
let ptr = self.ptr.cast::<B>();
270-
debug_assert!(
271-
is_aligned(ptr.as_ptr()),
272-
"alignment mismatch in raw view cast"
273-
);
274-
/* Alignment checked with debug assertion: alignment could be dynamically correct,
275-
* and we don't have a check that compiles out for that. */
276277
unsafe { RawArrayViewMut::new(ptr, self.dim, self.strides) }
277278
}
278279
}

src/lib.rs

+11-10
Original file line numberDiff line numberDiff line change
@@ -1106,10 +1106,12 @@ pub type Ixs = isize;
11061106
// `dim`, and `strides` must be exclusively borrowed and not aliased by
11071107
// multiple indices.
11081108
//
1109-
// 2. `ptr` must be non-null and aligned, and it must be safe to [`.offset()`]
1110-
// `ptr` by zero.
1109+
// 2. If the type of `data` implements `Data`, then `ptr` must be aligned.
11111110
//
1112-
// 3. It must be safe to [`.offset()`] the pointer repeatedly along all axes
1111+
// 3. `ptr` must be non-null, and it must be safe to [`.offset()`] `ptr` by
1112+
// zero.
1113+
//
1114+
// 4. It must be safe to [`.offset()`] the pointer repeatedly along all axes
11131115
// and calculate the `count`s for the `.offset()` calls without overflow,
11141116
// even if the array is empty or the elements are zero-sized.
11151117
//
@@ -1177,13 +1179,13 @@ pub type Ixs = isize;
11771179
// `.offset()` at all, even by zero bytes, but the implementation of
11781180
// `Vec<A>` does this, so we can too. See rust-lang/rust#54857 for details.)
11791181
//
1180-
// 4. The product of non-zero axis lengths must not exceed `isize::MAX`. (This
1182+
// 5. The product of non-zero axis lengths must not exceed `isize::MAX`. (This
11811183
// also implies that the length of any individual axis must not exceed
11821184
// `isize::MAX`, and an array can contain at most `isize::MAX` elements.)
11831185
// This constraint makes various calculations easier because they don't have
11841186
// to worry about overflow and axis lengths can be freely cast to `isize`.
11851187
//
1186-
// Constraints 2–4 are carefully designed such that if they're upheld for the
1188+
// Constraints 2–5 are carefully designed such that if they're upheld for the
11871189
// array, they're also upheld for any subset of axes of the array as well as
11881190
// slices/subviews/reshapes of the array. This is important for iterators that
11891191
// produce subviews (and other similar cases) to be safe without extra (easy to
@@ -1209,8 +1211,8 @@ where
12091211
/// Data buffer / ownership information. (If owned, contains the data
12101212
/// buffer; if borrowed, contains the lifetime and mutability.)
12111213
data: S,
1212-
/// A non-null and aligned pointer into the buffer held by `data`; may
1213-
/// point anywhere in its range.
1214+
/// A non-null pointer into the buffer held by `data`; may point anywhere
1215+
/// in its range. If `S: Data`, this pointer must be aligned.
12141216
ptr: std::ptr::NonNull<S::Elem>,
12151217
/// The lengths of the axes.
12161218
dim: D,
@@ -1331,7 +1333,7 @@ pub type ArrayViewMut<'a, A, D> = ArrayBase<ViewRepr<&'a mut A>, D>;
13311333
/// conversion into an [`ArrayView`]. The relationship between `RawArrayView`
13321334
/// and [`ArrayView`] is somewhat analogous to the relationship between `*const
13331335
/// T` and `&T`, but `RawArrayView` has additional requirements that `*const T`
1334-
/// does not, such as alignment and non-nullness.
1336+
/// does not, such as non-nullness.
13351337
///
13361338
/// [`ArrayView`]: type.ArrayView.html
13371339
///
@@ -1356,8 +1358,7 @@ pub type RawArrayView<A, D> = ArrayBase<RawViewRepr<*const A>, D>;
13561358
/// unsafe conversion into an [`ArrayViewMut`]. The relationship between
13571359
/// `RawArrayViewMut` and [`ArrayViewMut`] is somewhat analogous to the
13581360
/// relationship between `*mut T` and `&mut T`, but `RawArrayViewMut` has
1359-
/// additional requirements that `*mut T` does not, such as alignment and
1360-
/// non-nullness.
1361+
/// additional requirements that `*mut T` does not, such as non-nullness.
13611362
///
13621363
/// [`ArrayViewMut`]: type.ArrayViewMut.html
13631364
///

tests/raw_views.rs

+20-23
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@ use ndarray::prelude::*;
22
use ndarray::Zip;
33

44
use std::cell::Cell;
5-
#[cfg(debug_assertions)]
6-
use std::mem;
75

86
#[test]
97
fn raw_view_cast_cell() {
@@ -59,28 +57,27 @@ fn raw_view_mut_invalid_size_cast() {
5957
}
6058

6159
#[test]
62-
#[cfg(debug_assertions)]
63-
#[should_panic = "alignment mismatch"]
64-
fn raw_view_invalid_align_cast() {
65-
#[derive(Copy, Clone, Debug)]
66-
#[repr(transparent)]
67-
struct A([u8; 16]);
68-
#[derive(Copy, Clone, Debug)]
69-
#[repr(transparent)]
70-
struct B([f64; 2]);
71-
60+
fn raw_view_misaligned() {
61+
let data: [u16; 2] = [0x0011, 0x2233];
62+
let ptr: *const u16 = data.as_ptr();
7263
unsafe {
73-
const LEN: usize = 16;
74-
let mut buffer = [0u8; mem::size_of::<A>() * (LEN + 1)];
75-
// Take out a slice of buffer as &[A] which is misaligned for B
76-
let mut ptr = buffer.as_mut_ptr();
77-
if ptr as usize % mem::align_of::<B>() == 0 {
78-
ptr = ptr.add(1);
79-
}
80-
81-
let view = RawArrayViewMut::from_shape_ptr(LEN, ptr as *mut A);
64+
let misaligned_ptr = (ptr as *const u8).add(1) as *const u16;
65+
RawArrayView::from_shape_ptr(1, misaligned_ptr);
66+
}
67+
}
8268

83-
// misaligned cast - test debug assertion
84-
view.cast::<B>();
69+
#[test]
70+
#[cfg(debug_assertions)]
71+
#[should_panic = "The pointer must be aligned."]
72+
fn raw_view_deref_into_view_misaligned() {
73+
fn misaligned_deref(data: &[u16; 2]) -> ArrayView1<'_, u16> {
74+
let ptr: *const u16 = data.as_ptr();
75+
unsafe {
76+
let misaligned_ptr = (ptr as *const u8).add(1) as *const u16;
77+
let raw_view = RawArrayView::from_shape_ptr(1, misaligned_ptr);
78+
raw_view.deref_into_view()
79+
}
8580
}
81+
let data: [u16; 2] = [0x0011, 0x2233];
82+
misaligned_deref(&data);
8683
}

0 commit comments

Comments
 (0)