Implement non-null pointer for malloc(0)
This commit is contained in:
parent
4d6d9a95f6
commit
4ab79e5622
6 changed files with 74 additions and 19 deletions
|
@ -36,6 +36,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
if kind == MiriMemoryKind::WinHeap || size >= min_align {
|
||||
return Align::from_bytes(min_align).unwrap();
|
||||
}
|
||||
if size == 0 {
|
||||
return Align::ONE;
|
||||
}
|
||||
// We have `size < min_align`. Round `size` *down* to the next power of two and use that.
|
||||
fn prev_power_of_two(x: u64) -> u64 {
|
||||
let next_pow2 = x.next_power_of_two();
|
||||
|
@ -85,21 +88,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
kind: MiriMemoryKind,
|
||||
) -> InterpResult<'tcx, Pointer<Option<Provenance>>> {
|
||||
let this = self.eval_context_mut();
|
||||
if size == 0 {
|
||||
Ok(Pointer::null())
|
||||
} else {
|
||||
let align = this.min_align(size, kind);
|
||||
let ptr = this.allocate_ptr(Size::from_bytes(size), align, kind.into())?;
|
||||
if zero_init {
|
||||
// We just allocated this, the access is definitely in-bounds and fits into our address space.
|
||||
this.write_bytes_ptr(
|
||||
ptr.into(),
|
||||
iter::repeat(0u8).take(usize::try_from(size).unwrap()),
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
Ok(ptr.into())
|
||||
let align = this.min_align(size, kind);
|
||||
let ptr = this.allocate_ptr(Size::from_bytes(size), align, kind.into())?;
|
||||
if zero_init {
|
||||
// We just allocated this, the access is definitely in-bounds and fits into our address space.
|
||||
this.write_bytes_ptr(
|
||||
ptr.into(),
|
||||
iter::repeat(0u8).take(usize::try_from(size).unwrap()),
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
Ok(ptr.into())
|
||||
}
|
||||
|
||||
fn free(
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
fn main() {
|
||||
unsafe {
|
||||
let ptr = libc::malloc(0);
|
||||
libc::free(ptr);
|
||||
libc::free(ptr); //~ERROR: dangling
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
error: Undefined Behavior: memory access failed: ALLOC has been freed, so this pointer is dangling
|
||||
--> $DIR/malloc_zero_double_free.rs:LL:CC
|
||||
|
|
||||
LL | libc::free(ptr);
|
||||
| ^^^^^^^^^^^^^^^ memory access failed: ALLOC has been freed, so this pointer is dangling
|
||||
|
|
||||
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
|
||||
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
|
||||
help: ALLOC was allocated here:
|
||||
--> $DIR/malloc_zero_double_free.rs:LL:CC
|
||||
|
|
||||
LL | let ptr = libc::malloc(0);
|
||||
| ^^^^^^^^^^^^^^^
|
||||
help: ALLOC was deallocated here:
|
||||
--> $DIR/malloc_zero_double_free.rs:LL:CC
|
||||
|
|
||||
LL | libc::free(ptr);
|
||||
| ^^^^^^^^^^^^^^^
|
||||
= note: BACKTRACE (of the first span):
|
||||
= note: inside `main` at $DIR/malloc_zero_double_free.rs:LL:CC
|
||||
|
||||
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
fn main() {
|
||||
unsafe {
|
||||
let _ptr = libc::malloc(0); //~ERROR: memory leak
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
error: memory leaked: ALLOC (C heap, size: 0, align: 1), allocated here:
|
||||
--> $DIR/malloc_zero_memory_leak.rs:LL:CC
|
||||
|
|
||||
LL | let _ptr = libc::malloc(0);
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: BACKTRACE:
|
||||
= note: inside `main` at $DIR/malloc_zero_memory_leak.rs:LL:CC
|
||||
|
||||
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
|
||||
|
||||
note: the evaluated program leaked memory, pass `-Zmiri-ignore-leaks` to disable this check
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
|
@ -110,9 +110,10 @@ fn test_malloc() {
|
|||
}
|
||||
|
||||
unsafe {
|
||||
// Realloc with size 0 is okay for the null pointer
|
||||
// Realloc with size 0 is okay for the null pointer (and acts like `malloc(0)`)
|
||||
let p2 = libc::realloc(ptr::null_mut(), 0);
|
||||
assert!(p2.is_null());
|
||||
assert!(!p2.is_null());
|
||||
libc::free(p2);
|
||||
}
|
||||
|
||||
unsafe {
|
||||
|
@ -126,13 +127,16 @@ fn test_malloc() {
|
|||
fn test_calloc() {
|
||||
unsafe {
|
||||
let p1 = libc::calloc(0, 0);
|
||||
assert!(p1.is_null());
|
||||
assert!(!p1.is_null());
|
||||
libc::free(p1);
|
||||
|
||||
let p2 = libc::calloc(20, 0);
|
||||
assert!(p2.is_null());
|
||||
assert!(!p2.is_null());
|
||||
libc::free(p2);
|
||||
|
||||
let p3 = libc::calloc(0, 20);
|
||||
assert!(p3.is_null());
|
||||
assert!(!p3.is_null());
|
||||
libc::free(p3);
|
||||
|
||||
let p4 = libc::calloc(4, 8);
|
||||
assert!(!p4.is_null());
|
||||
|
|
Loading…
Add table
Reference in a new issue