@@ -102,14 +102,17 @@ impl<'tcx> GotocCtx<'tcx> {
102102 }
103103}
104104
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+
105108impl < ' tcx > GotocCtx < ' tcx > {
106109 /// Dereference a boxed type `std::boxed::Box<T>` to get a `*T`.
107110 ///
108111 /// WARNING: This is based on a manual inspection of how boxed types are currently
109112 /// a) implemented by the rust standard library
110113 /// b) codegenned by Kani.
111114 /// 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 {
113116 // Internally, a Boxed type is stored as a chain of structs.
114117 // In particular:
115118 // `Box<T>` is an owning reference to an allocation of type T on the heap.
@@ -137,35 +140,39 @@ impl<'tcx> GotocCtx<'tcx> {
137140 // };
138141 // ```
139142 // 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 ) )
142145 }
143146
144147 /// 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.
146151 /// `boxed_type` is the type of the resulting expression
147152 pub fn box_value ( & self , boxed_value : Expr , boxed_type : Type ) -> Expr {
148153 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+ } )
165172 }
166173
167174 /// 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 ) {
169176 // TODO: A std::alloc::Global appears to be an empty struct, in the cases we've seen.
170177 // Is there something smarter we can do here?
171178 assert ! ( t. is_struct_like( ) ) ;
@@ -174,7 +181,7 @@ impl<'tcx> GotocCtx<'tcx> {
174181 }
175182
176183 /// 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 ) {
178185 // TODO: A std::marker::PhantomData appears to be an empty struct, in the cases we've seen.
179186 // Is there something smarter we can do here?
180187 assert ! ( t. is_struct_like( ) ) ;
@@ -183,7 +190,7 @@ impl<'tcx> GotocCtx<'tcx> {
183190 }
184191
185192 /// 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 ) {
187194 // struct std::boxed::Box<[u8; 8]>::15334369982748499855
188195 // {
189196 // // 1
@@ -204,25 +211,40 @@ impl<'tcx> GotocCtx<'tcx> {
204211 }
205212
206213 /// 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 ) {
208215 // struct std::ptr::Unique<[u8; 8]>::14713681870393313245
209216 // {
210217 // // _marker
211218 // struct std::marker::PhantomData<[u8; 8]>::18073278521438838603 _marker;
212219 // // pointer
213- // struct [u8::16712579856250238426; 8] * pointer;
220+ // NonNull<T> pointer;
214221 // };
215222 assert ! ( t. is_struct_like( ) ) ;
216223 let components = t. lookup_components ( & self . symbol_table ) . unwrap ( ) ;
217224 assert_eq ! ( components. len( ) , 2 ) ;
218225 for c in components {
219226 match c. name ( ) . to_string ( ) . as_str ( ) {
220227 "_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 ( ) ) ,
224229 _ => panic ! ( "Unexpected component {} in {:?}" , c. name( ) , t) ,
225230 }
226231 }
227232 }
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+ }
228250}
0 commit comments