about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2023-12-05 07:12:28 +0000
committerbors <bors@rust-lang.org>2023-12-05 07:12:28 +0000
commit73db2e48d78750d96bb54915738d46d365395226 (patch)
tree8fe1f2530f94a2fbabf5ba2c69cd2d5a55e78537
parent88d905cb3a09054665b9cee9b7a3ee0c139f8df7 (diff)
parent1fa8fd800f7cdd245b8ea73dd0673a1cf434d925 (diff)
downloadrust-73db2e48d78750d96bb54915738d46d365395226.tar.gz
rust-73db2e48d78750d96bb54915738d46d365395226.zip
Auto merge of #3211 - RalfJung:promise, r=RalfJung
fix promising a very large alignment

Also make use of https://github.com/rust-lang/rust/pull/118565 to simplify some SIMD intrinsics, while we are at it
-rw-r--r--src/tools/miri/src/shims/foreign_items.rs15
-rw-r--r--src/tools/miri/src/shims/intrinsics/simd.rs13
-rw-r--r--src/tools/miri/tests/fail/unaligned_pointers/promise_alignment_zero.rs8
-rw-r--r--src/tools/miri/tests/fail/unaligned_pointers/promise_alignment_zero.stderr14
-rw-r--r--src/tools/miri/tests/pass/align_offset_symbolic.rs12
-rw-r--r--src/tools/miri/tests/pass/issues/issue-3200-packed2-field-offset.rs2
6 files changed, 48 insertions, 16 deletions
diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs
index 15432c5dd9c..8ddfc05dd30 100644
--- a/src/tools/miri/src/shims/foreign_items.rs
+++ b/src/tools/miri/src/shims/foreign_items.rs
@@ -558,14 +558,23 @@ trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
 
             // Promises that a pointer has a given symbolic alignment.
             "miri_promise_symbolic_alignment" => {
+                use rustc_target::abi::AlignFromBytesError;
+
                 let [ptr, align] = this.check_shim(abi, Abi::Rust, link_name, args)?;
                 let ptr = this.read_pointer(ptr)?;
                 let align = this.read_target_usize(align)?;
-                let Ok(align) = Align::from_bytes(align) else {
+                if !align.is_power_of_two() {
                     throw_unsup_format!(
-                        "`miri_promise_symbolic_alignment`: alignment must be a power of 2"
+                        "`miri_promise_symbolic_alignment`: alignment must be a power of 2, got {align}"
                     );
-                };
+                }
+                let align = Align::from_bytes(align).unwrap_or_else(|err| {
+                    match err {
+                        AlignFromBytesError::NotPowerOfTwo(_) => unreachable!(),
+                        // When the alignment is a power of 2 but too big, clamp it to MAX.
+                        AlignFromBytesError::TooLarge(_) => Align::MAX,
+                    }
+                });
                 let (_, addr) = ptr.into_parts(); // we know the offset is absolute
                 // Cannot panic since `align` is a power of 2 and hence non-zero.
                 if addr.bytes().checked_rem(align.bytes()).unwrap() != 0 {
diff --git a/src/tools/miri/src/shims/intrinsics/simd.rs b/src/tools/miri/src/shims/intrinsics/simd.rs
index a514cadcec9..e17c06be9b8 100644
--- a/src/tools/miri/src/shims/intrinsics/simd.rs
+++ b/src/tools/miri/src/shims/intrinsics/simd.rs
@@ -115,18 +115,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                             }
                         }
                         Op::Numeric(name) => {
-                            assert!(op.layout.ty.is_integral());
-                            let size = op.layout.size;
-                            let bits = op.to_scalar().to_bits(size).unwrap();
-                            let extra = 128u128.checked_sub(u128::from(size.bits())).unwrap();
-                            let bits_out = match name {
-                                sym::ctlz => u128::from(bits.leading_zeros()).checked_sub(extra).unwrap(),
-                                sym::cttz => u128::from((bits << extra).trailing_zeros()).checked_sub(extra).unwrap(),
-                                sym::bswap => (bits << extra).swap_bytes(),
-                                sym::bitreverse => (bits << extra).reverse_bits(),
-                                _ => unreachable!(),
-                            };
-                            Scalar::from_uint(bits_out, size)
+                            this.numeric_intrinsic(name, op.to_scalar(), op.layout)?
                         }
                     };
                     this.write_scalar(val, &dest)?;
diff --git a/src/tools/miri/tests/fail/unaligned_pointers/promise_alignment_zero.rs b/src/tools/miri/tests/fail/unaligned_pointers/promise_alignment_zero.rs
new file mode 100644
index 00000000000..5b0638b1fdf
--- /dev/null
+++ b/src/tools/miri/tests/fail/unaligned_pointers/promise_alignment_zero.rs
@@ -0,0 +1,8 @@
+#[path = "../../utils/mod.rs"]
+mod utils;
+
+fn main() {
+    let buffer = [0u32; 128];
+    unsafe { utils::miri_promise_symbolic_alignment(buffer.as_ptr().cast(), 0) };
+    //~^ERROR: alignment must be a power of 2
+}
diff --git a/src/tools/miri/tests/fail/unaligned_pointers/promise_alignment_zero.stderr b/src/tools/miri/tests/fail/unaligned_pointers/promise_alignment_zero.stderr
new file mode 100644
index 00000000000..b3327e04933
--- /dev/null
+++ b/src/tools/miri/tests/fail/unaligned_pointers/promise_alignment_zero.stderr
@@ -0,0 +1,14 @@
+error: unsupported operation: `miri_promise_symbolic_alignment`: alignment must be a power of 2, got 0
+  --> $DIR/promise_alignment_zero.rs:LL:CC
+   |
+LL |     unsafe { utils::miri_promise_symbolic_alignment(buffer.as_ptr().cast(), 0) };
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `miri_promise_symbolic_alignment`: alignment must be a power of 2, got 0
+   |
+   = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support
+   = note: BACKTRACE:
+   = note: inside `main` at $DIR/promise_alignment_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/align_offset_symbolic.rs b/src/tools/miri/tests/pass/align_offset_symbolic.rs
index 292858ebc2e..3e493952d28 100644
--- a/src/tools/miri/tests/pass/align_offset_symbolic.rs
+++ b/src/tools/miri/tests/pass/align_offset_symbolic.rs
@@ -90,9 +90,21 @@ fn test_cstr() {
     std::ffi::CStr::from_bytes_with_nul(b"this is a test that is longer than 16 bytes\0").unwrap();
 }
 
+fn huge_align() {
+    #[cfg(target_pointer_width = "64")]
+    const SIZE: usize = 1 << 47;
+    #[cfg(target_pointer_width = "32")]
+    const SIZE: usize = 1 << 30;
+    #[cfg(target_pointer_width = "16")]
+    const SIZE: usize = 1 << 13;
+    struct HugeSize([u8; SIZE - 1]);
+    let _ = std::ptr::invalid::<HugeSize>(SIZE).align_offset(SIZE);
+}
+
 fn main() {
     test_align_to();
     test_from_utf8();
     test_u64_array();
     test_cstr();
+    huge_align();
 }
diff --git a/src/tools/miri/tests/pass/issues/issue-3200-packed2-field-offset.rs b/src/tools/miri/tests/pass/issues/issue-3200-packed2-field-offset.rs
index a5cf337da02..a8a7387ecdc 100644
--- a/src/tools/miri/tests/pass/issues/issue-3200-packed2-field-offset.rs
+++ b/src/tools/miri/tests/pass/issues/issue-3200-packed2-field-offset.rs
@@ -30,7 +30,7 @@ fn main() {
     unsafe {
         let p = PackedSized { f: 0, d: [1, 2, 3, 4] };
         let p = p.unsize() as *const PackedUnsized;
-        // Make sure the size computation correctly adds exact 1 byte of padding
+        // Make sure the size computation correctly adds exactly 1 byte of padding
         // in front of the `d` field.
         assert_eq!(mem::size_of_val_raw(p), 1 + 1 + 4 * 4);
         // And likewise for the offset computation.