8
8
9
9
use std:: assert_matches:: assert_matches;
10
10
use std:: borrow:: Cow ;
11
- use std:: cell:: Cell ;
12
11
use std:: collections:: VecDeque ;
13
- use std:: { fmt, ptr} ;
12
+ use std:: { fmt, mem , ptr} ;
14
13
15
14
use rustc_ast:: Mutability ;
16
15
use rustc_data_structures:: fx:: { FxHashSet , FxIndexMap } ;
@@ -118,7 +117,7 @@ pub struct Memory<'tcx, M: Machine<'tcx>> {
118
117
/// This stores whether we are currently doing reads purely for the purpose of validation.
119
118
/// Those reads do not trigger the machine's hooks for memory reads.
120
119
/// Needless to say, this must only be set with great care!
121
- validation_in_progress : Cell < bool > ,
120
+ validation_in_progress : bool ,
122
121
}
123
122
124
123
/// A reference to some allocation that was already bounds-checked for the given region
@@ -145,7 +144,7 @@ impl<'tcx, M: Machine<'tcx>> Memory<'tcx, M> {
145
144
alloc_map : M :: MemoryMap :: default ( ) ,
146
145
extra_fn_ptr_map : FxIndexMap :: default ( ) ,
147
146
dead_alloc_map : FxIndexMap :: default ( ) ,
148
- validation_in_progress : Cell :: new ( false ) ,
147
+ validation_in_progress : false ,
149
148
}
150
149
}
151
150
@@ -682,15 +681,15 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
682
681
// We want to call the hook on *all* accesses that involve an AllocId, including zero-sized
683
682
// accesses. That means we cannot rely on the closure above or the `Some` branch below. We
684
683
// do this after `check_and_deref_ptr` to ensure some basic sanity has already been checked.
685
- if !self . memory . validation_in_progress . get ( ) {
684
+ if !self . memory . validation_in_progress {
686
685
if let Ok ( ( alloc_id, ..) ) = self . ptr_try_get_alloc_id ( ptr, size_i64) {
687
686
M :: before_alloc_read ( self , alloc_id) ?;
688
687
}
689
688
}
690
689
691
690
if let Some ( ( alloc_id, offset, prov, alloc) ) = ptr_and_alloc {
692
691
let range = alloc_range ( offset, size) ;
693
- if !self . memory . validation_in_progress . get ( ) {
692
+ if !self . memory . validation_in_progress {
694
693
M :: before_memory_read (
695
694
self . tcx ,
696
695
& self . machine ,
@@ -766,11 +765,14 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
766
765
let parts = self . get_ptr_access ( ptr, size) ?;
767
766
if let Some ( ( alloc_id, offset, prov) ) = parts {
768
767
let tcx = self . tcx ;
768
+ let validation_in_progress = self . memory . validation_in_progress ;
769
769
// FIXME: can we somehow avoid looking up the allocation twice here?
770
770
// We cannot call `get_raw_mut` inside `check_and_deref_ptr` as that would duplicate `&mut self`.
771
771
let ( alloc, machine) = self . get_alloc_raw_mut ( alloc_id) ?;
772
772
let range = alloc_range ( offset, size) ;
773
- M :: before_memory_write ( tcx, machine, & mut alloc. extra , ( alloc_id, prov) , range) ?;
773
+ if !validation_in_progress {
774
+ M :: before_memory_write ( tcx, machine, & mut alloc. extra , ( alloc_id, prov) , range) ?;
775
+ }
774
776
Ok ( Some ( AllocRefMut { alloc, range, tcx : * tcx, alloc_id } ) )
775
777
} else {
776
778
Ok ( None )
@@ -1014,16 +1016,16 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
1014
1016
///
1015
1017
/// We do this so Miri's allocation access tracking does not show the validation
1016
1018
/// reads as spurious accesses.
1017
- pub fn run_for_validation < R > ( & self , f : impl FnOnce ( ) -> R ) -> R {
1019
+ pub fn run_for_validation < R > ( & mut self , f : impl FnOnce ( & mut Self ) -> R ) -> R {
1018
1020
// This deliberately uses `==` on `bool` to follow the pattern
1019
1021
// `assert!(val.replace(new) == old)`.
1020
1022
assert ! (
1021
- self . memory. validation_in_progress. replace ( true ) == false ,
1023
+ mem :: replace ( & mut self . memory. validation_in_progress, true ) == false ,
1022
1024
"`validation_in_progress` was already set"
1023
1025
) ;
1024
- let res = f ( ) ;
1026
+ let res = f ( self ) ;
1025
1027
assert ! (
1026
- self . memory. validation_in_progress. replace ( false ) == true ,
1028
+ mem :: replace ( & mut self . memory. validation_in_progress, false ) == true ,
1027
1029
"`validation_in_progress` was unset by someone else"
1028
1030
) ;
1029
1031
res
@@ -1115,6 +1117,10 @@ impl<'a, 'tcx, M: Machine<'tcx>> std::fmt::Debug for DumpAllocs<'a, 'tcx, M> {
1115
1117
impl < ' tcx , ' a , Prov : Provenance , Extra , Bytes : AllocBytes >
1116
1118
AllocRefMut < ' a , ' tcx , Prov , Extra , Bytes >
1117
1119
{
1120
+ pub fn as_ref < ' b > ( & ' b self ) -> AllocRef < ' b , ' tcx , Prov , Extra , Bytes > {
1121
+ AllocRef { alloc : self . alloc , range : self . range , tcx : self . tcx , alloc_id : self . alloc_id }
1122
+ }
1123
+
1118
1124
/// `range` is relative to this allocation reference, not the base of the allocation.
1119
1125
pub fn write_scalar ( & mut self , range : AllocRange , val : Scalar < Prov > ) -> InterpResult < ' tcx > {
1120
1126
let range = self . range . subrange ( range) ;
@@ -1130,13 +1136,30 @@ impl<'tcx, 'a, Prov: Provenance, Extra, Bytes: AllocBytes>
1130
1136
self . write_scalar ( alloc_range ( offset, self . tcx . data_layout ( ) . pointer_size ) , val)
1131
1137
}
1132
1138
1139
+ /// Mark the given sub-range (relative to this allocation reference) as uninitialized.
1140
+ pub fn write_uninit ( & mut self , range : AllocRange ) -> InterpResult < ' tcx > {
1141
+ let range = self . range . subrange ( range) ;
1142
+ Ok ( self
1143
+ . alloc
1144
+ . write_uninit ( & self . tcx , range)
1145
+ . map_err ( |e| e. to_interp_error ( self . alloc_id ) ) ?)
1146
+ }
1147
+
1133
1148
/// Mark the entire referenced range as uninitialized
1134
- pub fn write_uninit ( & mut self ) -> InterpResult < ' tcx > {
1149
+ pub fn write_uninit_full ( & mut self ) -> InterpResult < ' tcx > {
1135
1150
Ok ( self
1136
1151
. alloc
1137
1152
. write_uninit ( & self . tcx , self . range )
1138
1153
. map_err ( |e| e. to_interp_error ( self . alloc_id ) ) ?)
1139
1154
}
1155
+
1156
+ /// Remove all provenance in the reference range.
1157
+ pub fn clear_provenance ( & mut self ) -> InterpResult < ' tcx > {
1158
+ Ok ( self
1159
+ . alloc
1160
+ . clear_provenance ( & self . tcx , self . range )
1161
+ . map_err ( |e| e. to_interp_error ( self . alloc_id ) ) ?)
1162
+ }
1140
1163
}
1141
1164
1142
1165
impl < ' tcx , ' a , Prov : Provenance , Extra , Bytes : AllocBytes > AllocRef < ' a , ' tcx , Prov , Extra , Bytes > {
@@ -1278,7 +1301,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
1278
1301
} ;
1279
1302
let src_alloc = self . get_alloc_raw ( src_alloc_id) ?;
1280
1303
let src_range = alloc_range ( src_offset, size) ;
1281
- assert ! ( !self . memory. validation_in_progress. get ( ) , "we can't be copying during validation" ) ;
1304
+ assert ! ( !self . memory. validation_in_progress, "we can't be copying during validation" ) ;
1282
1305
M :: before_memory_read (
1283
1306
tcx,
1284
1307
& self . machine ,
0 commit comments