rustc_mir_transform/
check_alignment.rs
1use rustc_index::IndexVec;
2use rustc_middle::mir::interpret::Scalar;
3use rustc_middle::mir::visit::PlaceContext;
4use rustc_middle::mir::*;
5use rustc_middle::ty::{Ty, TyCtxt};
6use rustc_session::Session;
7
8use crate::check_pointers::{BorrowCheckMode, PointerCheck, check_pointers};
9
10pub(super) struct CheckAlignment;
11
12impl<'tcx> crate::MirPass<'tcx> for CheckAlignment {
13 fn is_enabled(&self, sess: &Session) -> bool {
14 if sess.target.llvm_target == "i686-pc-windows-msvc" {
16 return false;
17 }
18 sess.ub_checks()
19 }
20
21 fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
22 let excluded_pointees = [tcx.types.bool, tcx.types.i8, tcx.types.u8];
24
25 check_pointers(
29 tcx,
30 body,
31 &excluded_pointees,
32 insert_alignment_check,
33 BorrowCheckMode::ExcludeBorrows,
34 );
35 }
36
37 fn is_required(&self) -> bool {
38 true
39 }
40}
41
42fn insert_alignment_check<'tcx>(
45 tcx: TyCtxt<'tcx>,
46 pointer: Place<'tcx>,
47 pointee_ty: Ty<'tcx>,
48 _context: PlaceContext,
49 local_decls: &mut IndexVec<Local, LocalDecl<'tcx>>,
50 stmts: &mut Vec<Statement<'tcx>>,
51 source_info: SourceInfo,
52) -> PointerCheck<'tcx> {
53 let const_raw_ptr = Ty::new_imm_ptr(tcx, tcx.types.unit);
55 let rvalue = Rvalue::Cast(CastKind::PtrToPtr, Operand::Copy(pointer), const_raw_ptr);
56 let thin_ptr = local_decls.push(LocalDecl::with_source_info(const_raw_ptr, source_info)).into();
57 stmts
58 .push(Statement { source_info, kind: StatementKind::Assign(Box::new((thin_ptr, rvalue))) });
59
60 let rvalue = Rvalue::Cast(CastKind::Transmute, Operand::Copy(thin_ptr), tcx.types.usize);
62 let addr = local_decls.push(LocalDecl::with_source_info(tcx.types.usize, source_info)).into();
63 stmts.push(Statement { source_info, kind: StatementKind::Assign(Box::new((addr, rvalue))) });
64
65 let alignment =
67 local_decls.push(LocalDecl::with_source_info(tcx.types.usize, source_info)).into();
68 let rvalue = Rvalue::NullaryOp(NullOp::AlignOf, pointee_ty);
69 stmts.push(Statement {
70 source_info,
71 kind: StatementKind::Assign(Box::new((alignment, rvalue))),
72 });
73
74 let alignment_mask =
76 local_decls.push(LocalDecl::with_source_info(tcx.types.usize, source_info)).into();
77 let one = Operand::Constant(Box::new(ConstOperand {
78 span: source_info.span,
79 user_ty: None,
80 const_: Const::Val(ConstValue::Scalar(Scalar::from_target_usize(1, &tcx)), tcx.types.usize),
81 }));
82 stmts.push(Statement {
83 source_info,
84 kind: StatementKind::Assign(Box::new((
85 alignment_mask,
86 Rvalue::BinaryOp(BinOp::Sub, Box::new((Operand::Copy(alignment), one))),
87 ))),
88 });
89
90 let alignment_bits =
92 local_decls.push(LocalDecl::with_source_info(tcx.types.usize, source_info)).into();
93 stmts.push(Statement {
94 source_info,
95 kind: StatementKind::Assign(Box::new((
96 alignment_bits,
97 Rvalue::BinaryOp(
98 BinOp::BitAnd,
99 Box::new((Operand::Copy(addr), Operand::Copy(alignment_mask))),
100 ),
101 ))),
102 });
103
104 let is_ok = local_decls.push(LocalDecl::with_source_info(tcx.types.bool, source_info)).into();
106 let zero = Operand::Constant(Box::new(ConstOperand {
107 span: source_info.span,
108 user_ty: None,
109 const_: Const::Val(ConstValue::Scalar(Scalar::from_target_usize(0, &tcx)), tcx.types.usize),
110 }));
111 stmts.push(Statement {
112 source_info,
113 kind: StatementKind::Assign(Box::new((
114 is_ok,
115 Rvalue::BinaryOp(BinOp::Eq, Box::new((Operand::Copy(alignment_bits), zero.clone()))),
116 ))),
117 });
118
119 PointerCheck {
122 cond: Operand::Copy(is_ok),
123 assert_kind: Box::new(AssertKind::MisalignedPointerDereference {
124 required: Operand::Copy(alignment),
125 found: Operand::Copy(addr),
126 }),
127 }
128}