Skip to content

Commit 9822a02

Browse files
committed
Add safety preconditions to alloc/src/alloc.rs
These changes add code contracts in the form of `#[requires(...)]` attributes to various methods in the `Global` allocator implementation. These contracts ensure that the safety conditions mentioned in the comments are explicitly stated as preconditions for the functions.
1 parent dc862c4 commit 9822a02

File tree

1 file changed

+71
-0
lines changed

1 file changed

+71
-0
lines changed

library/alloc/src/alloc.rs

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@
66
#[doc(inline)]
77
pub use core::alloc::*;
88
#[cfg(not(test))]
9+
use safety::requires;
10+
#[cfg(kani)]
11+
use crate::kani;
12+
913
use core::hint;
1014
#[cfg(not(test))]
1115
use core::ptr::{self, NonNull};
@@ -174,6 +178,7 @@ pub unsafe fn alloc_zeroed(layout: Layout) -> *mut u8 {
174178
impl Global {
175179
#[inline]
176180
fn alloc_impl(&self, layout: Layout, zeroed: bool) -> Result<NonNull<[u8]>, AllocError> {
181+
#[requires(layout.size() == 0 || layout.align() != 0)]
177182
match layout.size() {
178183
0 => Ok(NonNull::slice_from_raw_parts(layout.dangling(), 0)),
179184
// SAFETY: `layout` is non-zero in size,
@@ -186,6 +191,10 @@ impl Global {
186191
}
187192

188193
// SAFETY: Same as `Allocator::grow`
194+
#[requires(new_layout.size() >= old_layout.size())]
195+
#[requires(old_layout.size() == 0 || old_layout.align() != 0)]
196+
#[requires(new_layout.size() == 0 || new_layout.align() != 0)]
197+
#[requires(ptr.as_ptr() as usize % old_layout.align() == 0)]
189198
#[inline]
190199
unsafe fn grow_impl(
191200
&self,
@@ -247,6 +256,8 @@ unsafe impl Allocator for Global {
247256
}
248257

249258
#[inline]
259+
#[requires(layout.size() == 0 || layout.align() != 0)]
260+
#[requires(ptr.as_ptr() as usize % layout.align() == 0)]
250261
unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) {
251262
if layout.size() != 0 {
252263
// SAFETY: `layout` is non-zero in size,
@@ -256,6 +267,10 @@ unsafe impl Allocator for Global {
256267
}
257268

258269
#[inline]
270+
#[requires(new_layout.size() >= old_layout.size())]
271+
#[requires(old_layout.size() == 0 || old_layout.align() != 0)]
272+
#[requires(new_layout.size() == 0 || new_layout.align() != 0)]
273+
#[requires(ptr.as_ptr() as usize % old_layout.align() == 0)]
259274
unsafe fn grow(
260275
&self,
261276
ptr: NonNull<u8>,
@@ -267,6 +282,10 @@ unsafe impl Allocator for Global {
267282
}
268283

269284
#[inline]
285+
#[requires(new_layout.size() >= old_layout.size())]
286+
#[requires(old_layout.size() == 0 || old_layout.align() != 0)]
287+
#[requires(new_layout.size() == 0 || new_layout.align() != 0)]
288+
#[requires(ptr.as_ptr() as usize % old_layout.align() == 0)]
270289
unsafe fn grow_zeroed(
271290
&self,
272291
ptr: NonNull<u8>,
@@ -278,6 +297,10 @@ unsafe impl Allocator for Global {
278297
}
279298

280299
#[inline]
300+
#[requires(new_layout.size() <= old_layout.size())]
301+
#[requires(old_layout.size() == 0 || old_layout.align() != 0)]
302+
#[requires(new_layout.size() == 0 || new_layout.align() != 0)]
303+
#[requires(ptr.as_ptr() as usize % old_layout.align() == 0)]
281304
unsafe fn shrink(
282305
&self,
283306
ptr: NonNull<u8>,
@@ -423,3 +446,51 @@ pub mod __alloc_error_handler {
423446
}
424447
}
425448
}
449+
450+
#[cfg(kani)]
451+
#[unstable(feature="kani", issue="none")]
452+
mod verify {
453+
use super::*;
454+
455+
// fn alloc_impl(&self, layout: Layout, zeroed: bool) -> Result<NonNull<[u8]>, AllocError>
456+
#[kani::proof_for_contract(Global::alloc_impl)]
457+
pub fn check_alloc_impl() {
458+
let obj : Global = kani::any();
459+
let _ = obj.alloc_impl(kani::any());
460+
}
461+
462+
// unsafe fn grow_impl(&self, ptr: NonNull<u8>, old_layout: Layout, new_layout: Layout, zeroed: bool) -> Result<NonNull<[u8]>, AllocError>
463+
#[kani::proof_for_contract(Global::grow_impl)]
464+
pub fn check_grow_impl() {
465+
let obj : Global = kani::any();
466+
let _ = obj.grow_impl(kani::any());
467+
}
468+
469+
// unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout)
470+
#[kani::proof_for_contract(Allocator::deallocate)]
471+
pub fn check_deallocate() {
472+
let obj : Allocator = kani::any();
473+
let _ = obj.deallocate(kani::any());
474+
}
475+
476+
// unsafe fn grow(&self, ptr: NonNull<u8>, old_layout: Layout, new_layout: Layout) -> Result<NonNull<[u8]>, AllocError>
477+
#[kani::proof_for_contract(Allocator::grow)]
478+
pub fn check_grow() {
479+
let obj : Allocator = kani::any();
480+
let _ = obj.grow(kani::any());
481+
}
482+
483+
// unsafe fn grow_zeroed(&self, ptr: NonNull<u8>, old_layout: Layout, new_layout: Layout) -> Result<NonNull<[u8]>, AllocError>
484+
#[kani::proof_for_contract(Allocator::grow_zeroed)]
485+
pub fn check_grow_zeroed() {
486+
let obj : Allocator = kani::any();
487+
let _ = obj.grow_zeroed(kani::any());
488+
}
489+
490+
// unsafe fn shrink(&self, ptr: NonNull<u8>, old_layout: Layout, new_layout: Layout) -> Result<NonNull<[u8]>, AllocError>
491+
#[kani::proof_for_contract(Allocator::shrink)]
492+
pub fn check_shrink() {
493+
let obj : Allocator = kani::any();
494+
let _ = obj.shrink(kani::any());
495+
}
496+
}

0 commit comments

Comments
 (0)