1- use  rustc_hir:: lang_items:: LangItem ; 
21use  rustc_index:: IndexVec ; 
32use  rustc_middle:: mir:: interpret:: Scalar ; 
4- use  rustc_middle:: mir:: visit:: { MutatingUseContext ,  NonMutatingUseContext ,  PlaceContext ,  Visitor } ; 
53use  rustc_middle:: mir:: * ; 
6- use  rustc_middle:: ty:: { self ,   Ty ,  TyCtxt } ; 
4+ use  rustc_middle:: ty:: { Ty ,  TyCtxt } ; 
75use  rustc_session:: Session ; 
8- use  tracing:: { debug,  trace} ; 
6+ 
7+ use  crate :: check_pointers:: { BorrowCheckMode ,  PointerCheck ,  check_pointers} ; 
98
109pub ( super )  struct  CheckAlignment ; 
1110
@@ -19,166 +18,53 @@ impl<'tcx> crate::MirPass<'tcx> for CheckAlignment {
1918    } 
2019
2120    fn  run_pass ( & self ,  tcx :  TyCtxt < ' tcx > ,  body :  & mut  Body < ' tcx > )  { 
22-         // This pass emits new panics. If for whatever reason we do not have a panic 
23-         // implementation, running this pass may cause otherwise-valid code to not compile. 
24-         if  tcx. lang_items ( ) . get ( LangItem :: PanicImpl ) . is_none ( )  { 
25-             return ; 
26-         } 
27- 
28-         let  typing_env = body. typing_env ( tcx) ; 
29-         let  basic_blocks = body. basic_blocks . as_mut ( ) ; 
30-         let  local_decls = & mut  body. local_decls ; 
31- 
32-         // This pass inserts new blocks. Each insertion changes the Location for all 
33-         // statements/blocks after. Iterating or visiting the MIR in order would require updating 
34-         // our current location after every insertion. By iterating backwards, we dodge this issue: 
35-         // The only Locations that an insertion changes have already been handled. 
36-         for  block in  ( 0 ..basic_blocks. len ( ) ) . rev ( )  { 
37-             let  block = block. into ( ) ; 
38-             for  statement_index in  ( 0 ..basic_blocks[ block] . statements . len ( ) ) . rev ( )  { 
39-                 let  location = Location  {  block,  statement_index } ; 
40-                 let  statement = & basic_blocks[ block] . statements [ statement_index] ; 
41-                 let  source_info = statement. source_info ; 
42- 
43-                 let  mut  finder =
44-                     PointerFinder  {  tcx,  local_decls,  typing_env,  pointers :  Vec :: new ( )  } ; 
45-                 finder. visit_statement ( statement,  location) ; 
46- 
47-                 for  ( local,  ty)  in  finder. pointers  { 
48-                     debug ! ( "Inserting alignment check for {:?}" ,  ty) ; 
49-                     let  new_block = split_block ( basic_blocks,  location) ; 
50-                     insert_alignment_check ( 
51-                         tcx, 
52-                         local_decls, 
53-                         & mut  basic_blocks[ block] , 
54-                         local, 
55-                         ty, 
56-                         source_info, 
57-                         new_block, 
58-                     ) ; 
59-                 } 
60-             } 
61-         } 
21+         // Skip trivially aligned place types. 
22+         let  excluded_pointees = [ tcx. types . bool ,  tcx. types . i8 ,  tcx. types . u8 ] ; 
23+ 
24+         // We have to exclude borrows here: in `&x.field`, the exact 
25+         // requirement is that the final reference must be aligned, but 
26+         // `check_pointers` would check that `x` is aligned, which would be wrong. 
27+         check_pointers ( 
28+             tcx, 
29+             body, 
30+             & excluded_pointees, 
31+             insert_alignment_check, 
32+             BorrowCheckMode :: ExcludeBorrows , 
33+         ) ; 
6234    } 
6335
6436    fn  is_required ( & self )  -> bool  { 
6537        true 
6638    } 
6739} 
6840
69- struct  PointerFinder < ' a ,  ' tcx >  { 
70-     tcx :  TyCtxt < ' tcx > , 
71-     local_decls :  & ' a  mut  LocalDecls < ' tcx > , 
72-     typing_env :  ty:: TypingEnv < ' tcx > , 
73-     pointers :  Vec < ( Place < ' tcx > ,  Ty < ' tcx > ) > , 
74- } 
75- 
76- impl < ' a ,  ' tcx >  Visitor < ' tcx >  for  PointerFinder < ' a ,  ' tcx >  { 
77-     fn  visit_place ( & mut  self ,  place :  & Place < ' tcx > ,  context :  PlaceContext ,  location :  Location )  { 
78-         // We want to only check reads and writes to Places, so we specifically exclude 
79-         // Borrow and RawBorrow. 
80-         match  context { 
81-             PlaceContext :: MutatingUse ( 
82-                 MutatingUseContext :: Store 
83-                 | MutatingUseContext :: AsmOutput 
84-                 | MutatingUseContext :: Call 
85-                 | MutatingUseContext :: Yield 
86-                 | MutatingUseContext :: Drop , 
87-             )  => { } 
88-             PlaceContext :: NonMutatingUse ( 
89-                 NonMutatingUseContext :: Copy  | NonMutatingUseContext :: Move , 
90-             )  => { } 
91-             _ => { 
92-                 return ; 
93-             } 
94-         } 
95- 
96-         if  !place. is_indirect ( )  { 
97-             return ; 
98-         } 
99- 
100-         // Since Deref projections must come first and only once, the pointer for an indirect place 
101-         // is the Local that the Place is based on. 
102-         let  pointer = Place :: from ( place. local ) ; 
103-         let  pointer_ty = self . local_decls [ place. local ] . ty ; 
104- 
105-         // We only want to check places based on unsafe pointers 
106-         if  !pointer_ty. is_unsafe_ptr ( )  { 
107-             trace ! ( "Indirect, but not based on an unsafe ptr, not checking {:?}" ,  place) ; 
108-             return ; 
109-         } 
110- 
111-         let  pointee_ty =
112-             pointer_ty. builtin_deref ( true ) . expect ( "no builtin_deref for an unsafe pointer" ) ; 
113-         // Ideally we'd support this in the future, but for now we are limited to sized types. 
114-         if  !pointee_ty. is_sized ( self . tcx ,  self . typing_env )  { 
115-             debug ! ( "Unsafe pointer, but pointee is not known to be sized: {:?}" ,  pointer_ty) ; 
116-             return ; 
117-         } 
118- 
119-         // Try to detect types we are sure have an alignment of 1 and skip the check 
120-         // We don't need to look for str and slices, we already rejected unsized types above 
121-         let  element_ty = match  pointee_ty. kind ( )  { 
122-             ty:: Array ( ty,  _)  => * ty, 
123-             _ => pointee_ty, 
124-         } ; 
125-         if  [ self . tcx . types . bool ,  self . tcx . types . i8 ,  self . tcx . types . u8 ] . contains ( & element_ty)  { 
126-             debug ! ( "Trivially aligned place type: {:?}" ,  pointee_ty) ; 
127-             return ; 
128-         } 
129- 
130-         // Ensure that this place is based on an aligned pointer. 
131-         self . pointers . push ( ( pointer,  pointee_ty) ) ; 
132- 
133-         self . super_place ( place,  context,  location) ; 
134-     } 
135- } 
136- 
137- fn  split_block ( 
138-     basic_blocks :  & mut  IndexVec < BasicBlock ,  BasicBlockData < ' _ > > , 
139-     location :  Location , 
140- )  -> BasicBlock  { 
141-     let  block_data = & mut  basic_blocks[ location. block ] ; 
142- 
143-     // Drain every statement after this one and move the current terminator to a new basic block 
144-     let  new_block = BasicBlockData  { 
145-         statements :  block_data. statements . split_off ( location. statement_index ) , 
146-         terminator :  block_data. terminator . take ( ) , 
147-         is_cleanup :  block_data. is_cleanup , 
148-     } ; 
149- 
150-     basic_blocks. push ( new_block) 
151- } 
152- 
41+ /// Inserts the actual alignment check's logic. Returns a 
42+ /// [AssertKind::MisalignedPointerDereference] on failure. 
15343fn  insert_alignment_check < ' tcx > ( 
15444    tcx :  TyCtxt < ' tcx > , 
155-     local_decls :  & mut  IndexVec < Local ,  LocalDecl < ' tcx > > , 
156-     block_data :  & mut  BasicBlockData < ' tcx > , 
15745    pointer :  Place < ' tcx > , 
15846    pointee_ty :  Ty < ' tcx > , 
47+     local_decls :  & mut  IndexVec < Local ,  LocalDecl < ' tcx > > , 
48+     stmts :  & mut  Vec < Statement < ' tcx > > , 
15949    source_info :  SourceInfo , 
160-     new_block :  BasicBlock , 
161- )  { 
162-     // Cast the pointer to a *const () 
50+ )  -> PointerCheck < ' tcx >  { 
51+     // Cast the pointer to a *const (). 
16352    let  const_raw_ptr = Ty :: new_imm_ptr ( tcx,  tcx. types . unit ) ; 
16453    let  rvalue = Rvalue :: Cast ( CastKind :: PtrToPtr ,  Operand :: Copy ( pointer) ,  const_raw_ptr) ; 
16554    let  thin_ptr = local_decls. push ( LocalDecl :: with_source_info ( const_raw_ptr,  source_info) ) . into ( ) ; 
166-     block_data
167-         . statements 
55+     stmts
16856        . push ( Statement  {  source_info,  kind :  StatementKind :: Assign ( Box :: new ( ( thin_ptr,  rvalue) ) )  } ) ; 
16957
170-     // Transmute the pointer to a usize (equivalent to `ptr.addr()`) 
58+     // Transmute the pointer to a usize (equivalent to `ptr.addr()`).  
17159    let  rvalue = Rvalue :: Cast ( CastKind :: Transmute ,  Operand :: Copy ( thin_ptr) ,  tcx. types . usize ) ; 
17260    let  addr = local_decls. push ( LocalDecl :: with_source_info ( tcx. types . usize ,  source_info) ) . into ( ) ; 
173-     block_data
174-         . statements 
175-         . push ( Statement  {  source_info,  kind :  StatementKind :: Assign ( Box :: new ( ( addr,  rvalue) ) )  } ) ; 
61+     stmts. push ( Statement  {  source_info,  kind :  StatementKind :: Assign ( Box :: new ( ( addr,  rvalue) ) )  } ) ; 
17662
17763    // Get the alignment of the pointee 
17864    let  alignment =
17965        local_decls. push ( LocalDecl :: with_source_info ( tcx. types . usize ,  source_info) ) . into ( ) ; 
18066    let  rvalue = Rvalue :: NullaryOp ( NullOp :: AlignOf ,  pointee_ty) ; 
181-     block_data . statements . push ( Statement  { 
67+     stmts . push ( Statement  { 
18268        source_info, 
18369        kind :  StatementKind :: Assign ( Box :: new ( ( alignment,  rvalue) ) ) , 
18470    } ) ; 
@@ -191,7 +77,7 @@ fn insert_alignment_check<'tcx>(
19177        user_ty :  None , 
19278        const_ :  Const :: Val ( ConstValue :: Scalar ( Scalar :: from_target_usize ( 1 ,  & tcx) ) ,  tcx. types . usize ) , 
19379    } ) ) ; 
194-     block_data . statements . push ( Statement  { 
80+     stmts . push ( Statement  { 
19581        source_info, 
19682        kind :  StatementKind :: Assign ( Box :: new ( ( 
19783            alignment_mask, 
@@ -202,7 +88,7 @@ fn insert_alignment_check<'tcx>(
20288    // BitAnd the alignment mask with the pointer 
20389    let  alignment_bits =
20490        local_decls. push ( LocalDecl :: with_source_info ( tcx. types . usize ,  source_info) ) . into ( ) ; 
205-     block_data . statements . push ( Statement  { 
91+     stmts . push ( Statement  { 
20692        source_info, 
20793        kind :  StatementKind :: Assign ( Box :: new ( ( 
20894            alignment_bits, 
@@ -220,29 +106,21 @@ fn insert_alignment_check<'tcx>(
220106        user_ty :  None , 
221107        const_ :  Const :: Val ( ConstValue :: Scalar ( Scalar :: from_target_usize ( 0 ,  & tcx) ) ,  tcx. types . usize ) , 
222108    } ) ) ; 
223-     block_data . statements . push ( Statement  { 
109+     stmts . push ( Statement  { 
224110        source_info, 
225111        kind :  StatementKind :: Assign ( Box :: new ( ( 
226112            is_ok, 
227113            Rvalue :: BinaryOp ( BinOp :: Eq ,  Box :: new ( ( Operand :: Copy ( alignment_bits) ,  zero. clone ( ) ) ) ) , 
228114        ) ) ) , 
229115    } ) ; 
230116
231-     // Set this block's terminator to our assert, continuing to new_block if we pass 
232-     block_data. terminator  = Some ( Terminator  { 
233-         source_info, 
234-         kind :  TerminatorKind :: Assert  { 
235-             cond :  Operand :: Copy ( is_ok) , 
236-             expected :  true , 
237-             target :  new_block, 
238-             msg :  Box :: new ( AssertKind :: MisalignedPointerDereference  { 
239-                 required :  Operand :: Copy ( alignment) , 
240-                 found :  Operand :: Copy ( addr) , 
241-             } ) , 
242-             // This calls panic_misaligned_pointer_dereference, which is #[rustc_nounwind]. 
243-             // We never want to insert an unwind into unsafe code, because unwinding could 
244-             // make a failing UB check turn into much worse UB when we start unwinding. 
245-             unwind :  UnwindAction :: Unreachable , 
246-         } , 
247-     } ) ; 
117+     // Emit a check that asserts on the alignment and otherwise triggers a 
118+     // AssertKind::MisalignedPointerDereference. 
119+     PointerCheck  { 
120+         cond :  Operand :: Copy ( is_ok) , 
121+         assert_kind :  Box :: new ( AssertKind :: MisalignedPointerDereference  { 
122+             required :  Operand :: Copy ( alignment) , 
123+             found :  Operand :: Copy ( addr) , 
124+         } ) , 
125+     } 
248126} 
0 commit comments