diff options
| author | Ralf Jung <post@ralfj.de> | 2025-07-02 14:16:28 +0200 |
|---|---|---|
| committer | Ralf Jung <post@ralfj.de> | 2025-07-02 14:25:11 +0200 |
| commit | de1278bd16fdef81a2b93f43d4ae9159da716d95 (patch) | |
| tree | ba4691722cddf571a55e74346ba33124b567b3d1 /compiler/rustc_const_eval/src/interpret | |
| parent | f51c9870bab634afb9e7a262b6ca7816bb9e940d (diff) | |
interpret: move the native call preparation logic into Miri
Diffstat (limited to 'compiler/rustc_const_eval/src/interpret')
| -rw-r--r-- | compiler/rustc_const_eval/src/interpret/memory.rs | 61 |
1 files changed, 27 insertions, 34 deletions
diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index 3b36bb85985..ff822b52a8d 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -655,7 +655,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { /// The caller is responsible for calling the access hooks! /// /// You almost certainly want to use `get_ptr_alloc`/`get_ptr_alloc_mut` instead. - fn get_alloc_raw( + pub fn get_alloc_raw( &self, id: AllocId, ) -> InterpResult<'tcx, &Allocation<M::Provenance, M::AllocExtra, M::Bytes>> { @@ -757,7 +757,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { /// /// Also returns a ptr to `self.extra` so that the caller can use it in parallel with the /// allocation. - fn get_alloc_raw_mut( + /// + /// You almost certainly want to use `get_ptr_alloc`/`get_ptr_alloc_mut` instead. + pub fn get_alloc_raw_mut( &mut self, id: AllocId, ) -> InterpResult<'tcx, (&mut Allocation<M::Provenance, M::AllocExtra, M::Bytes>, &mut M)> { @@ -976,15 +978,15 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { interp_ok(()) } - /// Handle the effect an FFI call might have on the state of allocations. - /// This overapproximates the modifications which external code might make to memory: - /// We set all reachable allocations as initialized, mark all reachable provenances as exposed - /// and overwrite them with `Provenance::WILDCARD`. - /// - /// The allocations in `ids` are assumed to be already exposed. - pub fn prepare_for_native_call(&mut self, ids: Vec<AllocId>) -> InterpResult<'tcx> { + /// Visit all allocations reachable from the given start set, by recursively traversing the + /// provenance information of those allocations. + pub fn visit_reachable_allocs( + &mut self, + start: Vec<AllocId>, + mut visit: impl FnMut(&mut Self, AllocId, &AllocInfo) -> InterpResult<'tcx>, + ) -> InterpResult<'tcx> { let mut done = FxHashSet::default(); - let mut todo = ids; + let mut todo = start; while let Some(id) = todo.pop() { if !done.insert(id) { // We already saw this allocation before, don't process it again. @@ -992,31 +994,20 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } let info = self.get_alloc_info(id); - // If there is no data behind this pointer, skip this. - if !matches!(info.kind, AllocKind::LiveData) { - continue; - } - - // Expose all provenances in this allocation, and add them to `todo`. - let alloc = self.get_alloc_raw(id)?; - for prov in alloc.provenance().provenances() { - M::expose_provenance(self, prov)?; - if let Some(id) = prov.get_alloc_id() { - todo.push(id); + // Recurse, if there is data here. + // Do this *before* invoking the callback, as the callback might mutate the + // allocation and e.g. replace all provenance by wildcards! + if matches!(info.kind, AllocKind::LiveData) { + let alloc = self.get_alloc_raw(id)?; + for prov in alloc.provenance().provenances() { + if let Some(id) = prov.get_alloc_id() { + todo.push(id); + } } } - // Also expose the provenance of the interpreter-level allocation, so it can - // be read by FFI. The `black_box` is defensive programming as LLVM likes - // to (incorrectly) optimize away ptr2int casts whose result is unused. - std::hint::black_box(alloc.get_bytes_unchecked_raw().expose_provenance()); - - // Prepare for possible write from native code if mutable. - if info.mutbl.is_mut() { - self.get_alloc_raw_mut(id)? - .0 - .prepare_for_native_write() - .map_err(|e| e.to_interp_error(id))?; - } + + // Call the callback. + visit(self, id, &info)?; } interp_ok(()) } @@ -1073,7 +1064,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { todo.extend(static_roots(self)); while let Some(id) = todo.pop() { if reachable.insert(id) { - // This is a new allocation, add the allocation it points to `todo`. + // This is a new allocation, add the allocations it points to `todo`. + // We only need to care about `alloc_map` memory here, as entirely unchanged + // global memory cannot point to memory relevant for the leak check. if let Some((_, alloc)) = self.memory.alloc_map.get(id) { todo.extend( alloc.provenance().provenances().filter_map(|prov| prov.get_alloc_id()), |
