about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/tools/miri/src/shims/alloc.rs27
-rw-r--r--src/tools/miri/tests/fail-dep/libc/malloc_zero_double_free.rs7
-rw-r--r--src/tools/miri/tests/fail-dep/libc/malloc_zero_double_free.stderr25
-rw-r--r--src/tools/miri/tests/fail-dep/libc/malloc_zero_memory_leak.rs5
-rw-r--r--src/tools/miri/tests/fail-dep/libc/malloc_zero_memory_leak.stderr15
-rw-r--r--src/tools/miri/tests/pass-dep/libc/libc-mem.rs14
6 files changed, 74 insertions, 19 deletions
diff --git a/src/tools/miri/src/shims/alloc.rs b/src/tools/miri/src/shims/alloc.rs
index 61e639f76ed..4eefb8b439b 100644
--- a/src/tools/miri/src/shims/alloc.rs
+++ b/src/tools/miri/src/shims/alloc.rs
@@ -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(
diff --git a/src/tools/miri/tests/fail-dep/libc/malloc_zero_double_free.rs b/src/tools/miri/tests/fail-dep/libc/malloc_zero_double_free.rs
new file mode 100644
index 00000000000..3298d61c8e8
--- /dev/null
+++ b/src/tools/miri/tests/fail-dep/libc/malloc_zero_double_free.rs
@@ -0,0 +1,7 @@
+fn main() {
+    unsafe {
+        let ptr = libc::malloc(0);
+        libc::free(ptr);
+        libc::free(ptr); //~ERROR: dangling
+    }
+}
diff --git a/src/tools/miri/tests/fail-dep/libc/malloc_zero_double_free.stderr b/src/tools/miri/tests/fail-dep/libc/malloc_zero_double_free.stderr
new file mode 100644
index 00000000000..6437c9dbeb4
--- /dev/null
+++ b/src/tools/miri/tests/fail-dep/libc/malloc_zero_double_free.stderr
@@ -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
+
diff --git a/src/tools/miri/tests/fail-dep/libc/malloc_zero_memory_leak.rs b/src/tools/miri/tests/fail-dep/libc/malloc_zero_memory_leak.rs
new file mode 100644
index 00000000000..b09a74f41d7
--- /dev/null
+++ b/src/tools/miri/tests/fail-dep/libc/malloc_zero_memory_leak.rs
@@ -0,0 +1,5 @@
+fn main() {
+    unsafe {
+        let _ptr = libc::malloc(0); //~ERROR: memory leak
+    }
+}
diff --git a/src/tools/miri/tests/fail-dep/libc/malloc_zero_memory_leak.stderr b/src/tools/miri/tests/fail-dep/libc/malloc_zero_memory_leak.stderr
new file mode 100644
index 00000000000..65ce0dcdcdd
--- /dev/null
+++ b/src/tools/miri/tests/fail-dep/libc/malloc_zero_memory_leak.stderr
@@ -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
+
diff --git a/src/tools/miri/tests/pass-dep/libc/libc-mem.rs b/src/tools/miri/tests/pass-dep/libc/libc-mem.rs
index 33cdc18b70f..5df3ace7496 100644
--- a/src/tools/miri/tests/pass-dep/libc/libc-mem.rs
+++ b/src/tools/miri/tests/pass-dep/libc/libc-mem.rs
@@ -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());