Skip to content

Commit 97c00b9

Browse files
committed
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 a7d1fd6 commit 97c00b9

File tree

5 files changed

+76
-31
lines changed

5 files changed

+76
-31
lines changed

src/impl_views/conversions.rs

+21
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

+36-19
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

+1-1
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ impl<$($typarm)*> NdProducer for $fulltype {
9090

9191
#[doc(hidden)]
9292
unsafe fn uget_ptr(&self, i: &Self::Dim) -> *mut A {
93-
self.$base.uget_ptr(i)
93+
self.$base.uget_ptr(i) as *mut _
9494
}
9595

9696
#[doc(hidden)]

src/iterators/windows.rs

+18-7
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;
@@ -9,7 +11,8 @@ use crate::NdProducer;
911
/// See [`.windows()`](ArrayBase::windows) for more
1012
/// information.
1113
pub struct Windows<'a, A, D> {
12-
base: ArrayView<'a, A, D>,
14+
base: RawArrayView<A, D>,
15+
life: PhantomData<&'a A>,
1316
window: D,
1417
strides: D,
1518
}
@@ -41,7 +44,8 @@ impl<'a, A, D: Dimension> Windows<'a, A, D> {
4144

4245
unsafe {
4346
Windows {
44-
base: ArrayView::new(a.ptr, size, a.strides),
47+
base: RawArrayView::new(a.ptr, size, a.strides),
48+
life: PhantomData,
4549
window,
4650
strides: window_strides,
4751
}
@@ -54,6 +58,7 @@ impl_ndproducer! {
5458
[Clone => 'a, A, D: Clone ]
5559
Windows {
5660
base,
61+
life,
5762
window,
5863
strides,
5964
}
@@ -77,7 +82,8 @@ where
7782
type IntoIter = WindowsIter<'a, A, D>;
7883
fn into_iter(self) -> Self::IntoIter {
7984
WindowsIter {
80-
iter: self.base.into_elements_base(),
85+
iter: self.base.into_base_iter(),
86+
life: self.life,
8187
window: self.window,
8288
strides: self.strides,
8389
}
@@ -89,7 +95,8 @@ where
8995
/// See [`.windows()`](ArrayBase::windows) for more
9096
/// information.
9197
pub struct WindowsIter<'a, A, D> {
92-
iter: ElementsBase<'a, A, D>,
98+
iter: Baseiter<A, D>,
99+
life: PhantomData<&'a A>,
93100
window: D,
94101
strides: D,
95102
}
@@ -99,19 +106,23 @@ impl_iterator! {
99106
[Clone => 'a, A, D: Clone]
100107
WindowsIter {
101108
iter,
109+
life,
102110
window,
103111
strides,
104112
}
105113
WindowsIter<'a, A, D> {
106114
type Item = ArrayView<'a, A, D>;
107115

108-
fn item(&mut self, elt) {
116+
fn item(&mut self, ptr) {
109117
unsafe {
110118
ArrayView::new_(
111-
elt,
119+
ptr,
112120
self.window.clone(),
113121
self.strides.clone())
114122
}
115123
}
116124
}
117125
}
126+
127+
send_sync_read_only!(Windows);
128+
send_sync_read_only!(WindowsIter);

src/lib.rs

-4
Original file line numberDiff line numberDiff line change
@@ -1554,10 +1554,6 @@ where
15541554
unsafe { ArrayView::new(ptr, dim, strides) }
15551555
}
15561556

1557-
fn raw_strides(&self) -> D {
1558-
self.strides.clone()
1559-
}
1560-
15611557
/// Remove array axis `axis` and return the result.
15621558
fn try_remove_axis(self, axis: Axis) -> ArrayBase<S, D::Smaller> {
15631559
let d = self.dim.try_remove_axis(axis);

0 commit comments

Comments
 (0)