about summary refs log tree commit diff
diff options
context:
space:
mode:
authorDavid Carlier <devnexen@gmail.com>2024-05-07 23:11:48 +0000
committerDavid Carlier <devnexen@gmail.com>2024-05-18 12:45:34 +0100
commit5ea21ca486794f1f1ae038d420bdaee92ff5be5d (patch)
tree538efa90ec74f878d1abad9369a4c8345a642e70
parent7e5b9e215ddf8d183e944d088a105b2aa7ad4074 (diff)
downloadrust-5ea21ca486794f1f1ae038d420bdaee92ff5be5d.tar.gz
rust-5ea21ca486794f1f1ae038d420bdaee92ff5be5d.zip
support aligned_alloc for unixes support.
-rw-r--r--src/tools/miri/src/shims/alloc.rs38
-rw-r--r--src/tools/miri/src/shims/unix/foreign_items.rs11
-rw-r--r--src/tools/miri/src/shims/wasi/foreign_items.rs9
-rw-r--r--src/tools/miri/tests/fail-dep/libc/aligned_alloc_size_zero_leak.rs15
-rw-r--r--src/tools/miri/tests/fail-dep/libc/aligned_alloc_size_zero_leak.stderr15
-rw-r--r--src/tools/miri/tests/pass-dep/libc/libc-mem.rs40
6 files changed, 128 insertions, 0 deletions
diff --git a/src/tools/miri/src/shims/alloc.rs b/src/tools/miri/src/shims/alloc.rs
index d0f36bd4757..6c18989caad 100644
--- a/src/tools/miri/src/shims/alloc.rs
+++ b/src/tools/miri/src/shims/alloc.rs
@@ -172,4 +172,42 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
             }
         }
     }
+
+    fn aligned_alloc(
+        &mut self,
+        align: u64,
+        size: u64,
+    ) -> InterpResult<'tcx, Pointer<Option<Provenance>>> {
+        let this = self.eval_context_mut();
+        // Alignment must be a power of 2, and "supported by the implementation".
+        // We decide that "supported by the implementation" means that the
+        // size must be a multiple of the alignment. (This restriction seems common
+        // enough that it is stated on <https://en.cppreference.com/w/c/memory/aligned_alloc>
+        // as a general rule, but the actual standard has no such rule.)
+        // If any of these are violated, we have to return NULL.
+        // All fundamental alignments must be supported.
+        //
+        // macOS and Illumos are buggy in that they require the alignment
+        // to be at least the size of a pointer, so they do not support all fundamental
+        // alignments. We do not emulate those platform bugs.
+        //
+        // Linux also sets errno to EINVAL, but that's non-standard behavior that we do not
+        // emulate.
+        // FreeBSD says some of these cases are UB but that's violating the C standard.
+        // http://en.cppreference.com/w/cpp/memory/c/aligned_alloc
+        // Linux: https://linux.die.net/man/3/aligned_alloc
+        // FreeBSD: https://man.freebsd.org/cgi/man.cgi?query=aligned_alloc&apropos=0&sektion=3&manpath=FreeBSD+9-current&format=html
+        match size.checked_rem(align) {
+            Some(0) if align.is_power_of_two() => {
+                let align = align.max(this.malloc_align(size).bytes());
+                let ptr = this.allocate_ptr(
+                    Size::from_bytes(size),
+                    Align::from_bytes(align).unwrap(),
+                    MiriMemoryKind::C.into(),
+                )?;
+                Ok(ptr.into())
+            }
+            _ => Ok(Pointer::null()),
+        }
+    }
 }
diff --git a/src/tools/miri/src/shims/unix/foreign_items.rs b/src/tools/miri/src/shims/unix/foreign_items.rs
index 78d297d4b04..ca59e6e6501 100644
--- a/src/tools/miri/src/shims/unix/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/foreign_items.rs
@@ -295,6 +295,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                     }
                 }
             }
+            "aligned_alloc" => {
+                // This is a C11 function, we assume all Unixes have it.
+                // (MSVC explicitly does not support this.)
+                let [align, size] =
+                    this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+                let align = this.read_target_usize(align)?;
+                let size = this.read_target_usize(size)?;
+
+                let res = this.aligned_alloc(align, size)?;
+                this.write_pointer(res, dest)?;
+            }
 
             // Dynamic symbol loading
             "dlsym" => {
diff --git a/src/tools/miri/src/shims/wasi/foreign_items.rs b/src/tools/miri/src/shims/wasi/foreign_items.rs
index 12bf0490932..9c0a8e66390 100644
--- a/src/tools/miri/src/shims/wasi/foreign_items.rs
+++ b/src/tools/miri/src/shims/wasi/foreign_items.rs
@@ -26,6 +26,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                 let result = this.posix_memalign(memptr, align, size)?;
                 this.write_scalar(result, dest)?;
             }
+            "aligned_alloc" => {
+                let [align, size] =
+                    this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+                let align = this.read_target_usize(align)?;
+                let size = this.read_target_usize(size)?;
+
+                let res = this.aligned_alloc(align, size)?;
+                this.write_pointer(res, dest)?;
+            }
 
             _ => return Ok(EmulateItemResult::NotSupported),
         }
diff --git a/src/tools/miri/tests/fail-dep/libc/aligned_alloc_size_zero_leak.rs b/src/tools/miri/tests/fail-dep/libc/aligned_alloc_size_zero_leak.rs
new file mode 100644
index 00000000000..9a33cdccd27
--- /dev/null
+++ b/src/tools/miri/tests/fail-dep/libc/aligned_alloc_size_zero_leak.rs
@@ -0,0 +1,15 @@
+//@ignore-target-windows: Windows does not support the standard C11 aligned_alloc.
+
+fn main() {
+    // libc doesn't have this function (https://github.com/rust-lang/libc/issues/3689),
+    // so we declare it ourselves.
+    extern "C" {
+        fn aligned_alloc(alignment: libc::size_t, size: libc::size_t) -> *mut libc::c_void;
+    }
+
+    // Make sure even zero-sized allocations need to be freed.
+
+    unsafe {
+        aligned_alloc(2, 0); //~ERROR: memory leaked
+    }
+}
diff --git a/src/tools/miri/tests/fail-dep/libc/aligned_alloc_size_zero_leak.stderr b/src/tools/miri/tests/fail-dep/libc/aligned_alloc_size_zero_leak.stderr
new file mode 100644
index 00000000000..b0756d57212
--- /dev/null
+++ b/src/tools/miri/tests/fail-dep/libc/aligned_alloc_size_zero_leak.stderr
@@ -0,0 +1,15 @@
+error: memory leaked: ALLOC (C heap, size: 0, align: 2), allocated here:
+  --> $DIR/aligned_alloc_size_zero_leak.rs:LL:CC
+   |
+LL |         aligned_alloc(2, 0);
+   |         ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: BACKTRACE:
+   = note: inside `main` at $DIR/aligned_alloc_size_zero_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 5bd205dd085..25aef0a183a 100644
--- a/src/tools/miri/tests/pass-dep/libc/libc-mem.rs
+++ b/src/tools/miri/tests/pass-dep/libc/libc-mem.rs
@@ -241,6 +241,44 @@ fn test_reallocarray() {
     }
 }
 
+#[cfg(not(target_os = "windows"))]
+fn test_aligned_alloc() {
+    // libc doesn't have this function (https://github.com/rust-lang/libc/issues/3689),
+    // so we declare it ourselves.
+    extern "C" {
+        fn aligned_alloc(alignment: libc::size_t, size: libc::size_t) -> *mut libc::c_void;
+    }
+    // size not a multiple of the alignment
+    unsafe {
+        let p = aligned_alloc(16, 3);
+        assert_eq!(p, ptr::null_mut());
+    }
+
+    // alignment not power of 2
+    unsafe {
+        let p = aligned_alloc(63, 8);
+        assert_eq!(p, ptr::null_mut());
+    }
+
+    // alignment lesser than a word but still a successful allocation
+    unsafe {
+        let p = aligned_alloc(1, 4);
+        assert!(!p.is_null());
+        assert!(p.is_aligned_to(4));
+        libc::free(p);
+    }
+
+    // repeated tests on correct alignment/size
+    for _ in 0..16 {
+        unsafe {
+            let p = aligned_alloc(16, 16);
+            assert!(!p.is_null());
+            assert!(p.is_aligned_to(16));
+            libc::free(p);
+        }
+    }
+}
+
 fn main() {
     test_malloc();
     test_calloc();
@@ -254,6 +292,8 @@ fn main() {
         target_os = "wasi",
     )))]
     test_reallocarray();
+    #[cfg(not(target_os = "windows"))]
+    test_aligned_alloc();
 
     test_memcpy();
     test_strcpy();