about summary refs log tree commit diff
diff options
context:
space:
mode:
authorRalf Jung <post@ralfj.de>2024-04-18 10:32:44 +0200
committerRalf Jung <post@ralfj.de>2024-04-18 12:06:29 +0200
commit73e333ac44b27bee0de86920de72b3097feb648b (patch)
tree45e3d1325f1fc7d1d9ecbeb61dae492d08d9a1eb
parent5697f731b4aecf418b79212b78055994df62d66e (diff)
downloadrust-73e333ac44b27bee0de86920de72b3097feb648b.tar.gz
rust-73e333ac44b27bee0de86920de72b3097feb648b.zip
make realloc with a size of zero fail
-rw-r--r--src/tools/miri/src/shims/foreign_items.rs6
-rw-r--r--src/tools/miri/tests/fail-dep/realloc-zero.rs10
-rw-r--r--src/tools/miri/tests/fail-dep/realloc-zero.stderr15
-rw-r--r--src/tools/miri/tests/pass-dep/malloc.rs5
4 files changed, 31 insertions, 5 deletions
diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs
index acbc36b05b7..6a6ad33e52f 100644
--- a/src/tools/miri/src/shims/foreign_items.rs
+++ b/src/tools/miri/src/shims/foreign_items.rs
@@ -278,6 +278,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
         let this = self.eval_context_mut();
         let new_align = this.min_align(new_size, kind);
         if this.ptr_is_null(old_ptr)? {
+            // Here we must behave like `malloc`.
             if new_size == 0 {
                 Ok(Pointer::null())
             } else {
@@ -287,8 +288,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
             }
         } else {
             if new_size == 0 {
-                this.deallocate_ptr(old_ptr, None, kind.into())?;
-                Ok(Pointer::null())
+                // C, in their infinite wisdom, made this UB.
+                // <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2464.pdf>
+                throw_ub_format!("`realloc` with a size of zero");
             } else {
                 let new_ptr = this.reallocate_ptr(
                     old_ptr,
diff --git a/src/tools/miri/tests/fail-dep/realloc-zero.rs b/src/tools/miri/tests/fail-dep/realloc-zero.rs
new file mode 100644
index 00000000000..1482798e90c
--- /dev/null
+++ b/src/tools/miri/tests/fail-dep/realloc-zero.rs
@@ -0,0 +1,10 @@
+//@ignore-target-windows: No libc on Windows
+
+fn main() {
+    unsafe {
+        let p1 = libc::malloc(20);
+        // C made this UB...
+        let p2 = libc::realloc(p1, 0); //~ERROR: `realloc` with a size of zero
+        assert!(p2.is_null());
+    }
+}
diff --git a/src/tools/miri/tests/fail-dep/realloc-zero.stderr b/src/tools/miri/tests/fail-dep/realloc-zero.stderr
new file mode 100644
index 00000000000..749a61f7396
--- /dev/null
+++ b/src/tools/miri/tests/fail-dep/realloc-zero.stderr
@@ -0,0 +1,15 @@
+error: Undefined Behavior: `realloc` with a size of zero
+  --> $DIR/realloc-zero.rs:LL:CC
+   |
+LL |         let p2 = libc::realloc(p1, 0);
+   |                  ^^^^^^^^^^^^^^^^^^^^ `realloc` with a size of zero
+   |
+   = 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
+   = note: BACKTRACE:
+   = note: inside `main` at $DIR/realloc-zero.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/pass-dep/malloc.rs b/src/tools/miri/tests/pass-dep/malloc.rs
index f5e014c000d..35cd137931f 100644
--- a/src/tools/miri/tests/pass-dep/malloc.rs
+++ b/src/tools/miri/tests/pass-dep/malloc.rs
@@ -34,9 +34,8 @@ fn main() {
     }
 
     unsafe {
-        let p1 = libc::malloc(20);
-
-        let p2 = libc::realloc(p1, 0);
+        // Realloc with size 0 is okay for the null pointer
+        let p2 = libc::realloc(ptr::null_mut(), 0);
         assert!(p2.is_null());
     }