Rollup merge of #86521 - the8472:add-footgun-comments, r=RalfJung

Add comments around code where ordering is important due for panic-safety

Iterators contain arbitrary code which may panic. Unsafe code has to be
careful to do its state updates at the right point between calls that may panic.

As requested in https://github.com/rust-lang/rust/pull/86452#discussion_r655153948

r? `@RalfJung`
This commit is contained in:
Dylan DPC 2021-06-23 00:20:20 +02:00 committed by GitHub
commit 6023ac2c8d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 17 additions and 0 deletions

View File

@ -2568,6 +2568,8 @@ impl<T, A: Allocator> Vec<T, A> {
}
unsafe {
ptr::write(self.as_mut_ptr().add(len), element);
// Since next() executes user code which can panic we have to bump the length
// after each step.
// NB can't overflow since we would have had to alloc the address space
self.set_len(len + 1);
}

View File

@ -89,6 +89,8 @@ fn write_in_place_with_drop<T>(
// all we can do is check if it's still in range
debug_assert!(sink.dst as *const _ <= src_end, "InPlaceIterable contract violation");
ptr::write(sink.dst, item);
// Since this executes user code which can panic we have to bump the pointer
// after each step.
sink.dst = sink.dst.add(1);
}
Ok(sink)
@ -136,6 +138,8 @@ where
let dst = dst_buf.offset(i as isize);
debug_assert!(dst as *const _ <= end, "InPlaceIterable contract violation");
ptr::write(dst, self.__iterator_get_unchecked(i));
// Since this executes user code which can panic we have to bump the pointer
// after each step.
drop_guard.dst = dst.add(1);
}
}

View File

@ -40,6 +40,8 @@ where
iterator.for_each(move |element| {
ptr::write(ptr, element);
ptr = ptr.offset(1);
// Since the loop executes user code which can panic we have to bump the pointer
// after each step.
// NB can't overflow since we would have had to alloc the address space
local_len.increment_len(1);
});

View File

@ -227,6 +227,8 @@ where
fn next(&mut self) -> Option<(A::Item, B::Item)> {
if self.index < self.len {
let i = self.index;
// since get_unchecked executes code which can panic we increment the counters beforehand
// so that the same index won't be accessed twice, as required by TrustedRandomAccess
self.index += 1;
// SAFETY: `i` is smaller than `self.len`, thus smaller than `self.a.len()` and `self.b.len()`
unsafe {
@ -234,6 +236,7 @@ where
}
} else if A::MAY_HAVE_SIDE_EFFECT && self.index < self.a_len {
let i = self.index;
// as above, increment before executing code that may panic
self.index += 1;
self.len += 1;
// match the base implementation's potential side effects
@ -259,6 +262,8 @@ where
let end = self.index + delta;
while self.index < end {
let i = self.index;
// since get_unchecked executes code which can panic we increment the counters beforehand
// so that the same index won't be accessed twice, as required by TrustedRandomAccess
self.index += 1;
if A::MAY_HAVE_SIDE_EFFECT {
// SAFETY: the usage of `cmp::min` to calculate `delta`
@ -295,6 +300,8 @@ where
let sz_a = self.a.size();
if A::MAY_HAVE_SIDE_EFFECT && sz_a > self.len {
for _ in 0..sz_a - self.len {
// since next_back() may panic we increment the counters beforehand
// to keep Zip's state in sync with the underlying iterator source
self.a_len -= 1;
self.a.next_back();
}
@ -309,6 +316,8 @@ where
}
}
if self.index < self.len {
// since get_unchecked executes code which can panic we increment the counters beforehand
// so that the same index won't be accessed twice, as required by TrustedRandomAccess
self.len -= 1;
self.a_len -= 1;
let i = self.len;