@@ -102,14 +102,17 @@ impl<'tcx> GotocCtx<'tcx> {
102
102
}
103
103
}
104
104
105
+ /// Members traverse path to get to the raw pointer of a box (b.0.pointer.pointer).
106
+ const RAW_PTR_FROM_BOX : [ & str ; 3 ] = [ "0" , "pointer" , "pointer" ] ;
107
+
105
108
impl < ' tcx > GotocCtx < ' tcx > {
106
109
/// Dereference a boxed type `std::boxed::Box<T>` to get a `*T`.
107
110
///
108
111
/// WARNING: This is based on a manual inspection of how boxed types are currently
109
112
/// a) implemented by the rust standard library
110
113
/// b) codegenned by Kani.
111
114
/// If either of those change, this will almost certainly stop working.
112
- pub fn deref_box ( & self , e : Expr ) -> Expr {
115
+ pub fn deref_box ( & self , box_expr : Expr ) -> Expr {
113
116
// Internally, a Boxed type is stored as a chain of structs.
114
117
// In particular:
115
118
// `Box<T>` is an owning reference to an allocation of type T on the heap.
@@ -137,35 +140,39 @@ impl<'tcx> GotocCtx<'tcx> {
137
140
// };
138
141
// ```
139
142
// And notice that its `.pointer` field is exactly what we want.
140
- self . assert_is_rust_box_like ( e . typ ( ) ) ;
141
- e . member ( "0" , & self . symbol_table ) . member ( "pointer" , & self . symbol_table )
143
+ self . assert_is_rust_box_like ( box_expr . typ ( ) ) ;
144
+ RAW_PTR_FROM_BOX . iter ( ) . fold ( box_expr , |expr , name| expr . member ( name , & self . symbol_table ) )
142
145
}
143
146
144
147
/// Box<T> initializer
145
- /// `boxed_type the_box = >>> { .0=nondet(), .1={ ._marker=nondet(), .pointer=boxed_value } } <<<`
148
+ ///
149
+ /// Traverse over the Box representation and only initialize the raw_ptr field. All other
150
+ /// members are left uninitialized.
146
151
/// `boxed_type` is the type of the resulting expression
147
152
pub fn box_value ( & self , boxed_value : Expr , boxed_type : Type ) -> Expr {
148
153
self . assert_is_rust_box_like ( & boxed_type) ;
149
- let unique_ptr_typ = boxed_type. lookup_field_type ( "0" , & self . symbol_table ) . unwrap ( ) ;
150
- self . assert_is_rust_unique_pointer_like ( & unique_ptr_typ) ;
151
- let unique_ptr_pointer_typ =
152
- unique_ptr_typ. lookup_field_type ( "pointer" , & self . symbol_table ) . unwrap ( ) ;
153
- assert_eq ! ( & unique_ptr_pointer_typ, boxed_value. typ( ) ) ;
154
- let unique_ptr_val = Expr :: struct_expr_with_nondet_fields (
155
- unique_ptr_typ,
156
- btree_string_map ! [ ( "pointer" , boxed_value) , ] ,
157
- & self . symbol_table ,
158
- ) ;
159
- let boxed_val = Expr :: struct_expr_with_nondet_fields (
160
- boxed_type,
161
- btree_string_map ! [ ( "0" , unique_ptr_val) , ] ,
162
- & self . symbol_table ,
163
- ) ;
164
- boxed_val
154
+ tracing:: debug!( ?boxed_type, ?boxed_value, "box_value" ) ;
155
+ let mut inner_type = boxed_type;
156
+ let type_members = RAW_PTR_FROM_BOX
157
+ . iter ( )
158
+ . map ( |name| {
159
+ let outer_type = inner_type. clone ( ) ;
160
+ inner_type = outer_type. lookup_field_type ( name, & self . symbol_table ) . unwrap ( ) ;
161
+ ( * name, outer_type)
162
+ } )
163
+ . collect :: < Vec < _ > > ( ) ;
164
+
165
+ type_members. iter ( ) . rev ( ) . fold ( boxed_value, |value, ( name, typ) | {
166
+ Expr :: struct_expr_with_nondet_fields (
167
+ typ. clone ( ) ,
168
+ btree_string_map ! [ ( * name, value) , ] ,
169
+ & self . symbol_table ,
170
+ )
171
+ } )
165
172
}
166
173
167
174
/// Best effort check if the struct represents a rust "std::alloc::Global".
168
- pub fn assert_is_rust_global_alloc_like ( & self , t : & Type ) {
175
+ fn assert_is_rust_global_alloc_like ( & self , t : & Type ) {
169
176
// TODO: A std::alloc::Global appears to be an empty struct, in the cases we've seen.
170
177
// Is there something smarter we can do here?
171
178
assert ! ( t. is_struct_like( ) ) ;
@@ -174,7 +181,7 @@ impl<'tcx> GotocCtx<'tcx> {
174
181
}
175
182
176
183
/// Best effort check if the struct represents a rust "std::marker::PhantomData".
177
- pub fn assert_is_rust_phantom_data_like ( & self , t : & Type ) {
184
+ fn assert_is_rust_phantom_data_like ( & self , t : & Type ) {
178
185
// TODO: A std::marker::PhantomData appears to be an empty struct, in the cases we've seen.
179
186
// Is there something smarter we can do here?
180
187
assert ! ( t. is_struct_like( ) ) ;
@@ -183,7 +190,7 @@ impl<'tcx> GotocCtx<'tcx> {
183
190
}
184
191
185
192
/// Best effort check if the struct represents a Rust "Box". May return false positives.
186
- pub fn assert_is_rust_box_like ( & self , t : & Type ) {
193
+ fn assert_is_rust_box_like ( & self , t : & Type ) {
187
194
// struct std::boxed::Box<[u8; 8]>::15334369982748499855
188
195
// {
189
196
// // 1
@@ -204,25 +211,40 @@ impl<'tcx> GotocCtx<'tcx> {
204
211
}
205
212
206
213
/// Checks if the struct represents a Rust "std::ptr::Unique"
207
- pub fn assert_is_rust_unique_pointer_like ( & self , t : & Type ) {
214
+ fn assert_is_rust_unique_pointer_like ( & self , t : & Type ) {
208
215
// struct std::ptr::Unique<[u8; 8]>::14713681870393313245
209
216
// {
210
217
// // _marker
211
218
// struct std::marker::PhantomData<[u8; 8]>::18073278521438838603 _marker;
212
219
// // pointer
213
- // struct [u8::16712579856250238426; 8] * pointer;
220
+ // NonNull<T> pointer;
214
221
// };
215
222
assert ! ( t. is_struct_like( ) ) ;
216
223
let components = t. lookup_components ( & self . symbol_table ) . unwrap ( ) ;
217
224
assert_eq ! ( components. len( ) , 2 ) ;
218
225
for c in components {
219
226
match c. name ( ) . to_string ( ) . as_str ( ) {
220
227
"_marker" => self . assert_is_rust_phantom_data_like ( & c. typ ( ) ) ,
221
- "pointer" => {
222
- assert ! ( c. typ( ) . is_pointer( ) || c. typ( ) . is_rust_fat_ptr( & self . symbol_table) )
223
- }
228
+ "pointer" => self . assert_is_non_null_like ( & c. typ ( ) ) ,
224
229
_ => panic ! ( "Unexpected component {} in {:?}" , c. name( ) , t) ,
225
230
}
226
231
}
227
232
}
233
+
234
+ /// Best effort check if the struct represents a std::ptr::NonNull<T>.
235
+ ///
236
+ /// This assumes the following structure. Any changes to this will break this code.
237
+ /// ```
238
+ /// pub struct NonNull<T: ?Sized> {
239
+ /// pointer: *const T,
240
+ /// }
241
+ /// ```
242
+ fn assert_is_non_null_like ( & self , t : & Type ) {
243
+ assert ! ( t. is_struct_like( ) ) ;
244
+ let components = t. lookup_components ( & self . symbol_table ) . unwrap ( ) ;
245
+ assert_eq ! ( components. len( ) , 1 ) ;
246
+ let component = components. first ( ) . unwrap ( ) ;
247
+ assert_eq ! ( component. name( ) . to_string( ) . as_str( ) , "pointer" ) ;
248
+ assert ! ( component. typ( ) . is_pointer( ) || component. typ( ) . is_rust_fat_ptr( & self . symbol_table) )
249
+ }
228
250
}
0 commit comments