about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2023-03-31 08:50:35 +0000
committerbors <bors@rust-lang.org>2023-03-31 08:50:35 +0000
commit22a7a19f9333bc1fcba97ce444a3515cb5fb33e6 (patch)
tree8ac7da60c0ee60d36ef565024a75f848c98a19b6
parentec7bb8da11f3e5cc73be397b78d2aea4157df300 (diff)
parent750707801b42c0da6beeccd587925130ba2bad99 (diff)
downloadrust-22a7a19f9333bc1fcba97ce444a3515cb5fb33e6.tar.gz
rust-22a7a19f9333bc1fcba97ce444a3515cb5fb33e6.zip
Auto merge of #98112 - saethlin:mir-alignment-checks, r=oli-obk
Insert alignment checks for pointer dereferences when debug assertions are enabled

Closes https://github.com/rust-lang/rust/issues/54915

- [x] Jake tells me this sounds like a place to use `MirPatch`, but I can't figure out how to insert a new basic block with a new terminator in the middle of an existing basic block, using `MirPatch`. (if nobody else backs up this point I'm checking this as "not actually a good idea" because the code looks pretty clean to me after rearranging it a bit)
- [x] Using `CastKind::PointerExposeAddress` is definitely wrong, we don't want to expose. Calling a function to get the pointer address seems quite excessive. ~I'll see if I can add a new `CastKind`.~ `CastKind::Transmute` to the rescue!
- [x] Implement a more helpful panic message like slice bounds checking.

r? `@oli-obk`
-rw-r--r--compiler/rustc_codegen_cranelift/src/base.rs12
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/block.rs7
-rw-r--r--compiler/rustc_const_eval/src/const_eval/machine.rs6
-rw-r--r--compiler/rustc_hir/src/lang_items.rs1
-rw-r--r--compiler/rustc_middle/src/mir/mod.rs20
-rw-r--r--compiler/rustc_middle/src/mir/syntax.rs1
-rw-r--r--compiler/rustc_middle/src/mir/visit.rs4
-rw-r--r--compiler/rustc_mir_transform/src/check_alignment.rs227
-rw-r--r--compiler/rustc_mir_transform/src/lib.rs2
-rw-r--r--compiler/rustc_span/src/symbol.rs1
-rw-r--r--library/core/src/panicking.rs14
-rw-r--r--src/tools/miri/src/shims/panic.rs28
-rw-r--r--src/tools/miri/tests/fail/unaligned_pointers/alignment.rs1
-rw-r--r--src/tools/miri/tests/fail/unaligned_pointers/atomic_unaligned.rs2
-rw-r--r--src/tools/miri/tests/fail/unaligned_pointers/drop_in_place.rs2
-rw-r--r--src/tools/miri/tests/fail/unaligned_pointers/dyn_alignment.rs2
-rw-r--r--src/tools/miri/tests/fail/unaligned_pointers/intptrcast_alignment_check.rs2
-rw-r--r--src/tools/miri/tests/fail/unaligned_pointers/reference_to_packed.rs2
-rw-r--r--src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr1.rs2
-rw-r--r--src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr2.rs2
-rw-r--r--src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr3.rs2
-rw-r--r--src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr4.rs2
-rw-r--r--src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr_addr_of.rs2
-rw-r--r--src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr_zst.rs2
-rw-r--r--src/tools/miri/tests/panic/alignment-assertion.rs9
-rw-r--r--src/tools/miri/tests/panic/alignment-assertion.stderr2
-rw-r--r--src/tools/miri/tests/pass/disable-alignment-check.rs2
-rw-r--r--tests/assembly/static-relocation-model.rs1
-rw-r--r--tests/codegen/issues/issue-37945.rs1
-rw-r--r--tests/codegen/virtual-function-elimination.rs1
-rw-r--r--tests/mir-opt/inline/inline_into_box_place.main.Inline.diff8
-rw-r--r--tests/mir-opt/inline/inline_into_box_place.rs1
-rw-r--r--tests/run-make/fmt-write-bloat/Makefile4
-rw-r--r--tests/ui/mir/mir_alignment_check.rs12
-rw-r--r--tests/ui/process/signal-exit-status.rs6
35 files changed, 372 insertions, 21 deletions
diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs
index 615ef58ff58..98112fe0830 100644
--- a/compiler/rustc_codegen_cranelift/src/base.rs
+++ b/compiler/rustc_codegen_cranelift/src/base.rs
@@ -379,6 +379,18 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) {
                             source_info.span,
                         );
                     }
+                    AssertKind::MisalignedPointerDereference { ref required, ref found } => {
+                        let required = codegen_operand(fx, required).load_scalar(fx);
+                        let found = codegen_operand(fx, found).load_scalar(fx);
+                        let location = fx.get_caller_location(source_info).load_scalar(fx);
+
+                        codegen_panic_inner(
+                            fx,
+                            rustc_hir::LangItem::PanicBoundsCheck,
+                            &[required, found, location],
+                            source_info.span,
+                        );
+                    }
                     _ => {
                         let msg_str = msg.description();
                         codegen_panic(fx, msg_str, source_info);
diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs
index 2d647f5d7f2..c086d1b7f5a 100644
--- a/compiler/rustc_codegen_ssa/src/mir/block.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/block.rs
@@ -600,6 +600,13 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 // and `#[track_caller]` adds an implicit third argument.
                 (LangItem::PanicBoundsCheck, vec![index, len, location])
             }
+            AssertKind::MisalignedPointerDereference { ref required, ref found } => {
+                let required = self.codegen_operand(bx, required).immediate();
+                let found = self.codegen_operand(bx, found).immediate();
+                // It's `fn panic_bounds_check(index: usize, len: usize)`,
+                // and `#[track_caller]` adds an implicit third argument.
+                (LangItem::PanicMisalignedPointerDereference, vec![required, found, location])
+            }
             _ => {
                 let msg = bx.const_str(msg.description());
                 // It's `pub fn panic(expr: &str)`, with the wide reference being passed
diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs
index 350ce529ef5..c87ea18af4f 100644
--- a/compiler/rustc_const_eval/src/const_eval/machine.rs
+++ b/compiler/rustc_const_eval/src/const_eval/machine.rs
@@ -544,6 +544,12 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
             RemainderByZero(op) => RemainderByZero(eval_to_int(op)?),
             ResumedAfterReturn(generator_kind) => ResumedAfterReturn(*generator_kind),
             ResumedAfterPanic(generator_kind) => ResumedAfterPanic(*generator_kind),
+            MisalignedPointerDereference { ref required, ref found } => {
+                MisalignedPointerDereference {
+                    required: eval_to_int(required)?,
+                    found: eval_to_int(found)?,
+                }
+            }
         };
         Err(ConstEvalErrKind::AssertFailure(err).into())
     }
diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs
index 07faecdb6a7..eac8fd29429 100644
--- a/compiler/rustc_hir/src/lang_items.rs
+++ b/compiler/rustc_hir/src/lang_items.rs
@@ -240,6 +240,7 @@ language_item_table! {
     PanicDisplay,            sym::panic_display,       panic_display,              Target::Fn,             GenericRequirement::None;
     ConstPanicFmt,           sym::const_panic_fmt,     const_panic_fmt,            Target::Fn,             GenericRequirement::None;
     PanicBoundsCheck,        sym::panic_bounds_check,  panic_bounds_check_fn,      Target::Fn,             GenericRequirement::Exact(0);
+    PanicMisalignedPointerDereference,        sym::panic_misaligned_pointer_dereference,  panic_misaligned_pointer_dereference_fn,      Target::Fn,             GenericRequirement::Exact(0);
     PanicInfo,               sym::panic_info,          panic_info,                 Target::Struct,         GenericRequirement::None;
     PanicLocation,           sym::panic_location,      panic_location,             Target::Struct,         GenericRequirement::None;
     PanicImpl,               sym::panic_impl,          panic_impl,                 Target::Fn,             GenericRequirement::None;
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index 37356b53c02..de7e8bc861d 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -1277,7 +1277,7 @@ impl<O> AssertKind<O> {
 
     /// Getting a description does not require `O` to be printable, and does not
     /// require allocation.
-    /// The caller is expected to handle `BoundsCheck` separately.
+    /// The caller is expected to handle `BoundsCheck` and `MisalignedPointerDereference` separately.
     pub fn description(&self) -> &'static str {
         use AssertKind::*;
         match self {
@@ -1296,7 +1296,9 @@ impl<O> AssertKind<O> {
             ResumedAfterReturn(GeneratorKind::Async(_)) => "`async fn` resumed after completion",
             ResumedAfterPanic(GeneratorKind::Gen) => "generator resumed after panicking",
             ResumedAfterPanic(GeneratorKind::Async(_)) => "`async fn` resumed after panicking",
-            BoundsCheck { .. } => bug!("Unexpected AssertKind"),
+            BoundsCheck { .. } | MisalignedPointerDereference { .. } => {
+                bug!("Unexpected AssertKind")
+            }
         }
     }
 
@@ -1353,6 +1355,13 @@ impl<O> AssertKind<O> {
             Overflow(BinOp::Shl, _, r) => {
                 write!(f, "\"attempt to shift left by `{{}}`, which would overflow\", {:?}", r)
             }
+            MisalignedPointerDereference { required, found } => {
+                write!(
+                    f,
+                    "\"misaligned pointer dereference: address must be a multiple of {{}} but is {{}}\", {:?}, {:?}",
+                    required, found
+                )
+            }
             _ => write!(f, "\"{}\"", self.description()),
         }
     }
@@ -1397,6 +1406,13 @@ impl<O: fmt::Debug> fmt::Debug for AssertKind<O> {
             Overflow(BinOp::Shl, _, r) => {
                 write!(f, "attempt to shift left by `{:#?}`, which would overflow", r)
             }
+            MisalignedPointerDereference { required, found } => {
+                write!(
+                    f,
+                    "misaligned pointer dereference: address must be a multiple of {:?} but is {:?}",
+                    required, found
+                )
+            }
             _ => write!(f, "{}", self.description()),
         }
     }
diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs
index 8fb693055fa..413a7629b9a 100644
--- a/compiler/rustc_middle/src/mir/syntax.rs
+++ b/compiler/rustc_middle/src/mir/syntax.rs
@@ -760,6 +760,7 @@ pub enum AssertKind<O> {
     RemainderByZero(O),
     ResumedAfterReturn(GeneratorKind),
     ResumedAfterPanic(GeneratorKind),
+    MisalignedPointerDereference { required: O, found: O },
 }
 
 #[derive(Clone, Debug, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)]
diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs
index b39fc3aaaff..7aa446ae966 100644
--- a/compiler/rustc_middle/src/mir/visit.rs
+++ b/compiler/rustc_middle/src/mir/visit.rs
@@ -610,6 +610,10 @@ macro_rules! make_mir_visitor {
                     ResumedAfterReturn(_) | ResumedAfterPanic(_) => {
                         // Nothing to visit
                     }
+                    MisalignedPointerDereference { required, found } => {
+                        self.visit_operand(required, location);
+                        self.visit_operand(found, location);
+                    }
                 }
             }
 
diff --git a/compiler/rustc_mir_transform/src/check_alignment.rs b/compiler/rustc_mir_transform/src/check_alignment.rs
new file mode 100644
index 00000000000..996416ef22e
--- /dev/null
+++ b/compiler/rustc_mir_transform/src/check_alignment.rs
@@ -0,0 +1,227 @@
+use crate::MirPass;
+use rustc_hir::def_id::DefId;
+use rustc_index::vec::IndexVec;
+use rustc_middle::mir::*;
+use rustc_middle::mir::{
+    interpret::{ConstValue, Scalar},
+    visit::{PlaceContext, Visitor},
+};
+use rustc_middle::ty::{Ty, TyCtxt, TypeAndMut};
+use rustc_session::Session;
+
+pub struct CheckAlignment;
+
+impl<'tcx> MirPass<'tcx> for CheckAlignment {
+    fn is_enabled(&self, sess: &Session) -> bool {
+        sess.opts.debug_assertions
+    }
+
+    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+        let basic_blocks = body.basic_blocks.as_mut();
+        let local_decls = &mut body.local_decls;
+
+        for block in (0..basic_blocks.len()).rev() {
+            let block = block.into();
+            for statement_index in (0..basic_blocks[block].statements.len()).rev() {
+                let location = Location { block, statement_index };
+                let statement = &basic_blocks[block].statements[statement_index];
+                let source_info = statement.source_info;
+
+                let mut finder = PointerFinder {
+                    local_decls,
+                    tcx,
+                    pointers: Vec::new(),
+                    def_id: body.source.def_id(),
+                };
+                for (pointer, pointee_ty) in finder.find_pointers(statement) {
+                    debug!("Inserting alignment check for {:?}", pointer.ty(&*local_decls, tcx).ty);
+
+                    let new_block = split_block(basic_blocks, location);
+                    insert_alignment_check(
+                        tcx,
+                        local_decls,
+                        &mut basic_blocks[block],
+                        pointer,
+                        pointee_ty,
+                        source_info,
+                        new_block,
+                    );
+                }
+            }
+        }
+    }
+}
+
+impl<'tcx, 'a> PointerFinder<'tcx, 'a> {
+    fn find_pointers(&mut self, statement: &Statement<'tcx>) -> Vec<(Place<'tcx>, Ty<'tcx>)> {
+        self.pointers.clear();
+        self.visit_statement(statement, Location::START);
+        core::mem::take(&mut self.pointers)
+    }
+}
+
+struct PointerFinder<'tcx, 'a> {
+    local_decls: &'a mut LocalDecls<'tcx>,
+    tcx: TyCtxt<'tcx>,
+    def_id: DefId,
+    pointers: Vec<(Place<'tcx>, Ty<'tcx>)>,
+}
+
+impl<'tcx, 'a> Visitor<'tcx> for PointerFinder<'tcx, 'a> {
+    fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, _location: Location) {
+        if let PlaceContext::NonUse(_) = context {
+            return;
+        }
+        if !place.is_indirect() {
+            return;
+        }
+
+        let pointer = Place::from(place.local);
+        let pointer_ty = pointer.ty(&*self.local_decls, self.tcx).ty;
+
+        // We only want to check unsafe pointers
+        if !pointer_ty.is_unsafe_ptr() {
+            trace!("Indirect, but not an unsafe ptr, not checking {:?}", pointer_ty);
+            return;
+        }
+
+        let Some(pointee) = pointer_ty.builtin_deref(true) else {
+            debug!("Indirect but no builtin deref: {:?}", pointer_ty);
+            return;
+        };
+        let mut pointee_ty = pointee.ty;
+        if pointee_ty.is_array() || pointee_ty.is_slice() || pointee_ty.is_str() {
+            pointee_ty = pointee_ty.sequence_element_type(self.tcx);
+        }
+
+        if !pointee_ty.is_sized(self.tcx, self.tcx.param_env_reveal_all_normalized(self.def_id)) {
+            debug!("Unsafe pointer, but unsized: {:?}", pointer_ty);
+            return;
+        }
+
+        if [self.tcx.types.bool, self.tcx.types.i8, self.tcx.types.u8, self.tcx.types.str_]
+            .contains(&pointee_ty)
+        {
+            debug!("Trivially aligned pointee type: {:?}", pointer_ty);
+            return;
+        }
+
+        self.pointers.push((pointer, pointee_ty))
+    }
+}
+
+fn split_block(
+    basic_blocks: &mut IndexVec<BasicBlock, BasicBlockData<'_>>,
+    location: Location,
+) -> BasicBlock {
+    let block_data = &mut basic_blocks[location.block];
+
+    // Drain every statement after this one and move the current terminator to a new basic block
+    let new_block = BasicBlockData {
+        statements: block_data.statements.split_off(location.statement_index),
+        terminator: block_data.terminator.take(),
+        is_cleanup: block_data.is_cleanup,
+    };
+
+    basic_blocks.push(new_block)
+}
+
+fn insert_alignment_check<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    local_decls: &mut LocalDecls<'tcx>,
+    block_data: &mut BasicBlockData<'tcx>,
+    pointer: Place<'tcx>,
+    pointee_ty: Ty<'tcx>,
+    source_info: SourceInfo,
+    new_block: BasicBlock,
+) {
+    // Cast the pointer to a *const ()
+    let const_raw_ptr = tcx.mk_ptr(TypeAndMut { ty: tcx.types.unit, mutbl: Mutability::Not });
+    let rvalue = Rvalue::Cast(CastKind::PtrToPtr, Operand::Copy(pointer), const_raw_ptr);
+    let thin_ptr = local_decls.push(LocalDecl::with_source_info(const_raw_ptr, source_info)).into();
+    block_data
+        .statements
+        .push(Statement { source_info, kind: StatementKind::Assign(Box::new((thin_ptr, rvalue))) });
+
+    // Transmute the pointer to a usize (equivalent to `ptr.addr()`)
+    let rvalue = Rvalue::Cast(CastKind::Transmute, Operand::Copy(thin_ptr), tcx.types.usize);
+    let addr = local_decls.push(LocalDecl::with_source_info(tcx.types.usize, source_info)).into();
+    block_data
+        .statements
+        .push(Statement { source_info, kind: StatementKind::Assign(Box::new((addr, rvalue))) });
+
+    // Get the alignment of the pointee
+    let alignment =
+        local_decls.push(LocalDecl::with_source_info(tcx.types.usize, source_info)).into();
+    let rvalue = Rvalue::NullaryOp(NullOp::AlignOf, pointee_ty);
+    block_data.statements.push(Statement {
+        source_info,
+        kind: StatementKind::Assign(Box::new((alignment, rvalue))),
+    });
+
+    // Subtract 1 from the alignment to get the alignment mask
+    let alignment_mask =
+        local_decls.push(LocalDecl::with_source_info(tcx.types.usize, source_info)).into();
+    let one = Operand::Constant(Box::new(Constant {
+        span: source_info.span,
+        user_ty: None,
+        literal: ConstantKind::Val(
+            ConstValue::Scalar(Scalar::from_target_usize(1, &tcx)),
+            tcx.types.usize,
+        ),
+    }));
+    block_data.statements.push(Statement {
+        source_info,
+        kind: StatementKind::Assign(Box::new((
+            alignment_mask,
+            Rvalue::BinaryOp(BinOp::Sub, Box::new((Operand::Copy(alignment), one))),
+        ))),
+    });
+
+    // BitAnd the alignment mask with the pointer
+    let alignment_bits =
+        local_decls.push(LocalDecl::with_source_info(tcx.types.usize, source_info)).into();
+    block_data.statements.push(Statement {
+        source_info,
+        kind: StatementKind::Assign(Box::new((
+            alignment_bits,
+            Rvalue::BinaryOp(
+                BinOp::BitAnd,
+                Box::new((Operand::Copy(addr), Operand::Copy(alignment_mask))),
+            ),
+        ))),
+    });
+
+    // Check if the alignment bits are all zero
+    let is_ok = local_decls.push(LocalDecl::with_source_info(tcx.types.bool, source_info)).into();
+    let zero = Operand::Constant(Box::new(Constant {
+        span: source_info.span,
+        user_ty: None,
+        literal: ConstantKind::Val(
+            ConstValue::Scalar(Scalar::from_target_usize(0, &tcx)),
+            tcx.types.usize,
+        ),
+    }));
+    block_data.statements.push(Statement {
+        source_info,
+        kind: StatementKind::Assign(Box::new((
+            is_ok,
+            Rvalue::BinaryOp(BinOp::Eq, Box::new((Operand::Copy(alignment_bits), zero.clone()))),
+        ))),
+    });
+
+    // Set this block's terminator to our assert, continuing to new_block if we pass
+    block_data.terminator = Some(Terminator {
+        source_info,
+        kind: TerminatorKind::Assert {
+            cond: Operand::Copy(is_ok),
+            expected: true,
+            target: new_block,
+            msg: AssertKind::MisalignedPointerDereference {
+                required: Operand::Copy(alignment),
+                found: Operand::Copy(addr),
+            },
+            cleanup: None,
+        },
+    });
+}
diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs
index 6173b446b87..b52de4b72c9 100644
--- a/compiler/rustc_mir_transform/src/lib.rs
+++ b/compiler/rustc_mir_transform/src/lib.rs
@@ -90,6 +90,7 @@ mod separate_const_switch;
 mod shim;
 mod ssa;
 // This pass is public to allow external drivers to perform MIR cleanup
+mod check_alignment;
 pub mod simplify;
 mod simplify_branches;
 mod simplify_comparison_integral;
@@ -545,6 +546,7 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         tcx,
         body,
         &[
+            &check_alignment::CheckAlignment,
             &reveal_all::RevealAll, // has to be done before inlining, since inlined code is in RevealAll mode.
             &lower_slice_len::LowerSliceLenCalls, // has to be done before inlining, otherwise actual call will be almost always inlined. Also simple, so can just do first
             &unreachable_prop::UnreachablePropagation,
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 0ed99353145..d5dc1d0b315 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -1069,6 +1069,7 @@ symbols! {
         panic_implementation,
         panic_info,
         panic_location,
+        panic_misaligned_pointer_dereference,
         panic_nounwind,
         panic_runtime,
         panic_str,
diff --git a/library/core/src/panicking.rs b/library/core/src/panicking.rs
index 35da9151b6f..efeb726ab8e 100644
--- a/library/core/src/panicking.rs
+++ b/library/core/src/panicking.rs
@@ -162,6 +162,20 @@ fn panic_bounds_check(index: usize, len: usize) -> ! {
     panic!("index out of bounds: the len is {len} but the index is {index}")
 }
 
+#[cold]
+#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
+#[track_caller]
+#[cfg_attr(not(bootstrap), lang = "panic_misaligned_pointer_dereference")] // needed by codegen for panic on misaligned pointer deref
+fn panic_misaligned_pointer_dereference(required: usize, found: usize) -> ! {
+    if cfg!(feature = "panic_immediate_abort") {
+        super::intrinsics::abort()
+    }
+
+    panic!(
+        "misaligned pointer dereference: address must be a multiple of {required:#x} but is {found:#x}"
+    )
+}
+
 /// Panic because we cannot unwind out of a function.
 ///
 /// This function is called directly by the codegen backend, and must not have
diff --git a/src/tools/miri/src/shims/panic.rs b/src/tools/miri/src/shims/panic.rs
index 0ea1137200b..acc97c4b8a0 100644
--- a/src/tools/miri/src/shims/panic.rs
+++ b/src/tools/miri/src/shims/panic.rs
@@ -220,6 +220,34 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
                     },
                 )?;
             }
+            MisalignedPointerDereference { required, found } => {
+                // Forward to `panic_misaligned_pointer_dereference` lang item.
+
+                // First arg: required.
+                let required = this.read_scalar(&this.eval_operand(required, None)?)?;
+                // Second arg: found.
+                let found = this.read_scalar(&this.eval_operand(found, None)?)?;
+
+                // Call the lang item.
+                let panic_misaligned_pointer_dereference =
+                    this.tcx.lang_items().panic_misaligned_pointer_dereference_fn().unwrap();
+                let panic_misaligned_pointer_dereference =
+                    ty::Instance::mono(this.tcx.tcx, panic_misaligned_pointer_dereference);
+                this.call_function(
+                    panic_misaligned_pointer_dereference,
+                    Abi::Rust,
+                    &[required.into(), found.into()],
+                    None,
+                    StackPopCleanup::Goto {
+                        ret: None,
+                        unwind: match unwind {
+                            Some(cleanup) => StackPopUnwind::Cleanup(cleanup),
+                            None => StackPopUnwind::Skip,
+                        },
+                    },
+                )?;
+            }
+
             _ => {
                 // Forward everything else to `panic` lang item.
                 this.start_panic(
diff --git a/src/tools/miri/tests/fail/unaligned_pointers/alignment.rs b/src/tools/miri/tests/fail/unaligned_pointers/alignment.rs
index 438e74e5b8d..6bb95ae4bcb 100644
--- a/src/tools/miri/tests/fail/unaligned_pointers/alignment.rs
+++ b/src/tools/miri/tests/fail/unaligned_pointers/alignment.rs
@@ -1,4 +1,5 @@
 //@normalize-stderr-test: "\| +\^+" -> "| ^"
+//@compile-flags: -Cdebug-assertions=no
 
 fn main() {
     // No retry needed, this fails reliably.
diff --git a/src/tools/miri/tests/fail/unaligned_pointers/atomic_unaligned.rs b/src/tools/miri/tests/fail/unaligned_pointers/atomic_unaligned.rs
index 9dd652fd821..29976836b0b 100644
--- a/src/tools/miri/tests/fail/unaligned_pointers/atomic_unaligned.rs
+++ b/src/tools/miri/tests/fail/unaligned_pointers/atomic_unaligned.rs
@@ -1,4 +1,4 @@
-//@compile-flags: -Zmiri-symbolic-alignment-check
+//@compile-flags: -Zmiri-symbolic-alignment-check -Cdebug-assertions=no
 #![feature(core_intrinsics)]
 
 fn main() {
diff --git a/src/tools/miri/tests/fail/unaligned_pointers/drop_in_place.rs b/src/tools/miri/tests/fail/unaligned_pointers/drop_in_place.rs
index cf3a558bb99..8a40e527f0e 100644
--- a/src/tools/miri/tests/fail/unaligned_pointers/drop_in_place.rs
+++ b/src/tools/miri/tests/fail/unaligned_pointers/drop_in_place.rs
@@ -1,3 +1,5 @@
+//@compile-flags: -Cdebug-assertions=no
+
 #[repr(transparent)]
 struct HasDrop(u8);
 
diff --git a/src/tools/miri/tests/fail/unaligned_pointers/dyn_alignment.rs b/src/tools/miri/tests/fail/unaligned_pointers/dyn_alignment.rs
index ca8590cc6b3..6d31ded75c6 100644
--- a/src/tools/miri/tests/fail/unaligned_pointers/dyn_alignment.rs
+++ b/src/tools/miri/tests/fail/unaligned_pointers/dyn_alignment.rs
@@ -1,5 +1,5 @@
 // should find the bug even without validation and stacked borrows, but gets masked by optimizations
-//@compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows -Zmir-opt-level=0
+//@compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows -Zmir-opt-level=0 -Cdebug-assertions=no
 
 #[repr(align(256))]
 #[derive(Debug)]
diff --git a/src/tools/miri/tests/fail/unaligned_pointers/intptrcast_alignment_check.rs b/src/tools/miri/tests/fail/unaligned_pointers/intptrcast_alignment_check.rs
index da4cadc1c87..c1041ee32a4 100644
--- a/src/tools/miri/tests/fail/unaligned_pointers/intptrcast_alignment_check.rs
+++ b/src/tools/miri/tests/fail/unaligned_pointers/intptrcast_alignment_check.rs
@@ -1,4 +1,4 @@
-//@compile-flags: -Zmiri-symbolic-alignment-check -Zmiri-permissive-provenance
+//@compile-flags: -Zmiri-symbolic-alignment-check -Zmiri-permissive-provenance -Cdebug-assertions=no
 // With the symbolic alignment check, even with intptrcast and without
 // validation, we want to be *sure* to catch bugs that arise from pointers being
 // insufficiently aligned. The only way to achieve that is not not let programs
diff --git a/src/tools/miri/tests/fail/unaligned_pointers/reference_to_packed.rs b/src/tools/miri/tests/fail/unaligned_pointers/reference_to_packed.rs
index 4a43db0aac5..4a8cf405ae2 100644
--- a/src/tools/miri/tests/fail/unaligned_pointers/reference_to_packed.rs
+++ b/src/tools/miri/tests/fail/unaligned_pointers/reference_to_packed.rs
@@ -1,5 +1,5 @@
 // This should fail even without validation/SB
-//@compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows
+//@compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows -Cdebug-assertions=no
 
 #![allow(dead_code, unused_variables)]
 
diff --git a/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr1.rs b/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr1.rs
index 47d1f782cb6..921bcd6ce24 100644
--- a/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr1.rs
+++ b/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr1.rs
@@ -1,5 +1,5 @@
 // This should fail even without validation or Stacked Borrows.
-//@compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows
+//@compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows -Cdebug-assertions=no
 
 fn main() {
     // Try many times as this might work by chance.
diff --git a/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr2.rs b/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr2.rs
index c252944ffb7..8f597659f73 100644
--- a/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr2.rs
+++ b/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr2.rs
@@ -1,5 +1,5 @@
 // This should fail even without validation or Stacked Borrows.
-//@compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows
+//@compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows -Cdebug-assertions=no
 
 fn main() {
     // No retry needed, this fails reliably.
diff --git a/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr3.rs b/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr3.rs
index 3aa8cb492a1..a7fcf30c6ea 100644
--- a/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr3.rs
+++ b/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr3.rs
@@ -1,5 +1,5 @@
 // This should fail even without validation or Stacked Borrows.
-//@compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows
+//@compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows -Cdebug-assertions=no
 
 fn main() {
     // Try many times as this might work by chance.
diff --git a/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr4.rs b/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr4.rs
index 606316120d6..b8b01e113c9 100644
--- a/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr4.rs
+++ b/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr4.rs
@@ -1,5 +1,5 @@
 // This should fail even without validation or Stacked Borrows.
-//@compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows
+//@compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows -Cdebug-assertions=no
 
 fn main() {
     // Make sure we notice when a u16 is loaded at offset 1 into a u8 allocation.
diff --git a/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr_addr_of.rs b/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr_addr_of.rs
index f1032ab52bc..b414b905472 100644
--- a/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr_addr_of.rs
+++ b/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr_addr_of.rs
@@ -1,5 +1,5 @@
 // This should fail even without validation or Stacked Borrows.
-//@compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows
+//@compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows -Cdebug-assertions=no
 use std::ptr;
 
 fn main() {
diff --git a/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr_zst.rs b/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr_zst.rs
index eff42375956..04dbe3fd8d4 100644
--- a/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr_zst.rs
+++ b/src/tools/miri/tests/fail/unaligned_pointers/unaligned_ptr_zst.rs
@@ -1,6 +1,6 @@
 // This should fail even without validation
 // Some optimizations remove ZST accesses, thus masking this UB.
-//@compile-flags: -Zmir-opt-level=0 -Zmiri-disable-validation
+//@compile-flags: -Zmir-opt-level=0 -Zmiri-disable-validation -Cdebug-assertions=no
 
 fn main() {
     // Try many times as this might work by chance.
diff --git a/src/tools/miri/tests/panic/alignment-assertion.rs b/src/tools/miri/tests/panic/alignment-assertion.rs
new file mode 100644
index 00000000000..68aa19a88db
--- /dev/null
+++ b/src/tools/miri/tests/panic/alignment-assertion.rs
@@ -0,0 +1,9 @@
+//@compile-flags: -Zmiri-disable-alignment-check -Cdebug-assertions=yes
+
+fn main() {
+    let mut x = [0u32; 2];
+    let ptr: *mut u8 = x.as_mut_ptr().cast::<u8>();
+    unsafe {
+        *(ptr.add(1).cast::<u32>()) = 42;
+    }
+}
diff --git a/src/tools/miri/tests/panic/alignment-assertion.stderr b/src/tools/miri/tests/panic/alignment-assertion.stderr
new file mode 100644
index 00000000000..26cf51b0cd2
--- /dev/null
+++ b/src/tools/miri/tests/panic/alignment-assertion.stderr
@@ -0,0 +1,2 @@
+thread 'main' panicked at 'misaligned pointer dereference: address must be a multiple of 0x4 but is $HEX', $DIR/alignment-assertion.rs:LL:CC
+note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
diff --git a/src/tools/miri/tests/pass/disable-alignment-check.rs b/src/tools/miri/tests/pass/disable-alignment-check.rs
index fdcacc6cea4..e8c0e027673 100644
--- a/src/tools/miri/tests/pass/disable-alignment-check.rs
+++ b/src/tools/miri/tests/pass/disable-alignment-check.rs
@@ -1,6 +1,6 @@
 //@revisions: stack tree
 //@[tree]compile-flags: -Zmiri-tree-borrows
-//@compile-flags: -Zmiri-disable-alignment-check
+//@compile-flags: -Zmiri-disable-alignment-check -Cdebug-assertions=no
 
 fn main() {
     let mut x = [0u8; 20];
diff --git a/tests/assembly/static-relocation-model.rs b/tests/assembly/static-relocation-model.rs
index faa2e395209..41aa9a46103 100644
--- a/tests/assembly/static-relocation-model.rs
+++ b/tests/assembly/static-relocation-model.rs
@@ -6,6 +6,7 @@
 // [A64] needs-llvm-components: aarch64
 // [ppc64le] compile-flags: --target powerpc64le-unknown-linux-gnu -Crelocation-model=static
 // [ppc64le] needs-llvm-components: powerpc
+// ignore-debug: alignment checks insert panics that we don't have a lang item for
 
 #![feature(no_core, lang_items)]
 #![no_core]
diff --git a/tests/codegen/issues/issue-37945.rs b/tests/codegen/issues/issue-37945.rs
index fe54375bbf6..19e7e8b1f6e 100644
--- a/tests/codegen/issues/issue-37945.rs
+++ b/tests/codegen/issues/issue-37945.rs
@@ -4,6 +4,7 @@
 // ignore-emscripten
 // ignore-gnux32
 // ignore 32-bit platforms (LLVM has a bug with them)
+// ignore-debug
 
 // Check that LLVM understands that `Iter` pointer is not null. Issue #37945.
 
diff --git a/tests/codegen/virtual-function-elimination.rs b/tests/codegen/virtual-function-elimination.rs
index 4cf7e12fee2..30e5cd0584d 100644
--- a/tests/codegen/virtual-function-elimination.rs
+++ b/tests/codegen/virtual-function-elimination.rs
@@ -1,5 +1,6 @@
 // compile-flags: -Zvirtual-function-elimination -Clto -O -Csymbol-mangling-version=v0
 // ignore-32bit
+// ignore-debug
 
 // CHECK: @vtable.0 = {{.*}}, !type ![[TYPE0:[0-9]+]], !vcall_visibility ![[VCALL_VIS0:[0-9]+]]
 // CHECK: @vtable.1 = {{.*}}, !type ![[TYPE1:[0-9]+]], !vcall_visibility ![[VCALL_VIS0:[0-9]+]]
diff --git a/tests/mir-opt/inline/inline_into_box_place.main.Inline.diff b/tests/mir-opt/inline/inline_into_box_place.main.Inline.diff
index bc1c913c00e..a4f0ad465e2 100644
--- a/tests/mir-opt/inline/inline_into_box_place.main.Inline.diff
+++ b/tests/mir-opt/inline/inline_into_box_place.main.Inline.diff
@@ -8,10 +8,10 @@
       scope 1 {
           debug _x => _1;                  // in scope 1 at $DIR/inline_into_box_place.rs:+1:9: +1:11
       }
-+     scope 2 (inlined Vec::<u32>::new) {  // at $DIR/inline_into_box_place.rs:7:38: 7:48
++     scope 2 (inlined Vec::<u32>::new) {  // at $DIR/inline_into_box_place.rs:8:38: 8:48
 +         let mut _3: alloc::raw_vec::RawVec<u32>; // in scope 2 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
 +     }
-+     scope 3 (inlined Box::<Vec<u32>>::new) { // at $DIR/inline_into_box_place.rs:7:29: 7:49
++     scope 3 (inlined Box::<Vec<u32>>::new) { // at $DIR/inline_into_box_place.rs:8:29: 8:49
 +         debug x => _2;                   // in scope 3 at $SRC_DIR/alloc/src/boxed.rs:LL:COL
 +         let mut _4: usize;               // in scope 3 at $SRC_DIR/alloc/src/boxed.rs:LL:COL
 +         let mut _5: usize;               // in scope 3 at $SRC_DIR/alloc/src/boxed.rs:LL:COL
@@ -28,7 +28,7 @@
 +         StorageLive(_3);                 // scope 2 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
 +         _3 = const _;                    // scope 2 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
                                            // mir::Constant
--                                          // + span: $DIR/inline_into_box_place.rs:7:38: 7:46
+-                                          // + span: $DIR/inline_into_box_place.rs:8:38: 8:46
 -                                          // + user_ty: UserType(2)
 -                                          // + literal: Const { ty: fn() -> Vec<u32> {Vec::<u32>::new}, val: Value(<ZST>) }
 +                                          // + span: $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
@@ -47,7 +47,7 @@
       bb1: {
 -         _1 = Box::<Vec<u32>>::new(move _2) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/inline_into_box_place.rs:+1:29: +1:49
 -                                          // mir::Constant
--                                          // + span: $DIR/inline_into_box_place.rs:7:29: 7:37
+-                                          // + span: $DIR/inline_into_box_place.rs:8:29: 8:37
 -                                          // + user_ty: UserType(1)
 -                                          // + literal: Const { ty: fn(Vec<u32>) -> Box<Vec<u32>> {Box::<Vec<u32>>::new}, val: Value(<ZST>) }
 +         StorageDead(_1);                 // scope 0 at $DIR/inline_into_box_place.rs:+2:1: +2:2
diff --git a/tests/mir-opt/inline/inline_into_box_place.rs b/tests/mir-opt/inline/inline_into_box_place.rs
index b8b73f0c44c..02823e4e1b7 100644
--- a/tests/mir-opt/inline/inline_into_box_place.rs
+++ b/tests/mir-opt/inline/inline_into_box_place.rs
@@ -1,5 +1,6 @@
 // ignore-endian-big
 // ignore-wasm32-bare compiled with panic=abort by default
+// ignore-debug MIR alignment checks in std alter the diff, breaking the test
 // compile-flags: -Z mir-opt-level=4
 
 // EMIT_MIR inline_into_box_place.main.Inline.diff
diff --git a/tests/run-make/fmt-write-bloat/Makefile b/tests/run-make/fmt-write-bloat/Makefile
index 07e6e025e08..53615775486 100644
--- a/tests/run-make/fmt-write-bloat/Makefile
+++ b/tests/run-make/fmt-write-bloat/Makefile
@@ -11,11 +11,11 @@ else
 
 NM = nm
 
-PANIC_SYMS = panic_bounds_check pad_integral Display Debug
+PANIC_SYMS = panic_bounds_check Debug
 
 # Allow for debug_assert!() in debug builds of std.
 ifdef NO_DEBUG_ASSERTIONS
-PANIC_SYMS += panicking panic_fmt
+PANIC_SYMS += panicking panic_fmt pad_integral Display Debug
 endif
 
 all: main.rs
diff --git a/tests/ui/mir/mir_alignment_check.rs b/tests/ui/mir/mir_alignment_check.rs
new file mode 100644
index 00000000000..68a5384b30d
--- /dev/null
+++ b/tests/ui/mir/mir_alignment_check.rs
@@ -0,0 +1,12 @@
+// run-fail
+// ignore-wasm32-bare: No panic messages
+// compile-flags: -C debug-assertions
+// error-pattern: misaligned pointer dereference: address must be a multiple of 0x4 but is
+
+fn main() {
+    let mut x = [0u32; 2];
+    let ptr: *mut u8 = x.as_mut_ptr().cast::<u8>();
+    unsafe {
+        *(ptr.add(1).cast::<u32>()) = 42;
+    }
+}
diff --git a/tests/ui/process/signal-exit-status.rs b/tests/ui/process/signal-exit-status.rs
index 9519ed7b4c7..0f05f916cb9 100644
--- a/tests/ui/process/signal-exit-status.rs
+++ b/tests/ui/process/signal-exit-status.rs
@@ -4,14 +4,16 @@
 // ignore-windows
 // ignore-fuchsia code returned as ZX_TASK_RETCODE_EXCEPTION_KILL, FIXME (#58590)
 
+#![feature(core_intrinsics)]
+
 use std::env;
 use std::process::Command;
 
 pub fn main() {
     let args: Vec<String> = env::args().collect();
     if args.len() >= 2 && args[1] == "signal" {
-        // Raise a segfault.
-        unsafe { *(1 as *mut isize) = 0; }
+        // Raise an aborting signal without UB
+        core::intrinsics::abort();
     } else {
         let status = Command::new(&args[0]).arg("signal").status().unwrap();
         assert!(status.code().is_none());