Skip to content

Commit b80ff2a

Browse files
zhassan-awstedinski
authored andcommitted
Replace the hook for realloc with a C implementation (rust-lang#1088)
Co-authored-by: Daniel Schwartz-Narbonne
1 parent 36db3de commit b80ff2a

File tree

10 files changed

+155
-43
lines changed

10 files changed

+155
-43
lines changed

kani-compiler/src/codegen_cprover_gotoc/overrides/hooks.rs

Lines changed: 0 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -548,47 +548,6 @@ impl<'tcx> GotocHook<'tcx> for RustDealloc {
548548
}
549549
}
550550

551-
struct RustRealloc;
552-
553-
impl<'tcx> GotocHook<'tcx> for RustRealloc {
554-
fn hook_applies(&self, tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> bool {
555-
let name = tcx.symbol_name(instance).name.to_string();
556-
name == "__rust_realloc"
557-
}
558-
559-
fn handle(
560-
&self,
561-
tcx: &mut GotocCtx<'tcx>,
562-
_instance: Instance<'tcx>,
563-
mut fargs: Vec<Expr>,
564-
assign_to: Option<Place<'tcx>>,
565-
target: Option<BasicBlock>,
566-
span: Option<Span>,
567-
) -> Stmt {
568-
let loc = tcx.codegen_span_option(span);
569-
let p = assign_to.unwrap();
570-
let target = target.unwrap();
571-
let ptr = fargs.remove(0).cast_to(Type::void_pointer());
572-
fargs.remove(0); // old_size
573-
fargs.remove(0); // align
574-
let size = fargs.remove(0);
575-
Stmt::block(
576-
vec![
577-
unwrap_or_return_codegen_unimplemented_stmt!(tcx, tcx.codegen_place(&p))
578-
.goto_expr
579-
.assign(
580-
BuiltinFn::Realloc
581-
.call(vec![ptr, size], loc.clone())
582-
.cast_to(Type::unsigned_int(8).to_pointer()),
583-
loc.clone(),
584-
),
585-
Stmt::goto(tcx.current_fn().find_label(&target), loc.clone()),
586-
],
587-
loc,
588-
)
589-
}
590-
}
591-
592551
struct RustAllocZeroed;
593552

594553
impl<'tcx> GotocHook<'tcx> for RustAllocZeroed {
@@ -680,7 +639,6 @@ pub fn fn_hooks<'tcx>() -> GotocHooks<'tcx> {
680639
Rc::new(RustAlloc),
681640
Rc::new(RustAllocZeroed),
682641
Rc::new(RustDealloc),
683-
Rc::new(RustRealloc),
684642
Rc::new(SliceFromRawPart),
685643
],
686644
}

library/kani/kani_lib.c

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,36 @@
11
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
22
// SPDX-License-Identifier: Apache-2.0 OR MIT
3+
4+
#include <assert.h>
5+
#include <stddef.h>
6+
#include <stdint.h>
7+
#include <stdlib.h>
8+
#include <string.h>
9+
10+
// This is a C implementation of the __rust_realloc function that has the following signature:
11+
// fn __rust_realloc(ptr: *mut u8, old_size: usize, align: usize, new_size: usize) -> *mut u8;
12+
// This low-level function is called by std::alloc:realloc, and its
13+
// implementation is provided by the compiler backend, so we need to provide an
14+
// implementation for it to prevent verification failure due to missing function
15+
// definition.
16+
// For safety, refer to the documentation of GlobalAlloc::realloc:
17+
// https://doc.rust-lang.org/std/alloc/trait.GlobalAlloc.html#method.realloc
18+
uint8_t *__rust_realloc(uint8_t *ptr, size_t old_size, size_t align, size_t new_size)
19+
{
20+
// Passing a NULL pointer is undefined behavior
21+
__CPROVER_assert(ptr != 0, "realloc called with a null pointer");
22+
__CPROVER_assume(ptr != 0);
23+
24+
// Passing a new_size of 0 is undefined behavior
25+
__CPROVER_assert(new_size > 0, "realloc called with a size of 0");
26+
__CPROVER_assume(new_size > 0);
27+
28+
uint8_t *result = malloc(new_size);
29+
if (result) {
30+
size_t bytes_to_copy = new_size < old_size ? new_size : old_size;
31+
memcpy(result, ptr, bytes_to_copy);
32+
free(ptr);
33+
}
34+
35+
return result;
36+
}

tests/expected/realloc/null/expected

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Status: FAILURE\
2+
Description: "realloc called with a null pointer"
3+
4+
VERIFICATION:- FAILED

tests/expected/realloc/null/main.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0 OR MIT
3+
4+
// Calling realloc with a null pointer fails
5+
6+
use std::alloc::{realloc, Layout};
7+
8+
#[kani::proof]
9+
fn main() {
10+
unsafe {
11+
let layout = Layout::array::<i32>(0).unwrap();
12+
let ptr: *const u8 = std::ptr::null();
13+
14+
let _ptr = realloc(ptr as *mut u8, layout, 12);
15+
}
16+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Status: FAILURE\
2+
Description: "dereference failure: pointer outside object bounds"
3+
4+
VERIFICATION:- FAILED

tests/expected/realloc/shrink/main.rs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0 OR MIT
3+
4+
// Use realloc to shrink the size of the allocated block and make sure
5+
// out-of-bound accesses result in verification failure
6+
7+
use std::alloc::{alloc, dealloc, realloc, Layout};
8+
9+
#[kani::proof]
10+
fn main() {
11+
unsafe {
12+
let mut len = 5;
13+
let mut layout = Layout::array::<i16>(len).unwrap();
14+
let ptr = alloc(layout);
15+
16+
*(ptr as *mut i16) = 5557;
17+
*(ptr as *mut i16).offset(1) = 381;
18+
*(ptr as *mut i16).offset(2) = -782;
19+
*(ptr as *mut i16).offset(3) = -1294;
20+
*(ptr as *mut i16).offset(4) = 22222;
21+
22+
// realloc to a smaller size (2 i16 elements = 4 bytes)
23+
let ptr = realloc(ptr as *mut u8, layout, 4);
24+
len = 2;
25+
layout = Layout::array::<i16>(len).unwrap();
26+
27+
// the first two elements should remain intact
28+
assert_eq!(*(ptr as *mut i16), 5557);
29+
assert_eq!(*(ptr as *mut i16).offset(1), 381);
30+
// this should be an invalid memory access
31+
let _x = *(ptr as *mut i16).offset(2);
32+
33+
dealloc(ptr, layout);
34+
}
35+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Status: FAILURE\
2+
Description: "realloc called with a size of 0"
3+
4+
VERIFICATION:- FAILED
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0 OR MIT
3+
4+
// Calling realloc with a size of zero fails
5+
6+
use std::alloc::{alloc, realloc, Layout};
7+
8+
#[kani::proof]
9+
fn main() {
10+
unsafe {
11+
let layout = Layout::array::<i32>(3).unwrap();
12+
let ptr = alloc(layout);
13+
14+
*(ptr as *mut i32) = 888;
15+
*(ptr as *mut i32).offset(1) = 777;
16+
*(ptr as *mut i32).offset(2) = -432;
17+
18+
let _ptr = realloc(ptr as *mut u8, layout, 0);
19+
}
20+
}

tests/kani/Realloc/two_reallocs.rs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0 OR MIT
3+
4+
// Perform two reallocs in a row and make sure the data is properly copied
5+
6+
use std::alloc::{alloc, dealloc, realloc, Layout};
7+
8+
#[kani::proof]
9+
fn main() {
10+
unsafe {
11+
let mut len = 4;
12+
let mut layout = Layout::array::<u16>(len).unwrap();
13+
let mut sz = layout.size();
14+
let ptr = alloc(layout);
15+
16+
*(ptr as *mut u16) = 551;
17+
*(ptr as *mut u16).offset(1) = 12;
18+
*(ptr as *mut u16).offset(2) = 8928;
19+
*(ptr as *mut u16).offset(3) = 499;
20+
21+
sz *= 2;
22+
let ptr = realloc(ptr as *mut u8, layout, sz);
23+
len *= 2;
24+
layout = Layout::array::<u16>(len).unwrap();
25+
26+
sz *= 2;
27+
let ptr = realloc(ptr as *mut u8, layout, sz);
28+
len *= 2;
29+
layout = Layout::array::<u16>(len).unwrap();
30+
31+
assert_eq!(*(ptr as *mut u16), 551);
32+
assert_eq!(*(ptr as *mut u16).offset(1), 12);
33+
assert_eq!(*(ptr as *mut u16).offset(2), 8928);
34+
assert_eq!(*(ptr as *mut u16).offset(3), 499);
35+
36+
dealloc(ptr, layout);
37+
}
38+
}

tests/kani/Vectors/fixme_702.rs renamed to tests/kani/Vectors/push.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
22
// SPDX-License-Identifier: Apache-2.0 OR MIT
33

4-
// Failing example from https://github.com/model-checking/kani/issues/702
54
// Push 5 elements to force the vector to resize, then check that the values were correctly copied.
65
#[kani::proof]
76
fn main() {

0 commit comments

Comments
 (0)