1
- use rustc_hir:: lang_items:: LangItem ;
2
1
use rustc_index:: IndexVec ;
3
2
use rustc_middle:: mir:: interpret:: Scalar ;
4
- use rustc_middle:: mir:: visit:: { MutatingUseContext , NonMutatingUseContext , PlaceContext , Visitor } ;
5
3
use rustc_middle:: mir:: * ;
6
- use rustc_middle:: ty:: { self , Ty , TyCtxt } ;
4
+ use rustc_middle:: ty:: { Ty , TyCtxt } ;
7
5
use rustc_session:: Session ;
8
- use tracing:: { debug, trace} ;
6
+
7
+ use crate :: check_pointers:: check_pointers;
9
8
10
9
pub ( super ) struct CheckAlignment ;
11
10
@@ -19,133 +18,12 @@ impl<'tcx> crate::MirPass<'tcx> for CheckAlignment {
19
18
}
20
19
21
20
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
+ check_pointers ( tcx, body, & excluded_pointees, insert_alignment_check) ;
62
24
}
63
25
}
64
26
65
- struct PointerFinder < ' a , ' tcx > {
66
- tcx : TyCtxt < ' tcx > ,
67
- local_decls : & ' a mut LocalDecls < ' tcx > ,
68
- typing_env : ty:: TypingEnv < ' tcx > ,
69
- pointers : Vec < ( Place < ' tcx > , Ty < ' tcx > ) > ,
70
- }
71
-
72
- impl < ' a , ' tcx > Visitor < ' tcx > for PointerFinder < ' a , ' tcx > {
73
- fn visit_place ( & mut self , place : & Place < ' tcx > , context : PlaceContext , location : Location ) {
74
- // We want to only check reads and writes to Places, so we specifically exclude
75
- // Borrow and RawBorrow.
76
- match context {
77
- PlaceContext :: MutatingUse (
78
- MutatingUseContext :: Store
79
- | MutatingUseContext :: AsmOutput
80
- | MutatingUseContext :: Call
81
- | MutatingUseContext :: Yield
82
- | MutatingUseContext :: Drop ,
83
- ) => { }
84
- PlaceContext :: NonMutatingUse (
85
- NonMutatingUseContext :: Copy | NonMutatingUseContext :: Move ,
86
- ) => { }
87
- _ => {
88
- return ;
89
- }
90
- }
91
-
92
- if !place. is_indirect ( ) {
93
- return ;
94
- }
95
-
96
- // Since Deref projections must come first and only once, the pointer for an indirect place
97
- // is the Local that the Place is based on.
98
- let pointer = Place :: from ( place. local ) ;
99
- let pointer_ty = self . local_decls [ place. local ] . ty ;
100
-
101
- // We only want to check places based on unsafe pointers
102
- if !pointer_ty. is_unsafe_ptr ( ) {
103
- trace ! ( "Indirect, but not based on an unsafe ptr, not checking {:?}" , place) ;
104
- return ;
105
- }
106
-
107
- let pointee_ty =
108
- pointer_ty. builtin_deref ( true ) . expect ( "no builtin_deref for an unsafe pointer" ) ;
109
- // Ideally we'd support this in the future, but for now we are limited to sized types.
110
- if !pointee_ty. is_sized ( self . tcx , self . typing_env ) {
111
- debug ! ( "Unsafe pointer, but pointee is not known to be sized: {:?}" , pointer_ty) ;
112
- return ;
113
- }
114
-
115
- // Try to detect types we are sure have an alignment of 1 and skip the check
116
- // We don't need to look for str and slices, we already rejected unsized types above
117
- let element_ty = match pointee_ty. kind ( ) {
118
- ty:: Array ( ty, _) => * ty,
119
- _ => pointee_ty,
120
- } ;
121
- if [ self . tcx . types . bool , self . tcx . types . i8 , self . tcx . types . u8 ] . contains ( & element_ty) {
122
- debug ! ( "Trivially aligned place type: {:?}" , pointee_ty) ;
123
- return ;
124
- }
125
-
126
- // Ensure that this place is based on an aligned pointer.
127
- self . pointers . push ( ( pointer, pointee_ty) ) ;
128
-
129
- self . super_place ( place, context, location) ;
130
- }
131
- }
132
-
133
- fn split_block (
134
- basic_blocks : & mut IndexVec < BasicBlock , BasicBlockData < ' _ > > ,
135
- location : Location ,
136
- ) -> BasicBlock {
137
- let block_data = & mut basic_blocks[ location. block ] ;
138
-
139
- // Drain every statement after this one and move the current terminator to a new basic block
140
- let new_block = BasicBlockData {
141
- statements : block_data. statements . split_off ( location. statement_index ) ,
142
- terminator : block_data. terminator . take ( ) ,
143
- is_cleanup : block_data. is_cleanup ,
144
- } ;
145
-
146
- basic_blocks. push ( new_block)
147
- }
148
-
149
27
fn insert_alignment_check < ' tcx > (
150
28
tcx : TyCtxt < ' tcx > ,
151
29
local_decls : & mut IndexVec < Local , LocalDecl < ' tcx > > ,
0 commit comments