@@ -655,7 +655,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
655655 /// The caller is responsible for calling the access hooks!
656656 ///
657657 /// You almost certainly want to use `get_ptr_alloc`/`get_ptr_alloc_mut` instead.
658- fn get_alloc_raw (
658+ pub fn get_alloc_raw (
659659 & self ,
660660 id : AllocId ,
661661 ) -> InterpResult < ' tcx , & Allocation < M :: Provenance , M :: AllocExtra , M :: Bytes > > {
@@ -757,7 +757,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
757757 ///
758758 /// Also returns a ptr to `self.extra` so that the caller can use it in parallel with the
759759 /// allocation.
760- fn get_alloc_raw_mut (
760+ ///
761+ /// You almost certainly want to use `get_ptr_alloc`/`get_ptr_alloc_mut` instead.
762+ pub fn get_alloc_raw_mut (
761763 & mut self ,
762764 id : AllocId ,
763765 ) -> InterpResult < ' tcx , ( & mut Allocation < M :: Provenance , M :: AllocExtra , M :: Bytes > , & mut M ) > {
@@ -976,47 +978,36 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
976978 interp_ok ( ( ) )
977979 }
978980
979- /// Handle the effect an FFI call might have on the state of allocations.
980- /// This overapproximates the modifications which external code might make to memory:
981- /// We set all reachable allocations as initialized, mark all reachable provenances as exposed
982- /// and overwrite them with `Provenance::WILDCARD`.
983- ///
984- /// The allocations in `ids` are assumed to be already exposed.
985- pub fn prepare_for_native_call ( & mut self , ids : Vec < AllocId > ) -> InterpResult < ' tcx > {
981+ /// Visit all allocations reachable from the given start set, by recursively traversing the
982+ /// provenance information of those allocations.
983+ pub fn visit_reachable_allocs (
984+ & mut self ,
985+ start : Vec < AllocId > ,
986+ mut visit : impl FnMut ( & mut Self , AllocId , & AllocInfo ) -> InterpResult < ' tcx > ,
987+ ) -> InterpResult < ' tcx > {
986988 let mut done = FxHashSet :: default ( ) ;
987- let mut todo = ids ;
989+ let mut todo = start ;
988990 while let Some ( id) = todo. pop ( ) {
989991 if !done. insert ( id) {
990992 // We already saw this allocation before, don't process it again.
991993 continue ;
992994 }
993995 let info = self . get_alloc_info ( id) ;
994996
995- // If there is no data behind this pointer, skip this.
996- if !matches ! ( info. kind, AllocKind :: LiveData ) {
997- continue ;
998- }
999-
1000- // Expose all provenances in this allocation, and add them to `todo`.
1001- let alloc = self . get_alloc_raw ( id) ?;
1002- for prov in alloc. provenance ( ) . provenances ( ) {
1003- M :: expose_provenance ( self , prov) ?;
1004- if let Some ( id) = prov. get_alloc_id ( ) {
1005- todo. push ( id) ;
997+ // Recurse, if there is data here.
998+ // Do this *before* invoking the callback, as the callback might mutate the
999+ // allocation and e.g. replace all provenance by wildcards!
1000+ if matches ! ( info. kind, AllocKind :: LiveData ) {
1001+ let alloc = self . get_alloc_raw ( id) ?;
1002+ for prov in alloc. provenance ( ) . provenances ( ) {
1003+ if let Some ( id) = prov. get_alloc_id ( ) {
1004+ todo. push ( id) ;
1005+ }
10061006 }
10071007 }
1008- // Also expose the provenance of the interpreter-level allocation, so it can
1009- // be read by FFI. The `black_box` is defensive programming as LLVM likes
1010- // to (incorrectly) optimize away ptr2int casts whose result is unused.
1011- std:: hint:: black_box ( alloc. get_bytes_unchecked_raw ( ) . expose_provenance ( ) ) ;
1012-
1013- // Prepare for possible write from native code if mutable.
1014- if info. mutbl . is_mut ( ) {
1015- self . get_alloc_raw_mut ( id) ?
1016- . 0
1017- . prepare_for_native_write ( )
1018- . map_err ( |e| e. to_interp_error ( id) ) ?;
1019- }
1008+
1009+ // Call the callback.
1010+ visit ( self , id, & info) ?;
10201011 }
10211012 interp_ok ( ( ) )
10221013 }
@@ -1073,7 +1064,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
10731064 todo. extend ( static_roots ( self ) ) ;
10741065 while let Some ( id) = todo. pop ( ) {
10751066 if reachable. insert ( id) {
1076- // This is a new allocation, add the allocation it points to `todo`.
1067+ // This is a new allocation, add the allocations it points to `todo`.
1068+ // We only need to care about `alloc_map` memory here, as entirely unchanged
1069+ // global memory cannot point to memory relevant for the leak check.
10771070 if let Some ( ( _, alloc) ) = self . memory . alloc_map . get ( id) {
10781071 todo. extend (
10791072 alloc. provenance ( ) . provenances ( ) . filter_map ( |prov| prov. get_alloc_id ( ) ) ,
0 commit comments