also add type aliases for the pointer types
This commit is contained in:
parent
fcb4cf52d8
commit
98a3ac9e6d
19 changed files with 105 additions and 148 deletions
|
|
@ -257,7 +257,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn ptr_from_addr_cast(&self, addr: u64) -> InterpResult<'tcx, Pointer<Option<Provenance>>> {
|
||||
fn ptr_from_addr_cast(&self, addr: u64) -> InterpResult<'tcx, Pointer> {
|
||||
trace!("Casting {:#x} to a pointer", addr);
|
||||
|
||||
let ecx = self.eval_context_ref();
|
||||
|
|
@ -297,10 +297,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
/// Convert a relative (tcx) pointer to a Miri pointer.
|
||||
fn adjust_alloc_root_pointer(
|
||||
&self,
|
||||
ptr: Pointer<CtfeProvenance>,
|
||||
ptr: interpret::Pointer<CtfeProvenance>,
|
||||
tag: BorTag,
|
||||
kind: MemoryKind,
|
||||
) -> InterpResult<'tcx, Pointer<Provenance>> {
|
||||
) -> InterpResult<'tcx, interpret::Pointer<Provenance>> {
|
||||
let ecx = self.eval_context_ref();
|
||||
|
||||
let (prov, offset) = ptr.into_parts(); // offset is relative (AllocId provenance)
|
||||
|
|
@ -310,12 +310,15 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
// Add offset with the right kind of pointer-overflowing arithmetic.
|
||||
let dl = ecx.data_layout();
|
||||
let absolute_addr = dl.overflowing_offset(base_addr, offset.bytes()).0;
|
||||
Ok(Pointer::new(Provenance::Concrete { alloc_id, tag }, Size::from_bytes(absolute_addr)))
|
||||
Ok(interpret::Pointer::new(
|
||||
Provenance::Concrete { alloc_id, tag },
|
||||
Size::from_bytes(absolute_addr),
|
||||
))
|
||||
}
|
||||
|
||||
/// When a pointer is used for a memory access, this computes where in which allocation the
|
||||
/// access is going.
|
||||
fn ptr_get_alloc(&self, ptr: Pointer<Provenance>) -> Option<(AllocId, Size)> {
|
||||
fn ptr_get_alloc(&self, ptr: interpret::Pointer<Provenance>) -> Option<(AllocId, Size)> {
|
||||
let ecx = self.eval_context_ref();
|
||||
|
||||
let (tag, addr) = ptr.into_parts(); // addr is absolute (Tag provenance)
|
||||
|
|
|
|||
|
|
@ -324,7 +324,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
|
||||
fn give_pointer_debug_name(
|
||||
&mut self,
|
||||
ptr: Pointer<Option<Provenance>>,
|
||||
ptr: Pointer,
|
||||
nth_parent: u8,
|
||||
name: &str,
|
||||
) -> InterpResult<'tcx> {
|
||||
|
|
|
|||
|
|
@ -531,7 +531,7 @@ impl Stacks {
|
|||
trace!(
|
||||
"read access with tag {:?}: {:?}, size {}",
|
||||
tag,
|
||||
Pointer::new(alloc_id, range.start),
|
||||
interpret::Pointer::new(alloc_id, range.start),
|
||||
range.size.bytes()
|
||||
);
|
||||
let dcx = DiagnosticCxBuilder::read(machine, tag, range);
|
||||
|
|
@ -552,7 +552,7 @@ impl Stacks {
|
|||
trace!(
|
||||
"write access with tag {:?}: {:?}, size {}",
|
||||
tag,
|
||||
Pointer::new(alloc_id, range.start),
|
||||
interpret::Pointer::new(alloc_id, range.start),
|
||||
range.size.bytes()
|
||||
);
|
||||
let dcx = DiagnosticCxBuilder::write(machine, tag, range);
|
||||
|
|
@ -692,7 +692,7 @@ trait EvalContextPrivExt<'tcx, 'ecx>: crate::MiriInterpCxExt<'tcx> {
|
|||
new_tag,
|
||||
orig_tag,
|
||||
place.layout.ty,
|
||||
Pointer::new(alloc_id, base_offset),
|
||||
interpret::Pointer::new(alloc_id, base_offset),
|
||||
size.bytes()
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ impl<'tcx> Tree {
|
|||
"{} with tag {:?}: {:?}, size {}",
|
||||
access_kind,
|
||||
prov,
|
||||
Pointer::new(alloc_id, range.start),
|
||||
interpret::Pointer::new(alloc_id, range.start),
|
||||
range.size.bytes(),
|
||||
);
|
||||
// TODO: for now we bail out on wildcard pointers. Eventually we should
|
||||
|
|
@ -258,7 +258,7 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
new_tag,
|
||||
orig_tag,
|
||||
place.layout.ty,
|
||||
Pointer::new(alloc_id, base_offset),
|
||||
interpret::Pointer::new(alloc_id, base_offset),
|
||||
ptr_size.bytes()
|
||||
);
|
||||
|
||||
|
|
@ -574,7 +574,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
/// of `ptr` (with 0 representing `ptr` itself)
|
||||
fn tb_give_pointer_debug_name(
|
||||
&mut self,
|
||||
ptr: Pointer<Option<Provenance>>,
|
||||
ptr: Pointer,
|
||||
nth_parent: u8,
|
||||
name: &str,
|
||||
) -> InterpResult<'tcx> {
|
||||
|
|
|
|||
|
|
@ -948,7 +948,7 @@ impl VClockAlloc {
|
|||
mem_clocks: &MemoryCellClocks,
|
||||
access: AccessType,
|
||||
access_size: Size,
|
||||
ptr_dbg: Pointer<AllocId>,
|
||||
ptr_dbg: interpret::Pointer<AllocId>,
|
||||
ty: Option<Ty<'_>>,
|
||||
) -> InterpResult<'tcx> {
|
||||
let (active_index, active_clocks) = global.active_thread_state(thread_mgr);
|
||||
|
|
@ -1063,7 +1063,7 @@ impl VClockAlloc {
|
|||
mem_clocks,
|
||||
AccessType::NaRead(read_type),
|
||||
access_range.size,
|
||||
Pointer::new(alloc_id, Size::from_bytes(mem_clocks_range.start)),
|
||||
interpret::Pointer::new(alloc_id, Size::from_bytes(mem_clocks_range.start)),
|
||||
ty,
|
||||
);
|
||||
}
|
||||
|
|
@ -1108,7 +1108,7 @@ impl VClockAlloc {
|
|||
mem_clocks,
|
||||
AccessType::NaWrite(write_type),
|
||||
access_range.size,
|
||||
Pointer::new(alloc_id, Size::from_bytes(mem_clocks_range.start)),
|
||||
interpret::Pointer::new(alloc_id, Size::from_bytes(mem_clocks_range.start)),
|
||||
ty,
|
||||
);
|
||||
}
|
||||
|
|
@ -1337,7 +1337,7 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> {
|
|||
mem_clocks,
|
||||
access,
|
||||
place.layout.size,
|
||||
Pointer::new(
|
||||
interpret::Pointer::new(
|
||||
alloc_id,
|
||||
Size::from_bytes(mem_clocks_range.start),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -432,9 +432,8 @@ pub struct ThreadManager<'tcx> {
|
|||
///
|
||||
/// Note that this vector also contains terminated threads.
|
||||
threads: IndexVec<ThreadId, Thread<'tcx>>,
|
||||
/// A mapping from a thread-local static to an allocation id of a thread
|
||||
/// specific allocation.
|
||||
thread_local_alloc_ids: FxHashMap<(DefId, ThreadId), Pointer<Provenance>>,
|
||||
/// A mapping from a thread-local static to the thread specific allocation.
|
||||
thread_local_allocs: FxHashMap<(DefId, ThreadId), StrictPointer>,
|
||||
/// A flag that indicates that we should change the active thread.
|
||||
yield_active_thread: bool,
|
||||
}
|
||||
|
|
@ -443,7 +442,7 @@ impl VisitProvenance for ThreadManager<'_> {
|
|||
fn visit_provenance(&self, visit: &mut VisitWith<'_>) {
|
||||
let ThreadManager {
|
||||
threads,
|
||||
thread_local_alloc_ids,
|
||||
thread_local_allocs,
|
||||
active_thread: _,
|
||||
yield_active_thread: _,
|
||||
} = self;
|
||||
|
|
@ -451,7 +450,7 @@ impl VisitProvenance for ThreadManager<'_> {
|
|||
for thread in threads {
|
||||
thread.visit_provenance(visit);
|
||||
}
|
||||
for ptr in thread_local_alloc_ids.values() {
|
||||
for ptr in thread_local_allocs.values() {
|
||||
ptr.visit_provenance(visit);
|
||||
}
|
||||
}
|
||||
|
|
@ -465,7 +464,7 @@ impl<'tcx> Default for ThreadManager<'tcx> {
|
|||
Self {
|
||||
active_thread: ThreadId::MAIN_THREAD,
|
||||
threads,
|
||||
thread_local_alloc_ids: Default::default(),
|
||||
thread_local_allocs: Default::default(),
|
||||
yield_active_thread: false,
|
||||
}
|
||||
}
|
||||
|
|
@ -487,16 +486,16 @@ impl<'tcx> ThreadManager<'tcx> {
|
|||
|
||||
/// Check if we have an allocation for the given thread local static for the
|
||||
/// active thread.
|
||||
fn get_thread_local_alloc_id(&self, def_id: DefId) -> Option<Pointer<Provenance>> {
|
||||
self.thread_local_alloc_ids.get(&(def_id, self.active_thread)).cloned()
|
||||
fn get_thread_local_alloc_id(&self, def_id: DefId) -> Option<StrictPointer> {
|
||||
self.thread_local_allocs.get(&(def_id, self.active_thread)).cloned()
|
||||
}
|
||||
|
||||
/// Set the pointer for the allocation of the given thread local
|
||||
/// static for the active thread.
|
||||
///
|
||||
/// Panics if a thread local is initialized twice for the same thread.
|
||||
fn set_thread_local_alloc(&mut self, def_id: DefId, ptr: Pointer<Provenance>) {
|
||||
self.thread_local_alloc_ids.try_insert((def_id, self.active_thread), ptr).unwrap();
|
||||
fn set_thread_local_alloc(&mut self, def_id: DefId, ptr: StrictPointer) {
|
||||
self.thread_local_allocs.try_insert((def_id, self.active_thread), ptr).unwrap();
|
||||
}
|
||||
|
||||
/// Borrow the stack of the active thread.
|
||||
|
|
@ -848,7 +847,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
fn get_or_create_thread_local_alloc(
|
||||
&mut self,
|
||||
def_id: DefId,
|
||||
) -> InterpResult<'tcx, Pointer<Provenance>> {
|
||||
) -> InterpResult<'tcx, StrictPointer> {
|
||||
let this = self.eval_context_mut();
|
||||
let tcx = this.tcx;
|
||||
if let Some(old_alloc) = this.machine.threads.get_thread_local_alloc_id(def_id) {
|
||||
|
|
@ -878,7 +877,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
fn start_regular_thread(
|
||||
&mut self,
|
||||
thread: Option<MPlaceTy<'tcx>>,
|
||||
start_routine: Pointer<Option<Provenance>>,
|
||||
start_routine: Pointer,
|
||||
start_abi: Abi,
|
||||
func_arg: ImmTy<'tcx>,
|
||||
ret_layout: TyAndLayout<'tcx>,
|
||||
|
|
@ -947,18 +946,16 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
let gone_thread = this.active_thread();
|
||||
{
|
||||
let mut free_tls_statics = Vec::new();
|
||||
this.machine.threads.thread_local_alloc_ids.retain(
|
||||
|&(_def_id, thread), &mut alloc_id| {
|
||||
if thread != gone_thread {
|
||||
// A different thread, keep this static around.
|
||||
return true;
|
||||
}
|
||||
// Delete this static from the map and from memory.
|
||||
// We cannot free directly here as we cannot use `?` in this context.
|
||||
free_tls_statics.push(alloc_id);
|
||||
false
|
||||
},
|
||||
);
|
||||
this.machine.threads.thread_local_allocs.retain(|&(_def_id, thread), &mut alloc_id| {
|
||||
if thread != gone_thread {
|
||||
// A different thread, keep this static around.
|
||||
return true;
|
||||
}
|
||||
// Delete this static from the map and from memory.
|
||||
// We cannot free directly here as we cannot use `?` in this context.
|
||||
free_tls_statics.push(alloc_id);
|
||||
false
|
||||
});
|
||||
// Now free the TLS statics.
|
||||
for ptr in free_tls_statics {
|
||||
match tls_alloc_action {
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ pub enum TerminationInfo {
|
|||
},
|
||||
DataRace {
|
||||
involves_non_atomic: bool,
|
||||
ptr: Pointer<AllocId>,
|
||||
ptr: interpret::Pointer<AllocId>,
|
||||
op1: RacingOp,
|
||||
op2: RacingOp,
|
||||
extra: Option<&'static str>,
|
||||
|
|
@ -128,7 +128,7 @@ pub enum NonHaltingDiagnostic {
|
|||
details: bool,
|
||||
},
|
||||
WeakMemoryOutdatedLoad {
|
||||
ptr: Pointer<Option<Provenance>>,
|
||||
ptr: Pointer,
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -413,12 +413,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
}
|
||||
|
||||
/// Test if this pointer equals 0.
|
||||
fn ptr_is_null(&self, ptr: Pointer<Option<Provenance>>) -> InterpResult<'tcx, bool> {
|
||||
fn ptr_is_null(&self, ptr: Pointer) -> InterpResult<'tcx, bool> {
|
||||
Ok(ptr.addr().bytes() == 0)
|
||||
}
|
||||
|
||||
/// Generate some random bytes, and write them to `dest`.
|
||||
fn gen_random(&mut self, ptr: Pointer<Option<Provenance>>, len: u64) -> InterpResult<'tcx> {
|
||||
fn gen_random(&mut self, ptr: Pointer, len: u64) -> InterpResult<'tcx> {
|
||||
// Some programs pass in a null pointer and a length of 0
|
||||
// to their platform's random-generation function (e.g. getrandom())
|
||||
// on Linux. For compatibility with these programs, we don't perform
|
||||
|
|
@ -520,8 +520,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
let mut cur_addr = start_addr;
|
||||
// Called when we detected an `UnsafeCell` at the given offset and size.
|
||||
// Calls `action` and advances `cur_ptr`.
|
||||
let mut unsafe_cell_action = |unsafe_cell_ptr: &Pointer<Option<Provenance>>,
|
||||
unsafe_cell_size: Size| {
|
||||
let mut unsafe_cell_action = |unsafe_cell_ptr: &Pointer, unsafe_cell_size: Size| {
|
||||
// We assume that we are given the fields in increasing offset order,
|
||||
// and nothing else changes.
|
||||
let unsafe_cell_addr = unsafe_cell_ptr.addr();
|
||||
|
|
@ -924,7 +923,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
}
|
||||
|
||||
/// Read a sequence of bytes until the first null terminator.
|
||||
fn read_c_str<'a>(&'a self, ptr: Pointer<Option<Provenance>>) -> InterpResult<'tcx, &'a [u8]>
|
||||
fn read_c_str<'a>(&'a self, ptr: Pointer) -> InterpResult<'tcx, &'a [u8]>
|
||||
where
|
||||
'tcx: 'a,
|
||||
{
|
||||
|
|
@ -957,7 +956,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
fn write_c_str(
|
||||
&mut self,
|
||||
c_str: &[u8],
|
||||
ptr: Pointer<Option<Provenance>>,
|
||||
ptr: Pointer,
|
||||
size: u64,
|
||||
) -> InterpResult<'tcx, (bool, u64)> {
|
||||
// If `size` is smaller or equal than `bytes.len()`, writing `bytes` plus the required null
|
||||
|
|
@ -976,7 +975,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
/// until the first null terminator.
|
||||
fn read_c_str_with_char_size<T>(
|
||||
&self,
|
||||
mut ptr: Pointer<Option<Provenance>>,
|
||||
mut ptr: Pointer,
|
||||
size: Size,
|
||||
align: Align,
|
||||
) -> InterpResult<'tcx, Vec<T>>
|
||||
|
|
@ -1008,7 +1007,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
}
|
||||
|
||||
/// Read a sequence of u16 until the first null terminator.
|
||||
fn read_wide_str(&self, ptr: Pointer<Option<Provenance>>) -> InterpResult<'tcx, Vec<u16>> {
|
||||
fn read_wide_str(&self, ptr: Pointer) -> InterpResult<'tcx, Vec<u16>> {
|
||||
self.read_c_str_with_char_size(ptr, Size::from_bytes(2), Align::from_bytes(2).unwrap())
|
||||
}
|
||||
|
||||
|
|
@ -1021,7 +1020,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
fn write_wide_str(
|
||||
&mut self,
|
||||
wide_str: &[u16],
|
||||
ptr: Pointer<Option<Provenance>>,
|
||||
ptr: Pointer,
|
||||
size: u64,
|
||||
) -> InterpResult<'tcx, (bool, u64)> {
|
||||
// If `size` is smaller or equal than `bytes.len()`, writing `bytes` plus the required
|
||||
|
|
@ -1046,7 +1045,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
|
||||
/// Read a sequence of wchar_t until the first null terminator.
|
||||
/// Always returns a `Vec<u32>` no matter the size of `wchar_t`.
|
||||
fn read_wchar_t_str(&self, ptr: Pointer<Option<Provenance>>) -> InterpResult<'tcx, Vec<u32>> {
|
||||
fn read_wchar_t_str(&self, ptr: Pointer) -> InterpResult<'tcx, Vec<u32>> {
|
||||
let this = self.eval_context_ref();
|
||||
let wchar_t = this.libc_ty_layout("wchar_t");
|
||||
self.read_c_str_with_char_size(ptr, wchar_t.size, wchar_t.align.abi)
|
||||
|
|
|
|||
|
|
@ -100,6 +100,8 @@ pub use rustc_const_eval::interpret::*;
|
|||
pub use rustc_const_eval::interpret::{self, AllocMap, Provenance as _};
|
||||
|
||||
// Type aliases that set the provenance parameter.
|
||||
pub type Pointer = interpret::Pointer<Option<machine::Provenance>>;
|
||||
pub type StrictPointer = interpret::Pointer<machine::Provenance>;
|
||||
pub type Scalar = interpret::Scalar<machine::Provenance>;
|
||||
pub type ImmTy<'tcx> = interpret::ImmTy<'tcx, machine::Provenance>;
|
||||
pub type OpTy<'tcx> = interpret::OpTy<'tcx, machine::Provenance>;
|
||||
|
|
|
|||
|
|
@ -241,10 +241,10 @@ pub enum ProvenanceExtra {
|
|||
}
|
||||
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
static_assert_size!(Pointer<Provenance>, 24);
|
||||
static_assert_size!(StrictPointer, 24);
|
||||
// FIXME: this would with in 24bytes but layout optimizations are not smart enough
|
||||
// #[cfg(target_pointer_width = "64")]
|
||||
//static_assert_size!(Pointer<Option<Provenance>>, 24);
|
||||
//static_assert_size!(Pointer, 24);
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
static_assert_size!(Scalar, 32);
|
||||
|
||||
|
|
@ -270,7 +270,7 @@ impl fmt::Debug for Provenance {
|
|||
}
|
||||
|
||||
impl interpret::Provenance for Provenance {
|
||||
/// We use absolute addresses in the `offset` of a `Pointer<Provenance>`.
|
||||
/// We use absolute addresses in the `offset` of a `StrictPointer`.
|
||||
const OFFSET_IS_ADDR: bool = true;
|
||||
|
||||
fn get_alloc_id(self) -> Option<AllocId> {
|
||||
|
|
@ -280,7 +280,7 @@ impl interpret::Provenance for Provenance {
|
|||
}
|
||||
}
|
||||
|
||||
fn fmt(ptr: &Pointer<Self>, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fn fmt(ptr: &interpret::Pointer<Self>, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let (prov, addr) = ptr.into_parts(); // address is absolute
|
||||
write!(f, "{:#x}", addr.bytes())?;
|
||||
if f.alternate() {
|
||||
|
|
@ -447,9 +447,9 @@ pub struct MiriMachine<'tcx> {
|
|||
/// Program arguments (`Option` because we can only initialize them after creating the ecx).
|
||||
/// These are *pointers* to argc/argv because macOS.
|
||||
/// We also need the full command line as one string because of Windows.
|
||||
pub(crate) argc: Option<Pointer<Option<Provenance>>>,
|
||||
pub(crate) argv: Option<Pointer<Option<Provenance>>>,
|
||||
pub(crate) cmd_line: Option<Pointer<Option<Provenance>>>,
|
||||
pub(crate) argc: Option<Pointer>,
|
||||
pub(crate) argv: Option<Pointer>,
|
||||
pub(crate) cmd_line: Option<Pointer>,
|
||||
|
||||
/// TLS state.
|
||||
pub(crate) tls: TlsData<'tcx>,
|
||||
|
|
@ -504,7 +504,7 @@ pub struct MiriMachine<'tcx> {
|
|||
pub(crate) local_crates: Vec<CrateNum>,
|
||||
|
||||
/// Mapping extern static names to their pointer.
|
||||
extern_statics: FxHashMap<Symbol, Pointer<Provenance>>,
|
||||
extern_statics: FxHashMap<Symbol, StrictPointer>,
|
||||
|
||||
/// The random number generator used for resolving non-determinism.
|
||||
/// Needs to be queried by ptr_to_int, hence needs interior mutability.
|
||||
|
|
@ -716,11 +716,7 @@ impl<'tcx> MiriMachine<'tcx> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn add_extern_static(
|
||||
this: &mut MiriInterpCx<'tcx>,
|
||||
name: &str,
|
||||
ptr: Pointer<Option<Provenance>>,
|
||||
) {
|
||||
pub(crate) fn add_extern_static(this: &mut MiriInterpCx<'tcx>, name: &str, ptr: Pointer) {
|
||||
// This got just allocated, so there definitely is a pointer here.
|
||||
let ptr = ptr.into_pointer_or_addr().unwrap();
|
||||
this.machine.extern_statics.try_insert(Symbol::intern(name), ptr).unwrap();
|
||||
|
|
@ -1047,14 +1043,14 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
|
|||
fn thread_local_static_pointer(
|
||||
ecx: &mut MiriInterpCx<'tcx>,
|
||||
def_id: DefId,
|
||||
) -> InterpResult<'tcx, Pointer<Provenance>> {
|
||||
) -> InterpResult<'tcx, StrictPointer> {
|
||||
ecx.get_or_create_thread_local_alloc(def_id)
|
||||
}
|
||||
|
||||
fn extern_static_pointer(
|
||||
ecx: &MiriInterpCx<'tcx>,
|
||||
def_id: DefId,
|
||||
) -> InterpResult<'tcx, Pointer<Provenance>> {
|
||||
) -> InterpResult<'tcx, StrictPointer> {
|
||||
let link_name = ecx.item_link_name(def_id);
|
||||
if let Some(&ptr) = ecx.machine.extern_statics.get(&link_name) {
|
||||
// Various parts of the engine rely on `get_alloc_info` for size and alignment
|
||||
|
|
@ -1153,9 +1149,9 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
|
|||
|
||||
fn adjust_alloc_root_pointer(
|
||||
ecx: &MiriInterpCx<'tcx>,
|
||||
ptr: Pointer<CtfeProvenance>,
|
||||
ptr: interpret::Pointer<CtfeProvenance>,
|
||||
kind: Option<MemoryKind>,
|
||||
) -> InterpResult<'tcx, Pointer<Provenance>> {
|
||||
) -> InterpResult<'tcx, interpret::Pointer<Provenance>> {
|
||||
let kind = kind.expect("we set our GLOBAL_KIND so this cannot be None");
|
||||
let alloc_id = ptr.provenance.alloc_id();
|
||||
if cfg!(debug_assertions) {
|
||||
|
|
@ -1182,20 +1178,14 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
|
|||
|
||||
/// Called on `usize as ptr` casts.
|
||||
#[inline(always)]
|
||||
fn ptr_from_addr_cast(
|
||||
ecx: &MiriInterpCx<'tcx>,
|
||||
addr: u64,
|
||||
) -> InterpResult<'tcx, Pointer<Option<Self::Provenance>>> {
|
||||
fn ptr_from_addr_cast(ecx: &MiriInterpCx<'tcx>, addr: u64) -> InterpResult<'tcx, Pointer> {
|
||||
ecx.ptr_from_addr_cast(addr)
|
||||
}
|
||||
|
||||
/// Called on `ptr as usize` casts.
|
||||
/// (Actually computing the resulting `usize` doesn't need machine help,
|
||||
/// that's just `Scalar::try_to_int`.)
|
||||
fn expose_ptr(
|
||||
ecx: &mut InterpCx<'tcx, Self>,
|
||||
ptr: Pointer<Self::Provenance>,
|
||||
) -> InterpResult<'tcx> {
|
||||
fn expose_ptr(ecx: &mut InterpCx<'tcx, Self>, ptr: StrictPointer) -> InterpResult<'tcx> {
|
||||
match ptr.provenance {
|
||||
Provenance::Concrete { alloc_id, tag } => ecx.expose_ptr(alloc_id, tag),
|
||||
Provenance::Wildcard => {
|
||||
|
|
@ -1216,7 +1206,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
|
|||
/// stored in machine state).
|
||||
fn ptr_get_alloc(
|
||||
ecx: &MiriInterpCx<'tcx>,
|
||||
ptr: Pointer<Self::Provenance>,
|
||||
ptr: StrictPointer,
|
||||
) -> Option<(AllocId, Size, Self::ProvenanceExtra)> {
|
||||
let rel = ecx.ptr_get_alloc(ptr);
|
||||
|
||||
|
|
|
|||
|
|
@ -56,14 +56,14 @@ impl VisitProvenance for Provenance {
|
|||
}
|
||||
}
|
||||
|
||||
impl VisitProvenance for Pointer<Provenance> {
|
||||
impl VisitProvenance for StrictPointer {
|
||||
fn visit_provenance(&self, visit: &mut VisitWith<'_>) {
|
||||
let (prov, _offset) = self.into_parts();
|
||||
prov.visit_provenance(visit);
|
||||
}
|
||||
}
|
||||
|
||||
impl VisitProvenance for Pointer<Option<Provenance>> {
|
||||
impl VisitProvenance for Pointer {
|
||||
fn visit_provenance(&self, visit: &mut VisitWith<'_>) {
|
||||
let (prov, _offset) = self.into_parts();
|
||||
prov.visit_provenance(visit);
|
||||
|
|
|
|||
|
|
@ -92,11 +92,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn malloc(
|
||||
&mut self,
|
||||
size: u64,
|
||||
zero_init: bool,
|
||||
) -> InterpResult<'tcx, Pointer<Option<Provenance>>> {
|
||||
fn malloc(&mut self, size: u64, zero_init: bool) -> InterpResult<'tcx, Pointer> {
|
||||
let this = self.eval_context_mut();
|
||||
let align = this.malloc_align(size);
|
||||
let ptr = this.allocate_ptr(Size::from_bytes(size), align, MiriMemoryKind::C.into())?;
|
||||
|
|
@ -137,7 +133,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn free(&mut self, ptr: Pointer<Option<Provenance>>) -> InterpResult<'tcx> {
|
||||
fn free(&mut self, ptr: Pointer) -> InterpResult<'tcx> {
|
||||
let this = self.eval_context_mut();
|
||||
if !this.ptr_is_null(ptr)? {
|
||||
this.deallocate_ptr(ptr, None, MiriMemoryKind::C.into())?;
|
||||
|
|
@ -145,11 +141,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn realloc(
|
||||
&mut self,
|
||||
old_ptr: Pointer<Option<Provenance>>,
|
||||
new_size: u64,
|
||||
) -> InterpResult<'tcx, Pointer<Option<Provenance>>> {
|
||||
fn realloc(&mut self, old_ptr: Pointer, new_size: u64) -> InterpResult<'tcx, Pointer> {
|
||||
let this = self.eval_context_mut();
|
||||
let new_align = this.malloc_align(new_size);
|
||||
if this.ptr_is_null(old_ptr)? {
|
||||
|
|
@ -177,7 +169,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
&mut self,
|
||||
align: &OpTy<'tcx>,
|
||||
size: &OpTy<'tcx>,
|
||||
) -> InterpResult<'tcx, Pointer<Option<Provenance>>> {
|
||||
) -> InterpResult<'tcx, Pointer> {
|
||||
let this = self.eval_context_mut();
|
||||
let align = this.read_target_usize(align)?;
|
||||
let size = this.read_target_usize(size)?;
|
||||
|
|
|
|||
|
|
@ -34,10 +34,7 @@ impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
|
|||
pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
||||
/// Helper function to read an OsString from a null-terminated sequence of bytes, which is what
|
||||
/// the Unix APIs usually handle.
|
||||
fn read_os_str_from_c_str<'a>(
|
||||
&'a self,
|
||||
ptr: Pointer<Option<Provenance>>,
|
||||
) -> InterpResult<'tcx, &'a OsStr>
|
||||
fn read_os_str_from_c_str<'a>(&'a self, ptr: Pointer) -> InterpResult<'tcx, &'a OsStr>
|
||||
where
|
||||
'tcx: 'a,
|
||||
{
|
||||
|
|
@ -48,10 +45,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
|
||||
/// Helper function to read an OsString from a 0x0000-terminated sequence of u16,
|
||||
/// which is what the Windows APIs usually handle.
|
||||
fn read_os_str_from_wide_str<'a>(
|
||||
&'a self,
|
||||
ptr: Pointer<Option<Provenance>>,
|
||||
) -> InterpResult<'tcx, OsString>
|
||||
fn read_os_str_from_wide_str<'a>(&'a self, ptr: Pointer) -> InterpResult<'tcx, OsString>
|
||||
where
|
||||
'tcx: 'a,
|
||||
{
|
||||
|
|
@ -76,7 +70,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
fn write_os_str_to_c_str(
|
||||
&mut self,
|
||||
os_str: &OsStr,
|
||||
ptr: Pointer<Option<Provenance>>,
|
||||
ptr: Pointer,
|
||||
size: u64,
|
||||
) -> InterpResult<'tcx, (bool, u64)> {
|
||||
let bytes = os_str.as_encoded_bytes();
|
||||
|
|
@ -88,7 +82,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
fn write_os_str_to_wide_str_helper(
|
||||
&mut self,
|
||||
os_str: &OsStr,
|
||||
ptr: Pointer<Option<Provenance>>,
|
||||
ptr: Pointer,
|
||||
size: u64,
|
||||
truncate: bool,
|
||||
) -> InterpResult<'tcx, (bool, u64)> {
|
||||
|
|
@ -125,7 +119,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
fn write_os_str_to_wide_str(
|
||||
&mut self,
|
||||
os_str: &OsStr,
|
||||
ptr: Pointer<Option<Provenance>>,
|
||||
ptr: Pointer,
|
||||
size: u64,
|
||||
) -> InterpResult<'tcx, (bool, u64)> {
|
||||
self.write_os_str_to_wide_str_helper(os_str, ptr, size, /*truncate*/ false)
|
||||
|
|
@ -136,7 +130,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
fn write_os_str_to_wide_str_truncated(
|
||||
&mut self,
|
||||
os_str: &OsStr,
|
||||
ptr: Pointer<Option<Provenance>>,
|
||||
ptr: Pointer,
|
||||
size: u64,
|
||||
) -> InterpResult<'tcx, (bool, u64)> {
|
||||
self.write_os_str_to_wide_str_helper(os_str, ptr, size, /*truncate*/ true)
|
||||
|
|
@ -147,7 +141,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
&mut self,
|
||||
os_str: &OsStr,
|
||||
memkind: MemoryKind,
|
||||
) -> InterpResult<'tcx, Pointer<Option<Provenance>>> {
|
||||
) -> InterpResult<'tcx, Pointer> {
|
||||
let size = u64::try_from(os_str.len()).unwrap().checked_add(1).unwrap(); // Make space for `0` terminator.
|
||||
let this = self.eval_context_mut();
|
||||
|
||||
|
|
@ -163,7 +157,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
&mut self,
|
||||
os_str: &OsStr,
|
||||
memkind: MemoryKind,
|
||||
) -> InterpResult<'tcx, Pointer<Option<Provenance>>> {
|
||||
) -> InterpResult<'tcx, Pointer> {
|
||||
let size = u64::try_from(os_str.len()).unwrap().checked_add(1).unwrap(); // Make space for `0x0000` terminator.
|
||||
let this = self.eval_context_mut();
|
||||
|
||||
|
|
@ -175,10 +169,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
}
|
||||
|
||||
/// Read a null-terminated sequence of bytes, and perform path separator conversion if needed.
|
||||
fn read_path_from_c_str<'a>(
|
||||
&'a self,
|
||||
ptr: Pointer<Option<Provenance>>,
|
||||
) -> InterpResult<'tcx, Cow<'a, Path>>
|
||||
fn read_path_from_c_str<'a>(&'a self, ptr: Pointer) -> InterpResult<'tcx, Cow<'a, Path>>
|
||||
where
|
||||
'tcx: 'a,
|
||||
{
|
||||
|
|
@ -192,10 +183,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
}
|
||||
|
||||
/// Read a null-terminated sequence of `u16`s, and perform path separator conversion if needed.
|
||||
fn read_path_from_wide_str(
|
||||
&self,
|
||||
ptr: Pointer<Option<Provenance>>,
|
||||
) -> InterpResult<'tcx, PathBuf> {
|
||||
fn read_path_from_wide_str(&self, ptr: Pointer) -> InterpResult<'tcx, PathBuf> {
|
||||
let this = self.eval_context_ref();
|
||||
let os_str = this.read_os_str_from_wide_str(ptr)?;
|
||||
|
||||
|
|
@ -207,7 +195,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
fn write_path_to_c_str(
|
||||
&mut self,
|
||||
path: &Path,
|
||||
ptr: Pointer<Option<Provenance>>,
|
||||
ptr: Pointer,
|
||||
size: u64,
|
||||
) -> InterpResult<'tcx, (bool, u64)> {
|
||||
let this = self.eval_context_mut();
|
||||
|
|
@ -221,7 +209,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
fn write_path_to_wide_str(
|
||||
&mut self,
|
||||
path: &Path,
|
||||
ptr: Pointer<Option<Provenance>>,
|
||||
ptr: Pointer,
|
||||
size: u64,
|
||||
) -> InterpResult<'tcx, (bool, u64)> {
|
||||
let this = self.eval_context_mut();
|
||||
|
|
@ -235,7 +223,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
fn write_path_to_wide_str_truncated(
|
||||
&mut self,
|
||||
path: &Path,
|
||||
ptr: Pointer<Option<Provenance>>,
|
||||
ptr: Pointer,
|
||||
size: u64,
|
||||
) -> InterpResult<'tcx, (bool, u64)> {
|
||||
let this = self.eval_context_mut();
|
||||
|
|
@ -250,7 +238,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
&mut self,
|
||||
path: &Path,
|
||||
memkind: MemoryKind,
|
||||
) -> InterpResult<'tcx, Pointer<Option<Provenance>>> {
|
||||
) -> InterpResult<'tcx, Pointer> {
|
||||
let this = self.eval_context_mut();
|
||||
let os_str =
|
||||
this.convert_path(Cow::Borrowed(path.as_os_str()), PathConversion::HostToTarget);
|
||||
|
|
@ -263,7 +251,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
&mut self,
|
||||
path: &Path,
|
||||
memkind: MemoryKind,
|
||||
) -> InterpResult<'tcx, Pointer<Option<Provenance>>> {
|
||||
) -> InterpResult<'tcx, Pointer> {
|
||||
let this = self.eval_context_mut();
|
||||
let os_str =
|
||||
this.convert_path(Cow::Borrowed(path.as_os_str()), PathConversion::HostToTarget);
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ use helpers::check_arg_count;
|
|||
#[derive(Debug)]
|
||||
pub struct CatchUnwindData<'tcx> {
|
||||
/// The `catch_fn` callback to call in case of a panic.
|
||||
catch_fn: Pointer<Option<Provenance>>,
|
||||
catch_fn: Pointer,
|
||||
/// The `data` argument for that callback.
|
||||
data: Scalar,
|
||||
/// The return place from the original call to `try`.
|
||||
|
|
|
|||
|
|
@ -125,7 +125,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
&mut self,
|
||||
timep: &OpTy<'tcx>,
|
||||
result_op: &OpTy<'tcx>,
|
||||
) -> InterpResult<'tcx, Pointer<Option<Provenance>>> {
|
||||
) -> InterpResult<'tcx, Pointer> {
|
||||
let this = self.eval_context_mut();
|
||||
|
||||
this.assert_target_os_is_unix("localtime_r");
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ use crate::*;
|
|||
pub struct UnixEnvVars<'tcx> {
|
||||
/// Stores pointers to the environment variables. These variables must be stored as
|
||||
/// null-terminated target strings (c_str or wide_str) with the `"{name}={value}"` format.
|
||||
map: FxHashMap<OsString, Pointer<Option<Provenance>>>,
|
||||
map: FxHashMap<OsString, Pointer>,
|
||||
|
||||
/// Place where the `environ` static is stored. Lazily initialized, but then never changes.
|
||||
environ: MPlaceTy<'tcx>,
|
||||
|
|
@ -65,7 +65,7 @@ impl<'tcx> UnixEnvVars<'tcx> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn environ(&self) -> Pointer<Option<Provenance>> {
|
||||
pub(crate) fn environ(&self) -> Pointer {
|
||||
self.environ.ptr()
|
||||
}
|
||||
|
||||
|
|
@ -73,7 +73,7 @@ impl<'tcx> UnixEnvVars<'tcx> {
|
|||
&self,
|
||||
ecx: &InterpCx<'tcx, MiriMachine<'tcx>>,
|
||||
name: &OsStr,
|
||||
) -> InterpResult<'tcx, Option<Pointer<Option<Provenance>>>> {
|
||||
) -> InterpResult<'tcx, Option<Pointer>> {
|
||||
// We don't care about the value as we have the `map` to keep track of everything,
|
||||
// but we do want to do this read so it shows up as a data race.
|
||||
let _vars_ptr = ecx.read_pointer(&self.environ)?;
|
||||
|
|
@ -109,7 +109,7 @@ fn alloc_env_var<'tcx>(
|
|||
ecx: &mut InterpCx<'tcx, MiriMachine<'tcx>>,
|
||||
name: &OsStr,
|
||||
value: &OsStr,
|
||||
) -> InterpResult<'tcx, Pointer<Option<Provenance>>> {
|
||||
) -> InterpResult<'tcx, Pointer> {
|
||||
let mut name_osstring = name.to_os_string();
|
||||
name_osstring.push("=");
|
||||
name_osstring.push(value);
|
||||
|
|
@ -119,8 +119,8 @@ fn alloc_env_var<'tcx>(
|
|||
/// Allocates an `environ` block with the given list of pointers.
|
||||
fn alloc_environ_block<'tcx>(
|
||||
ecx: &mut InterpCx<'tcx, MiriMachine<'tcx>>,
|
||||
mut vars: Vec<Pointer<Option<Provenance>>>,
|
||||
) -> InterpResult<'tcx, Pointer<Option<Provenance>>> {
|
||||
mut vars: Vec<Pointer>,
|
||||
) -> InterpResult<'tcx, Pointer> {
|
||||
// Add trailing null.
|
||||
vars.push(Pointer::null());
|
||||
// Make an array with all these pointers inside Miri.
|
||||
|
|
@ -139,7 +139,7 @@ fn alloc_environ_block<'tcx>(
|
|||
|
||||
impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
|
||||
pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
||||
fn getenv(&mut self, name_op: &OpTy<'tcx>) -> InterpResult<'tcx, Pointer<Option<Provenance>>> {
|
||||
fn getenv(&mut self, name_op: &OpTy<'tcx>) -> InterpResult<'tcx, Pointer> {
|
||||
let this = self.eval_context_mut();
|
||||
this.assert_target_os_is_unix("getenv");
|
||||
|
||||
|
|
@ -206,11 +206,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn getcwd(
|
||||
&mut self,
|
||||
buf_op: &OpTy<'tcx>,
|
||||
size_op: &OpTy<'tcx>,
|
||||
) -> InterpResult<'tcx, Pointer<Option<Provenance>>> {
|
||||
fn getcwd(&mut self, buf_op: &OpTy<'tcx>, size_op: &OpTy<'tcx>) -> InterpResult<'tcx, Pointer> {
|
||||
let this = self.eval_context_mut();
|
||||
this.assert_target_os_is_unix("getcwd");
|
||||
|
||||
|
|
|
|||
|
|
@ -355,12 +355,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
Ok((-1).into())
|
||||
}
|
||||
|
||||
fn read(
|
||||
&mut self,
|
||||
fd: i32,
|
||||
buf: Pointer<Option<Provenance>>,
|
||||
count: u64,
|
||||
) -> InterpResult<'tcx, i64> {
|
||||
fn read(&mut self, fd: i32, buf: Pointer, count: u64) -> InterpResult<'tcx, i64> {
|
||||
let this = self.eval_context_mut();
|
||||
|
||||
// Isolation check is done via `FileDescriptor` trait.
|
||||
|
|
@ -409,12 +404,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn write(
|
||||
&mut self,
|
||||
fd: i32,
|
||||
buf: Pointer<Option<Provenance>>,
|
||||
count: u64,
|
||||
) -> InterpResult<'tcx, i64> {
|
||||
fn write(&mut self, fd: i32, buf: Pointer, count: u64) -> InterpResult<'tcx, i64> {
|
||||
let this = self.eval_context_mut();
|
||||
|
||||
// Isolation check is done via `FileDescriptor` trait.
|
||||
|
|
|
|||
|
|
@ -180,7 +180,7 @@ struct OpenDir {
|
|||
read_dir: ReadDir,
|
||||
/// The most recent entry returned by readdir().
|
||||
/// Will be freed by the next call.
|
||||
entry: Option<Pointer<Option<Provenance>>>,
|
||||
entry: Option<Pointer>,
|
||||
}
|
||||
|
||||
impl OpenDir {
|
||||
|
|
@ -900,7 +900,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
dirent64_layout.align.abi,
|
||||
MiriMemoryKind::Runtime.into(),
|
||||
)?;
|
||||
let entry: Pointer<Option<Provenance>> = entry.into();
|
||||
let entry: Pointer = entry.into();
|
||||
|
||||
// If the host is a Unix system, fill in the inode number with its real value.
|
||||
// If not, use 0 as a fallback value.
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
|
|||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
fn GetEnvironmentStringsW(&mut self) -> InterpResult<'tcx, Pointer<Option<Provenance>>> {
|
||||
fn GetEnvironmentStringsW(&mut self) -> InterpResult<'tcx, Pointer> {
|
||||
let this = self.eval_context_mut();
|
||||
this.assert_target_os("windows", "GetEnvironmentStringsW");
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue