Skip to content

Commit 6df86a3

Browse files
jturner314bluss
authored andcommitted
Fix Miri errors for WindowsIter and ExactChunksIter/Mut
Before this commit, running `MIRIFLAGS="-Zmiri-tag-raw-pointers" cargo miri test` caused Miri to report undefined behavior for code using the `WindowsIter`, `ExactChunksIter`, and `ExactChunksIterMut` iterators. This commit fixes the underlying issue. Basically, Miri doesn't like code which uses a reference to an element to access other elements. Before this commit, these iterators wrapped the `ElementsBase` and `ElementsBaseMut` iterators, and they created views from the references returned by those inner iterators. Accessing elements within those views (other than the first element) led to the Miri error, since the view's pointer was derived from a reference to a single element. Now, the iterators wrap `Baseiter` instead, which produces raw pointers instead of references. Although not necessary to satisfy Miri, this commit also changes the `Windows`, `ExactChunks`, and `ExactChunksMut` producers to wrap raw views instead of normal views. This avoids potential confusion regarding which elements are accessible through the views produced by these producers.
1 parent f124a16 commit 6df86a3

File tree

5 files changed

+76
-31
lines changed

5 files changed

+76
-31
lines changed

src/impl_views/conversions.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,27 @@ where
183183
}
184184
}
185185

186+
/// Private raw array view methods
187+
impl<A, D> RawArrayView<A, D>
188+
where
189+
D: Dimension,
190+
{
191+
#[inline]
192+
pub(crate) fn into_base_iter(self) -> Baseiter<A, D> {
193+
unsafe { Baseiter::new(self.ptr.as_ptr(), self.dim, self.strides) }
194+
}
195+
}
196+
197+
impl<A, D> RawArrayViewMut<A, D>
198+
where
199+
D: Dimension,
200+
{
201+
#[inline]
202+
pub(crate) fn into_base_iter(self) -> Baseiter<A, D> {
203+
unsafe { Baseiter::new(self.ptr.as_ptr(), self.dim, self.strides) }
204+
}
205+
}
206+
186207
/// Private array view methods
187208
impl<'a, A, D> ArrayView<'a, A, D>
188209
where

src/iterators/chunks.rs

Lines changed: 36 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1+
use std::marker::PhantomData;
2+
13
use crate::imp_prelude::*;
2-
use crate::ElementsBase;
3-
use crate::ElementsBaseMut;
4+
use crate::Baseiter;
45
use crate::IntoDimension;
56
use crate::{Layout, NdProducer};
67

@@ -9,6 +10,7 @@ impl_ndproducer! {
910
[Clone => 'a, A, D: Clone ]
1011
ExactChunks {
1112
base,
13+
life,
1214
chunk,
1315
inner_strides,
1416
}
@@ -23,16 +25,14 @@ impl_ndproducer! {
2325
}
2426
}
2527

26-
type BaseProducerRef<'a, A, D> = ArrayView<'a, A, D>;
27-
type BaseProducerMut<'a, A, D> = ArrayViewMut<'a, A, D>;
28-
2928
/// Exact chunks producer and iterable.
3029
///
3130
/// See [`.exact_chunks()`](ArrayBase::exact_chunks) for more
3231
/// information.
3332
//#[derive(Debug)]
3433
pub struct ExactChunks<'a, A, D> {
35-
base: BaseProducerRef<'a, A, D>,
34+
base: RawArrayView<A, D>,
35+
life: PhantomData<&'a A>,
3636
chunk: D,
3737
inner_strides: D,
3838
}
@@ -41,10 +41,11 @@ impl<'a, A, D: Dimension> ExactChunks<'a, A, D> {
4141
/// Creates a new exact chunks producer.
4242
///
4343
/// **Panics** if any chunk dimension is zero
44-
pub(crate) fn new<E>(mut a: ArrayView<'a, A, D>, chunk: E) -> Self
44+
pub(crate) fn new<E>(a: ArrayView<'a, A, D>, chunk: E) -> Self
4545
where
4646
E: IntoDimension<Dim = D>,
4747
{
48+
let mut a = a.into_raw_view();
4849
let chunk = chunk.into_dimension();
4950
ndassert!(
5051
a.ndim() == chunk.ndim(),
@@ -59,11 +60,12 @@ impl<'a, A, D: Dimension> ExactChunks<'a, A, D> {
5960
for i in 0..a.ndim() {
6061
a.dim[i] /= chunk[i];
6162
}
62-
let inner_strides = a.raw_strides();
63+
let inner_strides = a.strides.clone();
6364
a.strides *= &chunk;
6465

6566
ExactChunks {
6667
base: a,
68+
life: PhantomData,
6769
chunk,
6870
inner_strides,
6971
}
@@ -79,7 +81,8 @@ where
7981
type IntoIter = ExactChunksIter<'a, A, D>;
8082
fn into_iter(self) -> Self::IntoIter {
8183
ExactChunksIter {
82-
iter: self.base.into_elements_base(),
84+
iter: self.base.into_base_iter(),
85+
life: self.life,
8386
chunk: self.chunk,
8487
inner_strides: self.inner_strides,
8588
}
@@ -91,7 +94,8 @@ where
9194
/// See [`.exact_chunks()`](ArrayBase::exact_chunks) for more
9295
/// information.
9396
pub struct ExactChunksIter<'a, A, D> {
94-
iter: ElementsBase<'a, A, D>,
97+
iter: Baseiter<A, D>,
98+
life: PhantomData<&'a A>,
9599
chunk: D,
96100
inner_strides: D,
97101
}
@@ -101,6 +105,7 @@ impl_ndproducer! {
101105
[Clone => ]
102106
ExactChunksMut {
103107
base,
108+
life,
104109
chunk,
105110
inner_strides,
106111
}
@@ -122,7 +127,8 @@ impl_ndproducer! {
122127
/// for more information.
123128
//#[derive(Debug)]
124129
pub struct ExactChunksMut<'a, A, D> {
125-
base: BaseProducerMut<'a, A, D>,
130+
base: RawArrayViewMut<A, D>,
131+
life: PhantomData<&'a mut A>,
126132
chunk: D,
127133
inner_strides: D,
128134
}
@@ -131,10 +137,11 @@ impl<'a, A, D: Dimension> ExactChunksMut<'a, A, D> {
131137
/// Creates a new exact chunks producer.
132138
///
133139
/// **Panics** if any chunk dimension is zero
134-
pub(crate) fn new<E>(mut a: ArrayViewMut<'a, A, D>, chunk: E) -> Self
140+
pub(crate) fn new<E>(a: ArrayViewMut<'a, A, D>, chunk: E) -> Self
135141
where
136142
E: IntoDimension<Dim = D>,
137143
{
144+
let mut a = a.into_raw_view_mut();
138145
let chunk = chunk.into_dimension();
139146
ndassert!(
140147
a.ndim() == chunk.ndim(),
@@ -149,11 +156,12 @@ impl<'a, A, D: Dimension> ExactChunksMut<'a, A, D> {
149156
for i in 0..a.ndim() {
150157
a.dim[i] /= chunk[i];
151158
}
152-
let inner_strides = a.raw_strides();
159+
let inner_strides = a.strides.clone();
153160
a.strides *= &chunk;
154161

155162
ExactChunksMut {
156163
base: a,
164+
life: PhantomData,
157165
chunk,
158166
inner_strides,
159167
}
@@ -169,7 +177,8 @@ where
169177
type IntoIter = ExactChunksIterMut<'a, A, D>;
170178
fn into_iter(self) -> Self::IntoIter {
171179
ExactChunksIterMut {
172-
iter: self.base.into_elements_base(),
180+
iter: self.base.into_base_iter(),
181+
life: self.life,
173182
chunk: self.chunk,
174183
inner_strides: self.inner_strides,
175184
}
@@ -181,16 +190,17 @@ impl_iterator! {
181190
[Clone => 'a, A, D: Clone]
182191
ExactChunksIter {
183192
iter,
193+
life,
184194
chunk,
185195
inner_strides,
186196
}
187197
ExactChunksIter<'a, A, D> {
188198
type Item = ArrayView<'a, A, D>;
189199

190-
fn item(&mut self, elt) {
200+
fn item(&mut self, ptr) {
191201
unsafe {
192202
ArrayView::new_(
193-
elt,
203+
ptr,
194204
self.chunk.clone(),
195205
self.inner_strides.clone())
196206
}
@@ -209,10 +219,10 @@ impl_iterator! {
209219
ExactChunksIterMut<'a, A, D> {
210220
type Item = ArrayViewMut<'a, A, D>;
211221

212-
fn item(&mut self, elt) {
222+
fn item(&mut self, ptr) {
213223
unsafe {
214224
ArrayViewMut::new_(
215-
elt,
225+
ptr,
216226
self.chunk.clone(),
217227
self.inner_strides.clone())
218228
}
@@ -225,7 +235,14 @@ impl_iterator! {
225235
/// See [`.exact_chunks_mut()`](ArrayBase::exact_chunks_mut)
226236
/// for more information.
227237
pub struct ExactChunksIterMut<'a, A, D> {
228-
iter: ElementsBaseMut<'a, A, D>,
238+
iter: Baseiter<A, D>,
239+
life: PhantomData<&'a mut A>,
229240
chunk: D,
230241
inner_strides: D,
231242
}
243+
244+
send_sync_read_only!(ExactChunks);
245+
send_sync_read_only!(ExactChunksIter);
246+
247+
send_sync_read_write!(ExactChunksMut);
248+
send_sync_read_write!(ExactChunksIterMut);

src/iterators/macros.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ impl<$($typarm)*> NdProducer for $fulltype {
8484
}
8585

8686
unsafe fn uget_ptr(&self, i: &Self::Dim) -> *mut A {
87-
self.$base.uget_ptr(i)
87+
self.$base.uget_ptr(i) as *mut _
8888
}
8989

9090
fn stride_of(&self, axis: Axis) -> isize {

src/iterators/windows.rs

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
use super::ElementsBase;
1+
use std::marker::PhantomData;
2+
3+
use super::Baseiter;
24
use crate::imp_prelude::*;
35
use crate::IntoDimension;
46
use crate::Layout;
@@ -10,7 +12,8 @@ use crate::Slice;
1012
/// See [`.windows()`](ArrayBase::windows) for more
1113
/// information.
1214
pub struct Windows<'a, A, D> {
13-
base: ArrayView<'a, A, D>,
15+
base: RawArrayView<A, D>,
16+
life: PhantomData<&'a A>,
1417
window: D,
1518
strides: D,
1619
}
@@ -74,7 +77,8 @@ impl<'a, A, D: Dimension> Windows<'a, A, D> {
7477
});
7578

7679
Windows {
77-
base,
80+
base: base.into_raw_view(),
81+
life: PhantomData,
7882
window,
7983
strides: window_strides,
8084
}
@@ -86,6 +90,7 @@ impl_ndproducer! {
8690
[Clone => 'a, A, D: Clone ]
8791
Windows {
8892
base,
93+
life,
8994
window,
9095
strides,
9196
}
@@ -109,7 +114,8 @@ where
109114
type IntoIter = WindowsIter<'a, A, D>;
110115
fn into_iter(self) -> Self::IntoIter {
111116
WindowsIter {
112-
iter: self.base.into_elements_base(),
117+
iter: self.base.into_base_iter(),
118+
life: self.life,
113119
window: self.window,
114120
strides: self.strides,
115121
}
@@ -121,7 +127,8 @@ where
121127
/// See [`.windows()`](ArrayBase::windows) for more
122128
/// information.
123129
pub struct WindowsIter<'a, A, D> {
124-
iter: ElementsBase<'a, A, D>,
130+
iter: Baseiter<A, D>,
131+
life: PhantomData<&'a A>,
125132
window: D,
126133
strides: D,
127134
}
@@ -131,19 +138,23 @@ impl_iterator! {
131138
[Clone => 'a, A, D: Clone]
132139
WindowsIter {
133140
iter,
141+
life,
134142
window,
135143
strides,
136144
}
137145
WindowsIter<'a, A, D> {
138146
type Item = ArrayView<'a, A, D>;
139147

140-
fn item(&mut self, elt) {
148+
fn item(&mut self, ptr) {
141149
unsafe {
142150
ArrayView::new_(
143-
elt,
151+
ptr,
144152
self.window.clone(),
145153
self.strides.clone())
146154
}
147155
}
148156
}
149157
}
158+
159+
send_sync_read_only!(Windows);
160+
send_sync_read_only!(WindowsIter);

src/lib.rs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1559,10 +1559,6 @@ where
15591559
unsafe { ArrayView::new(ptr, dim, strides) }
15601560
}
15611561

1562-
fn raw_strides(&self) -> D {
1563-
self.strides.clone()
1564-
}
1565-
15661562
/// Remove array axis `axis` and return the result.
15671563
fn try_remove_axis(self, axis: Axis) -> ArrayBase<S, D::Smaller> {
15681564
let d = self.dim.try_remove_axis(axis);

0 commit comments

Comments
 (0)