Fix some out-of-bounds `offset` calls
After we yield the final element from the iterator, we don't offset `ptr` agian, to avoid having it go out-of-bounds. However, `inner_end` may be several elements out-of-bounds, depending on the value of `size`. Therefore, we use `wrapping_offset` to avoid undefined behavior.
This commit is contained in:
parent
4e3fb80b4c
commit
46904d710b
|
@ -74,7 +74,12 @@ macro_rules! iterator {
|
||||||
// Jump to the next outer dimension if needed.
|
// Jump to the next outer dimension if needed.
|
||||||
if self.ptr == self.inner_end {
|
if self.ptr == self.inner_end {
|
||||||
let stride = self.strides.1.value() as isize;
|
let stride = self.strides.1.value() as isize;
|
||||||
self.inner_end = self.ptr.offset(stride);
|
// This might go past the end of the allocation,
|
||||||
|
// depending on the value of 'size'. We use
|
||||||
|
// `wrapping_offset` to avoid UB
|
||||||
|
self.inner_end = self.ptr.wrapping_offset(stride);
|
||||||
|
// This will always be in bounds, since
|
||||||
|
// we're going to dereference it
|
||||||
self.ptr = self.inner_ptr.offset(stride);
|
self.ptr = self.inner_ptr.offset(stride);
|
||||||
self.inner_ptr = self.ptr;
|
self.inner_ptr = self.ptr;
|
||||||
}
|
}
|
||||||
|
@ -83,8 +88,13 @@ macro_rules! iterator {
|
||||||
let old = self.ptr;
|
let old = self.ptr;
|
||||||
|
|
||||||
let stride = self.strides.0.value() as isize;
|
let stride = self.strides.0.value() as isize;
|
||||||
self.ptr = self.ptr.offset(stride);
|
// Don't offset `self.ptr` for the last element,
|
||||||
|
// as this will be out of bounds. Iteration is done
|
||||||
|
// at this point (the next call to `next` will return `None`)
|
||||||
|
// so this is not observable.
|
||||||
|
if self.size != 0 {
|
||||||
|
self.ptr = self.ptr.offset(stride);
|
||||||
|
}
|
||||||
Some(mem::transmute(old))
|
Some(mem::transmute(old))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue