rustc_mir_transform/
check_alignment.rs1use rustc_abi::Align;
2use rustc_index::IndexVec;
3use rustc_middle::mir::interpret::Scalar;
4use rustc_middle::mir::visit::PlaceContext;
5use rustc_middle::mir::*;
6use rustc_middle::ty::{Ty, TyCtxt};
7use rustc_session::Session;
8
9use crate::check_pointers::{BorrowedFieldProjectionMode, PointerCheck, check_pointers};
10
11pub(super) struct CheckAlignment;
12
13impl<'tcx> crate::MirPass<'tcx> for CheckAlignment {
14 fn is_enabled(&self, sess: &Session) -> bool {
15 sess.ub_checks()
16 }
17
18 fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
19 let excluded_pointees = [tcx.types.bool, tcx.types.i8, tcx.types.u8];
21
22 check_pointers(
26 tcx,
27 body,
28 &excluded_pointees,
29 insert_alignment_check,
30 BorrowedFieldProjectionMode::FollowProjections,
31 );
32 }
33
34 fn is_required(&self) -> bool {
35 true
36 }
37}
38
39fn insert_alignment_check<'tcx>(
42 tcx: TyCtxt<'tcx>,
43 pointer: Place<'tcx>,
44 pointee_ty: Ty<'tcx>,
45 _context: PlaceContext,
46 local_decls: &mut IndexVec<Local, LocalDecl<'tcx>>,
47 stmts: &mut Vec<Statement<'tcx>>,
48 source_info: SourceInfo,
49) -> PointerCheck<'tcx> {
50 let const_raw_ptr = Ty::new_imm_ptr(tcx, tcx.types.unit);
52 let rvalue = Rvalue::Cast(CastKind::PtrToPtr, Operand::Copy(pointer), const_raw_ptr);
53 let thin_ptr = local_decls.push(LocalDecl::with_source_info(const_raw_ptr, source_info)).into();
54 stmts
55 .push(Statement { source_info, kind: StatementKind::Assign(Box::new((thin_ptr, rvalue))) });
56
57 let rvalue = Rvalue::Cast(CastKind::Transmute, Operand::Copy(thin_ptr), tcx.types.usize);
59 let addr = local_decls.push(LocalDecl::with_source_info(tcx.types.usize, source_info)).into();
60 stmts.push(Statement { source_info, kind: StatementKind::Assign(Box::new((addr, rvalue))) });
61
62 let alignment =
64 local_decls.push(LocalDecl::with_source_info(tcx.types.usize, source_info)).into();
65 let rvalue = Rvalue::NullaryOp(NullOp::AlignOf, pointee_ty);
66 stmts.push(Statement {
67 source_info,
68 kind: StatementKind::Assign(Box::new((alignment, rvalue))),
69 });
70
71 let alignment_mask =
73 local_decls.push(LocalDecl::with_source_info(tcx.types.usize, source_info)).into();
74 let one = Operand::Constant(Box::new(ConstOperand {
75 span: source_info.span,
76 user_ty: None,
77 const_: Const::Val(ConstValue::Scalar(Scalar::from_target_usize(1, &tcx)), tcx.types.usize),
78 }));
79 stmts.push(Statement {
80 source_info,
81 kind: StatementKind::Assign(Box::new((
82 alignment_mask,
83 Rvalue::BinaryOp(BinOp::Sub, Box::new((Operand::Copy(alignment), one))),
84 ))),
85 });
86
87 #[allow(irrefutable_let_patterns)]
90 if let max_align = tcx.sess.target.max_reliable_alignment()
91 && max_align < Align::MAX
92 {
93 let max_mask = max_align.bytes() - 1;
94 let max_mask = Operand::Constant(Box::new(ConstOperand {
95 span: source_info.span,
96 user_ty: None,
97 const_: Const::Val(
98 ConstValue::Scalar(Scalar::from_target_usize(max_mask, &tcx)),
99 tcx.types.usize,
100 ),
101 }));
102 stmts.push(Statement {
103 source_info,
104 kind: StatementKind::Assign(Box::new((
105 alignment_mask,
106 Rvalue::BinaryOp(
107 BinOp::BitAnd,
108 Box::new((Operand::Copy(alignment_mask), max_mask)),
109 ),
110 ))),
111 });
112 }
113
114 let alignment_bits =
116 local_decls.push(LocalDecl::with_source_info(tcx.types.usize, source_info)).into();
117 stmts.push(Statement {
118 source_info,
119 kind: StatementKind::Assign(Box::new((
120 alignment_bits,
121 Rvalue::BinaryOp(
122 BinOp::BitAnd,
123 Box::new((Operand::Copy(addr), Operand::Copy(alignment_mask))),
124 ),
125 ))),
126 });
127
128 let is_ok = local_decls.push(LocalDecl::with_source_info(tcx.types.bool, source_info)).into();
130 let zero = Operand::Constant(Box::new(ConstOperand {
131 span: source_info.span,
132 user_ty: None,
133 const_: Const::Val(ConstValue::Scalar(Scalar::from_target_usize(0, &tcx)), tcx.types.usize),
134 }));
135 stmts.push(Statement {
136 source_info,
137 kind: StatementKind::Assign(Box::new((
138 is_ok,
139 Rvalue::BinaryOp(BinOp::Eq, Box::new((Operand::Copy(alignment_bits), zero.clone()))),
140 ))),
141 });
142
143 PointerCheck {
146 cond: Operand::Copy(is_ok),
147 assert_kind: Box::new(AssertKind::MisalignedPointerDereference {
148 required: Operand::Copy(alignment),
149 found: Operand::Copy(addr),
150 }),
151 }
152}