1
- use rustc_middle :: mir :: interpret :: { Allocation , ConstAllocation } ;
2
- use rustc_middle:: mir:: Mutability ;
1
+ use rustc_hir :: lang_items :: LangItem ;
2
+ use rustc_middle:: mir:: interpret :: { AllocRange , Allocation , ConstAllocation , Scalar as MirScalar } ;
3
3
use rustc_middle:: ty:: layout:: LayoutCx ;
4
4
use rustc_middle:: ty:: { ParamEnv , ParamEnvAnd } ;
5
5
use rustc_middle:: ty:: { Ty , TyCtxt } ;
6
6
use rustc_target:: abi:: {
7
- Abi , Align , Endian , FieldsShape , HasDataLayout , Scalar , Size , WrappingRange ,
7
+ Abi , FieldsShape , HasDataLayout , Integer , Primitive , Scalar , Size , TyAndLayout , WrappingRange ,
8
8
} ;
9
9
10
+ #[ derive( Debug , Clone , Copy ) ]
11
+ enum InvariantSize {
12
+ U8 ,
13
+ U16 ,
14
+ U32 ,
15
+ U64 ,
16
+ U128 ,
17
+ Pointer ,
18
+ }
19
+
10
20
#[ derive( Debug , Clone , Copy ) ]
11
21
struct Invariant {
12
22
offset : Size ,
13
- size : Size ,
14
- start : u128 ,
15
- end : u128 ,
23
+ size : InvariantSize ,
24
+ valid_range_start : u128 ,
25
+ valid_range_end : u128 ,
16
26
}
17
27
18
- // TODO : Don't add duplicate invariants (maybe use a HashMap?)
28
+ // FIXME : Don't add duplicate invariants (maybe use a HashMap?)
19
29
fn add_invariants < ' tcx > ( tcx : TyCtxt < ' tcx > , ty : Ty < ' tcx > , invs : & mut Vec < Invariant > , offset : Size ) {
20
30
let x = tcx. layout_of ( ParamEnvAnd { param_env : ParamEnv :: reveal_all ( ) , value : ty } ) ;
21
31
22
32
if let Ok ( layout) = x {
23
33
if let Abi :: Scalar ( Scalar :: Initialized { value, valid_range } ) = layout. layout . abi ( ) {
24
- let size = value. size ( & tcx) ;
34
+ let size = match value {
35
+ Primitive :: Int ( Integer :: I8 , _) => InvariantSize :: U8 ,
36
+ Primitive :: Int ( Integer :: I16 , _) => InvariantSize :: U16 ,
37
+ Primitive :: Int ( Integer :: I32 , _) => InvariantSize :: U32 ,
38
+ Primitive :: Int ( Integer :: I64 , _) => InvariantSize :: U64 ,
39
+ Primitive :: Int ( Integer :: I128 , _) => InvariantSize :: U128 ,
40
+ Primitive :: F32 => InvariantSize :: U32 ,
41
+ Primitive :: F64 => InvariantSize :: U64 ,
42
+ Primitive :: Pointer => InvariantSize :: Pointer ,
43
+ } ;
25
44
let WrappingRange { start, end } = valid_range;
26
- invs. push ( Invariant { offset, size, start, end } )
45
+ invs. push ( Invariant { offset, size, valid_range_start : start, valid_range_end : end } )
27
46
}
28
47
29
48
let param_env = ParamEnv :: reveal_all ( ) ;
@@ -33,8 +52,8 @@ fn add_invariants<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, invs: &mut Vec<Invarian
33
52
FieldsShape :: Primitive => { }
34
53
FieldsShape :: Union ( _) => { }
35
54
FieldsShape :: Array { stride, count } => {
36
- // TODO: should we just bail if we're making a Too Large type?
37
- // (Like [bool; 1_000_000])
55
+ // We may wish to bail out if we're generating too many invariants.
56
+ // That would lead to false negatives, though.
38
57
for idx in 0 ..* count {
39
58
let off = offset + * stride * idx;
40
59
let f = layout. field ( & unwrap, idx as usize ) ;
@@ -57,22 +76,13 @@ fn add_invariants<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, invs: &mut Vec<Invarian
57
76
}
58
77
}
59
78
60
- fn extend_encoded_int ( to : & mut Vec < u8 > , endian : Endian , ptr_size : PointerSize , value : Size ) {
61
- match ( endian, ptr_size) {
62
- ( Endian :: Little , PointerSize :: Bits16 ) => to. extend ( ( value. bytes ( ) as u16 ) . to_le_bytes ( ) ) ,
63
- ( Endian :: Little , PointerSize :: Bits32 ) => to. extend ( ( value. bytes ( ) as u32 ) . to_le_bytes ( ) ) ,
64
- ( Endian :: Little , PointerSize :: Bits64 ) => to. extend ( ( value. bytes ( ) ) . to_le_bytes ( ) ) ,
65
- ( Endian :: Big , PointerSize :: Bits16 ) => to. extend ( ( value. bytes ( ) as u16 ) . to_be_bytes ( ) ) ,
66
- ( Endian :: Big , PointerSize :: Bits32 ) => to. extend ( ( value. bytes ( ) as u32 ) . to_be_bytes ( ) ) ,
67
- ( Endian :: Big , PointerSize :: Bits64 ) => to. extend ( ( value. bytes ( ) ) . to_be_bytes ( ) ) ,
68
- }
69
- }
70
-
71
- #[ derive( Clone , Copy ) ]
72
- enum PointerSize {
73
- Bits16 ,
74
- Bits32 ,
75
- Bits64 ,
79
+ fn get_layout_of_invariant < ' tcx > ( tcx : TyCtxt < ' tcx > ) -> TyAndLayout < ' tcx , Ty < ' tcx > > {
80
+ let item = tcx. require_lang_item ( LangItem :: ValidityInvariant , None ) ;
81
+ let ty = tcx. type_of ( item) ;
82
+ let layout = tcx
83
+ . layout_of ( ParamEnv :: reveal_all ( ) . and ( ty) )
84
+ . expect ( "invalid layout for ValidityInvariant lang item" ) ;
85
+ layout
76
86
}
77
87
78
88
/// Directly returns a `ConstAllocation` containing a list of validity invariants of the given type.
@@ -83,38 +93,54 @@ pub(crate) fn alloc_validity_invariants_of<'tcx>(
83
93
let mut invs: Vec < Invariant > = Vec :: new ( ) ;
84
94
85
95
let layout = tcx. data_layout ( ) ;
86
-
87
- let ptr_size = match layout. pointer_size . bits ( ) {
88
- 16 => PointerSize :: Bits16 ,
89
- 32 => PointerSize :: Bits32 ,
90
- 64 => PointerSize :: Bits64 ,
91
- _ => {
92
- // Not sure if this can happen, but just return an empty slice?
93
- let alloc =
94
- Allocation :: from_bytes ( Vec :: new ( ) , Align :: from_bytes ( 8 ) . unwrap ( ) , Mutability :: Not ) ;
95
- return tcx. intern_const_alloc ( alloc) ;
96
- }
97
- } ;
96
+ let validity_invariant = get_layout_of_invariant ( tcx) ;
98
97
99
98
add_invariants ( tcx, ty, & mut invs, Size :: ZERO ) ;
100
99
101
- let encode_range = match layout. endian {
102
- Endian :: Little => |r : u128 | r. to_le_bytes ( ) ,
103
- Endian :: Big => |r : u128 | r. to_be_bytes ( ) ,
104
- } ;
100
+ let allocation_size = validity_invariant. layout . size ( ) * invs. len ( ) as u64 ;
101
+ let mut alloc =
102
+ Allocation :: uninit ( allocation_size, validity_invariant. layout . align ( ) . abi , true ) . unwrap ( ) ;
103
+
104
+ let offset_off = validity_invariant. layout . fields ( ) . offset ( 0 ) ;
105
+ let size_off = validity_invariant. layout . fields ( ) . offset ( 1 ) ;
106
+ let start_off = validity_invariant. layout . fields ( ) . offset ( 2 ) ;
107
+ let end_off = validity_invariant. layout . fields ( ) . offset ( 3 ) ;
108
+
109
+ for ( idx, invariant) in invs. iter ( ) . enumerate ( ) {
110
+ let offset = idx as u64 * validity_invariant. layout . size ( ) ;
111
+
112
+ let offset_range = AllocRange { start : offset + offset_off, size : layout. pointer_size } ;
113
+ alloc
114
+ . write_scalar (
115
+ & tcx,
116
+ offset_range,
117
+ MirScalar :: from_machine_usize ( invariant. offset . bytes ( ) , & tcx) . into ( ) ,
118
+ )
119
+ . unwrap ( ) ;
120
+
121
+ let size_range = AllocRange { start : offset + size_off, size : Size :: from_bytes ( 1 ) } ;
122
+ alloc
123
+ . write_scalar ( & tcx, size_range, MirScalar :: from_u8 ( invariant. size as u8 ) . into ( ) )
124
+ . unwrap ( ) ;
105
125
106
- let mut encoded = Vec :: new ( ) ;
126
+ let offset_range = AllocRange { start : offset + start_off, size : Size :: from_bytes ( 16 ) } ;
127
+ alloc
128
+ . write_scalar (
129
+ & tcx,
130
+ offset_range,
131
+ MirScalar :: from_u128 ( invariant. valid_range_start ) . into ( ) ,
132
+ )
133
+ . unwrap ( ) ;
107
134
108
- // TODO: this needs to match the layout of `Invariant` in core/src/intrinsics.rs
109
- // how do we ensure that?
110
- for inv in invs {
111
- extend_encoded_int ( & mut encoded, layout. endian , ptr_size, inv. offset ) ;
112
- extend_encoded_int ( & mut encoded, layout. endian , ptr_size, inv. size ) ;
113
- encoded. extend ( encode_range ( inv. start ) ) ;
114
- encoded. extend ( encode_range ( inv. end ) ) ;
135
+ let offset_range = AllocRange { start : offset + end_off, size : Size :: from_bytes ( 16 ) } ;
136
+ alloc
137
+ . write_scalar (
138
+ & tcx,
139
+ offset_range,
140
+ MirScalar :: from_u128 ( invariant. valid_range_end ) . into ( ) ,
141
+ )
142
+ . unwrap ( ) ;
115
143
}
116
144
117
- // TODO: The alignment here should be calculated from the struct definition, I guess?
118
- let alloc = Allocation :: from_bytes ( encoded, Align :: from_bytes ( 8 ) . unwrap ( ) , Mutability :: Not ) ;
119
145
tcx. intern_const_alloc ( alloc)
120
146
}
0 commit comments