Skip to content

Commit bed0eeb

Browse files
author
Fedor Ryabinin
committed
More LLM-generated pre-condition
1 parent 58ff655 commit bed0eeb

65 files changed

Lines changed: 1092 additions & 0 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

library/alloc/src/boxed/convert.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,12 @@
1+
#![feature(ub_checks)]
2+
use safety::{ensures,requires};
3+
#[cfg(kani)]
4+
#[unstable(feature = "kani", issue = "none")]
5+
use core::kani;
6+
#[allow(unused_imports)]
7+
#[unstable(feature = "ub_checks", issue = "none")]
8+
use core::ub_checks::*;
9+
110
use core::any::Any;
211
use core::error::Error;
312
use core::mem;
@@ -275,6 +284,7 @@ impl<T, const N: usize> From<[T; N]> for Box<[T]> {
275284
/// # Safety
276285
///
277286
/// `boxed_slice.len()` must be exactly `N`.
287+
#[requires(boxed_slice.len() == N)]
278288
unsafe fn boxed_slice_as_array_unchecked<T, A: Allocator, const N: usize>(
279289
boxed_slice: Box<[T], A>,
280290
) -> Box<[T; N], A> {
@@ -391,6 +401,7 @@ impl<A: Allocator> Box<dyn Any, A> {
391401
/// [`downcast`]: Self::downcast
392402
#[inline]
393403
#[unstable(feature = "downcast_unchecked", issue = "90850")]
404+
#[requires(self.is::<T>())]
394405
pub unsafe fn downcast_unchecked<T: Any>(self) -> Box<T, A> {
395406
debug_assert!(self.is::<T>());
396407
unsafe {
@@ -450,6 +461,7 @@ impl<A: Allocator> Box<dyn Any + Send, A> {
450461
/// [`downcast`]: Self::downcast
451462
#[inline]
452463
#[unstable(feature = "downcast_unchecked", issue = "90850")]
464+
#[requires(self.is::<T>())]
453465
pub unsafe fn downcast_unchecked<T: Any>(self) -> Box<T, A> {
454466
debug_assert!(self.is::<T>());
455467
unsafe {
@@ -509,6 +521,7 @@ impl<A: Allocator> Box<dyn Any + Send + Sync, A> {
509521
/// [`downcast`]: Self::downcast
510522
#[inline]
511523
#[unstable(feature = "downcast_unchecked", issue = "90850")]
524+
#[requires(self.is::<T>())]
512525
pub unsafe fn downcast_unchecked<T: Any>(self) -> Box<T, A> {
513526
debug_assert!(self.is::<T>());
514527
unsafe {

library/alloc/src/collections/vec_deque/drain.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,12 @@
1+
#![feature(ub_checks)]
2+
use safety::{ensures,requires};
3+
#[cfg(kani)]
4+
#[unstable(feature = "kani", issue = "none")]
5+
use core::kani;
6+
#[allow(unused_imports)]
7+
#[unstable(feature = "ub_checks", issue = "none")]
8+
use core::ub_checks::*;
9+
110
use core::iter::FusedIterator;
211
use core::marker::PhantomData;
312
use core::mem::{self, SizedTypeProperties};
@@ -34,6 +43,10 @@ pub struct Drain<
3443
}
3544

3645
impl<'a, T, A: Allocator> Drain<'a, T, A> {
46+
#[requires(drain_start <= deque.len())]
47+
#[requires(drain_len <= deque.len())]
48+
#[requires(drain_start + drain_len <= deque.len())]
49+
#[cfg_attr(kani, kani::modifies(deque))]
3750
pub(super) unsafe fn new(
3851
deque: &'a mut VecDeque<T, A>,
3952
drain_start: usize,
@@ -53,6 +66,8 @@ impl<'a, T, A: Allocator> Drain<'a, T, A> {
5366

5467
// Only returns pointers to the slices, as that's all we need
5568
// to drop them. May only be called if `self.remaining != 0`.
69+
#[requires(self.remaining != 0)]
70+
#[cfg_attr(kani, kani::modifies(self))]
5671
unsafe fn as_slices(&self) -> (*mut [T], *mut [T]) {
5772
unsafe {
5873
let deque = self.deque.as_ref();

library/alloc/src/str.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,20 @@
22
//!
33
//! *[See also the `str` primitive type](str).*
44
5+
#![feature(ub_checks)]
56
#![stable(feature = "rust1", since = "1.0.0")]
67
// Many of the usings in this module are only used in the test configuration.
78
// It's cleaner to just turn off the unused_imports warning than to fix them.
89
#![allow(unused_imports)]
910

11+
use safety::{ensures,requires};
12+
#[cfg(kani)]
13+
#[unstable(feature = "kani", issue = "none")]
14+
use core::kani;
15+
#[allow(unused_imports)]
16+
#[unstable(feature = "ub_checks", issue = "none")]
17+
use core::ub_checks::*;
18+
1019
use core::borrow::{Borrow, BorrowMut};
1120
use core::iter::FusedIterator;
1221
use core::mem::MaybeUninit;
@@ -615,6 +624,7 @@ impl str {
615624
#[stable(feature = "str_box_extras", since = "1.20.0")]
616625
#[must_use]
617626
#[inline]
627+
#[requires(core::str::from_utf8(&v).is_ok())]
618628
pub unsafe fn from_boxed_utf8_unchecked(v: Box<[u8]>) -> Box<str> {
619629
unsafe { Box::from_raw(Box::into_raw(v) as *mut str) }
620630
}
@@ -712,3 +722,27 @@ unsafe fn replace_ascii(utf8_bytes: &[u8], from: u8, to: u8) -> String {
712722
// SAFETY: We replaced ascii with ascii on valid utf8 strings.
713723
unsafe { String::from_utf8_unchecked(result) }
714724
}
725+
#[cfg(kani)]
726+
mod verify {
727+
use super::*;
728+
#[kani::proof_for_contract(from_boxed_utf8_unchecked)]
729+
fn from_boxed_utf8_unchecked_contract() {
730+
// Create a small array of valid UTF-8 bytes (ASCII "hello")
731+
let valid_utf8_bytes = [b'h', b'e', b'l', b'l', b'o'];
732+
733+
// Create a Box<[u8]> from the array
734+
let boxed_bytes = Box::new(valid_utf8_bytes);
735+
736+
// Call the function being verified
737+
let _boxed_str = unsafe { from_boxed_utf8_unchecked(boxed_bytes) };
738+
739+
// Create another array with non-ASCII but valid UTF-8 sequence
740+
// UTF-8 encoding of "helloé"
741+
let valid_utf8_bytes_2 = [b'h', b'e', b'l', b'l', b'o', 0xC3, 0xA9];
742+
743+
let boxed_bytes_2 = Box::new(valid_utf8_bytes_2);
744+
745+
// Call the function being verified
746+
let _boxed_str_2 = unsafe { from_boxed_utf8_unchecked(boxed_bytes_2) };
747+
}
748+
}

library/alloc/src/task.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#![feature(ub_checks)]
12
#![stable(feature = "wake_trait", since = "1.51.0")]
23

34
//! Types and Traits for working with asynchronous tasks.
@@ -7,6 +8,14 @@
78
//! This may be detected at compile time using
89
//! `#[cfg(target_has_atomic = "ptr")]`.
910
11+
use safety::{ensures,requires};
12+
#[cfg(kani)]
13+
#[unstable(feature = "kani", issue = "none")]
14+
use core::kani;
15+
#[allow(unused_imports)]
16+
#[unstable(feature = "ub_checks", issue = "none")]
17+
use core::ub_checks::*;
18+
1019
use core::mem::ManuallyDrop;
1120
#[cfg(target_has_atomic = "ptr")]
1221
use core::task::Waker;
@@ -145,6 +154,7 @@ fn raw_waker<W: Wake + Send + Sync + 'static>(waker: Arc<W>) -> RawWaker {
145154
// the vtable pointers, rather than comparing all four function pointers
146155
// within the vtables.
147156
#[inline(always)]
157+
#[requires(waker != core::ptr::null())]
148158
unsafe fn clone_waker<W: Wake + Send + Sync + 'static>(waker: *const ()) -> RawWaker {
149159
unsafe { Arc::increment_strong_count(waker as *const W) };
150160
RawWaker::new(
@@ -154,18 +164,21 @@ fn raw_waker<W: Wake + Send + Sync + 'static>(waker: Arc<W>) -> RawWaker {
154164
}
155165

156166
// Wake by value, moving the Arc into the Wake::wake function
167+
#[requires(waker != core::ptr::null())]
157168
unsafe fn wake<W: Wake + Send + Sync + 'static>(waker: *const ()) {
158169
let waker = unsafe { Arc::from_raw(waker as *const W) };
159170
<W as Wake>::wake(waker);
160171
}
161172

162173
// Wake by reference, wrap the waker in ManuallyDrop to avoid dropping it
174+
#[requires(waker != core::ptr::null())]
163175
unsafe fn wake_by_ref<W: Wake + Send + Sync + 'static>(waker: *const ()) {
164176
let waker = unsafe { ManuallyDrop::new(Arc::from_raw(waker as *const W)) };
165177
<W as Wake>::wake_by_ref(&waker);
166178
}
167179

168180
// Decrement the reference count of the Arc on drop
181+
#[requires(waker != core::ptr::null())]
169182
unsafe fn drop_waker<W: Wake + Send + Sync + 'static>(waker: *const ()) {
170183
unsafe { Arc::decrement_strong_count(waker as *const W) };
171184
}
@@ -318,6 +331,7 @@ fn local_raw_waker<W: LocalWake + 'static>(waker: Rc<W>) -> RawWaker {
318331
// Refer to the comment on raw_waker's clone_waker regarding why this is
319332
// always inline.
320333
#[inline(always)]
334+
#[requires(waker != core::ptr::null())]
321335
unsafe fn clone_waker<W: LocalWake + 'static>(waker: *const ()) -> RawWaker {
322336
unsafe { Rc::increment_strong_count(waker as *const W) };
323337
RawWaker::new(
@@ -327,18 +341,21 @@ fn local_raw_waker<W: LocalWake + 'static>(waker: Rc<W>) -> RawWaker {
327341
}
328342

329343
// Wake by value, moving the Rc into the LocalWake::wake function
344+
#[requires(waker != core::ptr::null())]
330345
unsafe fn wake<W: LocalWake + 'static>(waker: *const ()) {
331346
let waker = unsafe { Rc::from_raw(waker as *const W) };
332347
<W as LocalWake>::wake(waker);
333348
}
334349

335350
// Wake by reference, wrap the waker in ManuallyDrop to avoid dropping it
351+
#[requires(waker != core::ptr::null())]
336352
unsafe fn wake_by_ref<W: LocalWake + 'static>(waker: *const ()) {
337353
let waker = unsafe { ManuallyDrop::new(Rc::from_raw(waker as *const W)) };
338354
<W as LocalWake>::wake_by_ref(&waker);
339355
}
340356

341357
// Decrement the reference count of the Rc on drop
358+
#[requires(waker != core::ptr::null())]
342359
unsafe fn drop_waker<W: LocalWake + 'static>(waker: *const ()) {
343360
unsafe { Rc::decrement_strong_count(waker as *const W) };
344361
}

library/alloc/src/vec/spec_from_elem.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,14 @@
1+
#![feature(ub_checks)]
2+
use core::ub_checks::Invariant;
3+
4+
use safety::{ensures,requires};
5+
#[cfg(kani)]
6+
#[unstable(feature = "kani", issue = "none")]
7+
use core::kani;
8+
#[allow(unused_imports)]
9+
#[unstable(feature = "ub_checks", issue = "none")]
10+
use core::ub_checks::*;
11+
112
use core::ptr;
213

314
use super::{IsZero, Vec};
@@ -34,6 +45,7 @@ impl<T: Clone + IsZero> SpecFromElem for T {
3445
impl SpecFromElem for i8 {
3546
#[inline]
3647
#[track_caller]
48+
#[requires(n <= isize::MAX as usize)]
3749
fn from_elem<A: Allocator>(elem: i8, n: usize, alloc: A) -> Vec<i8, A> {
3850
if elem == 0 {
3951
return Vec { buf: RawVec::with_capacity_zeroed_in(n, alloc), len: n };
@@ -50,6 +62,7 @@ impl SpecFromElem for i8 {
5062
impl SpecFromElem for u8 {
5163
#[inline]
5264
#[track_caller]
65+
#[requires(n <= isize::MAX as usize)]
5366
fn from_elem<A: Allocator>(elem: u8, n: usize, alloc: A) -> Vec<u8, A> {
5467
if elem == 0 {
5568
return Vec { buf: RawVec::with_capacity_zeroed_in(n, alloc), len: n };
@@ -67,6 +80,7 @@ impl SpecFromElem for u8 {
6780
// but the latter cannot be detected currently
6881
impl SpecFromElem for () {
6982
#[inline]
83+
#[requires(n <= isize::MAX as usize)]
7084
fn from_elem<A: Allocator>(_elem: (), n: usize, alloc: A) -> Vec<(), A> {
7185
let mut v = Vec::with_capacity_in(n, alloc);
7286
// SAFETY: the capacity has just been set to `n`
@@ -77,3 +91,10 @@ impl SpecFromElem for () {
7791
v
7892
}
7993
}
94+
95+
#[unstable(feature = "ub_checks", issue = "none")]
96+
impl<T, A: Allocator> Invariant for Vec<T, A> {
97+
fn is_safe(&self) -> bool {
98+
self.len <= self.buf.capacity()
99+
}
100+
}

library/alloctests/benches/vec_deque.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,14 @@
1+
#![feature(ub_checks)]
2+
use core::ub_checks::Invariant;
3+
4+
use safety::{ensures,requires};
5+
#[cfg(kani)]
6+
#[unstable(feature = "kani", issue = "none")]
7+
use core::kani;
8+
#[allow(unused_imports)]
9+
#[unstable(feature = "ub_checks", issue = "none")]
10+
use core::ub_checks::*;
11+
112
use std::collections::{VecDeque, vec_deque};
213
use std::mem;
314

@@ -57,6 +68,8 @@ fn bench_try_fold(b: &mut Bencher) {
5768

5869
/// does the memory bookkeeping to reuse the buffer of the Vec between iterations.
5970
/// `setup` must not modify its argument's length or capacity. `g` must not move out of its argument.
71+
#[requires(v.len() <= isize::MAX as usize)]
72+
#[requires(can_dereference(v.as_ptr()))]
6073
fn into_iter_helper<
6174
T: Copy,
6275
F: FnOnce(&mut VecDeque<T>),
@@ -265,3 +278,10 @@ fn bench_extend_chained_bytes(b: &mut Bencher) {
265278
ring.extend(black_box(input1.iter().chain(input2.iter())));
266279
});
267280
}
281+
282+
#[unstable(feature = "ub_checks", issue = "none")]
283+
impl<T> Invariant for Vec<T> {
284+
fn is_safe(&self) -> bool {
285+
self.len() <= self.capacity()
286+
}
287+
}

library/alloctests/tests/sort/ffi_types.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use core::ub_checks::Invariant;
2+
13
use std::cmp::Ordering;
24

35
// Very large stack value.
@@ -80,3 +82,10 @@ impl Ord for F128 {
8082
unsafe { this_div.partial_cmp(&other_div).unwrap_unchecked() }
8183
}
8284
}
85+
86+
#[unstable(feature = "ub_checks", issue = "none")]
87+
impl Invariant for F128 {
88+
fn is_safe(&self) -> bool {
89+
self.x.is_normal() && self.y.is_normal()
90+
}
91+
}

library/alloctests/tests/vec.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use core::ub_checks::Invariant;
2+
13
use core::alloc::{Allocator, Layout};
24
use core::num::NonZero;
35
use core::ptr::NonNull;
@@ -2704,3 +2706,10 @@ fn vec_null_ptr_roundtrip() {
27042706
let new = roundtripped.with_addr(ptr.addr());
27052707
unsafe { new.read() };
27062708
}
2709+
2710+
#[unstable(feature = "ub_checks", issue = "none")]
2711+
impl<T> Invariant for Vec<T> {
2712+
fn is_safe(&self) -> bool {
2713+
self.len() <= self.capacity()
2714+
}
2715+
}

library/alloctests/tests/vec_deque.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,14 @@
1+
#![feature(ub_checks)]
2+
use core::ub_checks::Invariant;
3+
4+
use safety::{ensures,requires};
5+
#[cfg(kani)]
6+
#[unstable(feature = "kani", issue = "none")]
7+
use core::kani;
8+
#[allow(unused_imports)]
9+
#[unstable(feature = "ub_checks", issue = "none")]
10+
use core::ub_checks::*;
11+
112
use core::num::NonZero;
213
use std::assert_matches::assert_matches;
314
use std::collections::TryReserveErrorKind::*;
@@ -1074,6 +1085,9 @@ fn test_append_double_drop() {
10741085

10751086
#[test]
10761087
#[should_panic]
1088+
#[requires(v.capacity() == usize::MAX)]
1089+
#[requires(core::mem::size_of::<()>() == 0)]
1090+
#[requires(can_write(v.as_mut_ptr()))]
10771091
fn test_append_zst_capacity_overflow() {
10781092
let mut v = Vec::with_capacity(usize::MAX);
10791093
// note: using resize instead of set_len here would
@@ -1849,3 +1863,10 @@ fn test_truncate_front() {
18491863
v.truncate_front(5);
18501864
assert_eq!(v.as_slices(), ([2, 3, 4, 5, 6].as_slice(), [].as_slice()));
18511865
}
1866+
1867+
#[unstable(feature = "ub_checks", issue = "none")]
1868+
impl<T> Invariant for VecDeque<T> {
1869+
fn is_safe(&self) -> bool {
1870+
self.len() <= self.capacity()
1871+
}
1872+
}

0 commit comments

Comments
 (0)