@@ -655,7 +655,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
655
655
/// The caller is responsible for calling the access hooks!
656
656
///
657
657
/// 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 (
659
659
& self ,
660
660
id : AllocId ,
661
661
) -> InterpResult < ' tcx , & Allocation < M :: Provenance , M :: AllocExtra , M :: Bytes > > {
@@ -757,7 +757,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
757
757
///
758
758
/// Also returns a ptr to `self.extra` so that the caller can use it in parallel with the
759
759
/// 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 (
761
763
& mut self ,
762
764
id : AllocId ,
763
765
) -> InterpResult < ' tcx , ( & mut Allocation < M :: Provenance , M :: AllocExtra , M :: Bytes > , & mut M ) > {
@@ -976,47 +978,36 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
976
978
interp_ok ( ( ) )
977
979
}
978
980
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 > {
986
988
let mut done = FxHashSet :: default ( ) ;
987
- let mut todo = ids ;
989
+ let mut todo = start ;
988
990
while let Some ( id) = todo. pop ( ) {
989
991
if !done. insert ( id) {
990
992
// We already saw this allocation before, don't process it again.
991
993
continue ;
992
994
}
993
995
let info = self . get_alloc_info ( id) ;
994
996
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
+ }
1006
1006
}
1007
1007
}
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) ?;
1020
1011
}
1021
1012
interp_ok ( ( ) )
1022
1013
}
@@ -1073,7 +1064,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
1073
1064
todo. extend ( static_roots ( self ) ) ;
1074
1065
while let Some ( id) = todo. pop ( ) {
1075
1066
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.
1077
1070
if let Some ( ( _, alloc) ) = self . memory . alloc_map . get ( id) {
1078
1071
todo. extend (
1079
1072
alloc. provenance ( ) . provenances ( ) . filter_map ( |prov| prov. get_alloc_id ( ) ) ,
0 commit comments