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