From 9de605b32f830ece9abaf3476bba418ab3b3d213 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 11 Dec 2018 14:16:58 +0100 Subject: [PATCH 1/3] avoid repeating signatures in EvalContext extension traits --- src/fn_call.rs | 337 +++++++++++++++++++---------------------- src/helpers.rs | 45 +++--- src/intrinsic.rs | 239 ++++++++++++++--------------- src/lib.rs | 15 ++ src/stacked_borrows.rs | 100 ++++-------- src/tls.rs | 28 ++-- 6 files changed, 352 insertions(+), 412 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index e28497aa25..ea913417a5 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -6,29 +6,8 @@ use syntax::attr; use crate::*; -pub trait EvalContextExt<'tcx, 'mir> { - /// Emulate calling a foreign item, fail if the item is not supported. - /// This function will handle `goto_block` if needed. - fn emulate_foreign_item( - &mut self, - def_id: DefId, - args: &[OpTy<'tcx, Borrow>], - dest: PlaceTy<'tcx, Borrow>, - ret: mir::BasicBlock, - ) -> EvalResult<'tcx>; - - fn find_fn( - &mut self, - instance: ty::Instance<'tcx>, - args: &[OpTy<'tcx, Borrow>], - dest: Option>, - ret: Option, - ) -> EvalResult<'tcx, Option<&'mir mir::Mir<'tcx>>>; - - fn write_null(&mut self, dest: PlaceTy<'tcx, Borrow>) -> EvalResult<'tcx>; -} - -impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalContext<'a, 'mir, 'tcx> { +impl<'a, 'mir, 'tcx> EvalContextExt<'a, 'mir, 'tcx> for crate::MiriEvalContext<'a, 'mir, 'tcx> {} +pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, 'mir, 'tcx> { fn find_fn( &mut self, instance: ty::Instance<'tcx>, @@ -36,30 +15,31 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo dest: Option>, ret: Option, ) -> EvalResult<'tcx, Option<&'mir mir::Mir<'tcx>>> { + let this = self.eval_context_mut(); trace!("eval_fn_call: {:#?}, {:?}", instance, dest.map(|place| *place)); // first run the common hooks also supported by CTFE - if self.hook_fn(instance, args, dest)? { - self.goto_block(ret)?; + if this.hook_fn(instance, args, dest)? { + this.goto_block(ret)?; return Ok(None); } // there are some more lang items we want to hook that CTFE does not hook (yet) - if self.tcx.lang_items().align_offset_fn() == Some(instance.def.def_id()) { + if this.tcx.lang_items().align_offset_fn() == Some(instance.def.def_id()) { // FIXME: return a real value in case the target allocation has an // alignment bigger than the one requested let n = u128::max_value(); let dest = dest.unwrap(); - let n = self.truncate(n, dest.layout); - self.write_scalar(Scalar::from_uint(n, dest.layout.size), dest)?; - self.goto_block(ret)?; + let n = this.truncate(n, dest.layout); + this.write_scalar(Scalar::from_uint(n, dest.layout.size), dest)?; + this.goto_block(ret)?; return Ok(None); } // Try to see if we can do something about foreign items - if self.tcx.is_foreign_item(instance.def_id()) { + if this.tcx.is_foreign_item(instance.def_id()) { // An external function that we cannot find MIR for, but we can still run enough // of them to make miri viable. - self.emulate_foreign_item( + this.emulate_foreign_item( instance.def_id(), args, dest.unwrap(), @@ -70,9 +50,11 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo } // Otherwise, load the MIR - Ok(Some(self.load_mir(instance.def)?)) + Ok(Some(this.load_mir(instance.def)?)) } + /// Emulate calling a foreign item, fail if the item is not supported. + /// This function will handle `goto_block` if needed. fn emulate_foreign_item( &mut self, def_id: DefId, @@ -80,15 +62,16 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo dest: PlaceTy<'tcx, Borrow>, ret: mir::BasicBlock, ) -> EvalResult<'tcx> { - let attrs = self.tcx.get_attrs(def_id); + let this = self.eval_context_mut(); + let attrs = this.tcx.get_attrs(def_id); let link_name = match attr::first_attr_value_str_by_name(&attrs, "link_name") { Some(name) => name.as_str(), - None => self.tcx.item_name(def_id).as_str(), + None => this.tcx.item_name(def_id).as_str(), }; // Strip linker suffixes (seen on 32bit macOS) let link_name = link_name.trim_end_matches("$UNIX2003"); - let tcx = &{self.tcx.tcx}; + let tcx = &{this.tcx.tcx}; // All these functions take raw pointers, so if we access memory directly // (as opposed to through a place), we have to remember to erase any tag @@ -96,20 +79,20 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo match &link_name[..] { "malloc" => { - let size = self.read_scalar(args[0])?.to_usize(self)?; + let size = this.read_scalar(args[0])?.to_usize(this)?; if size == 0 { - self.write_null(dest)?; + this.write_null(dest)?; } else { - let align = self.tcx.data_layout.pointer_align.abi; - let ptr = self.memory_mut().allocate(Size::from_bytes(size), align, MiriMemoryKind::C.into())?; - self.write_scalar(Scalar::Ptr(ptr.with_default_tag()), dest)?; + let align = this.tcx.data_layout.pointer_align.abi; + let ptr = this.memory_mut().allocate(Size::from_bytes(size), align, MiriMemoryKind::C.into())?; + this.write_scalar(Scalar::Ptr(ptr.with_default_tag()), dest)?; } } "free" => { - let ptr = self.read_scalar(args[0])?.not_undef()?; - if !ptr.is_null_ptr(self) { - self.memory_mut().deallocate( + let ptr = this.read_scalar(args[0])?.not_undef()?; + if !ptr.is_null_ptr(this) { + this.memory_mut().deallocate( ptr.to_ptr()?, None, MiriMemoryKind::C.into(), @@ -118,72 +101,72 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo } "__rust_alloc" => { - let size = self.read_scalar(args[0])?.to_usize(self)?; - let align = self.read_scalar(args[1])?.to_usize(self)?; + let size = this.read_scalar(args[0])?.to_usize(this)?; + let align = this.read_scalar(args[1])?.to_usize(this)?; if size == 0 { return err!(HeapAllocZeroBytes); } if !align.is_power_of_two() { return err!(HeapAllocNonPowerOfTwoAlignment(align)); } - let ptr = self.memory_mut() + let ptr = this.memory_mut() .allocate( Size::from_bytes(size), Align::from_bytes(align).unwrap(), MiriMemoryKind::Rust.into() )? .with_default_tag(); - self.write_scalar(Scalar::Ptr(ptr), dest)?; + this.write_scalar(Scalar::Ptr(ptr), dest)?; } "__rust_alloc_zeroed" => { - let size = self.read_scalar(args[0])?.to_usize(self)?; - let align = self.read_scalar(args[1])?.to_usize(self)?; + let size = this.read_scalar(args[0])?.to_usize(this)?; + let align = this.read_scalar(args[1])?.to_usize(this)?; if size == 0 { return err!(HeapAllocZeroBytes); } if !align.is_power_of_two() { return err!(HeapAllocNonPowerOfTwoAlignment(align)); } - let ptr = self.memory_mut() + let ptr = this.memory_mut() .allocate( Size::from_bytes(size), Align::from_bytes(align).unwrap(), MiriMemoryKind::Rust.into() )? .with_default_tag(); - self.memory_mut() + this.memory_mut() .get_mut(ptr.alloc_id)? .write_repeat(tcx, ptr, 0, Size::from_bytes(size))?; - self.write_scalar(Scalar::Ptr(ptr), dest)?; + this.write_scalar(Scalar::Ptr(ptr), dest)?; } "__rust_dealloc" => { - let ptr = self.read_scalar(args[0])?.to_ptr()?; - let old_size = self.read_scalar(args[1])?.to_usize(self)?; - let align = self.read_scalar(args[2])?.to_usize(self)?; + let ptr = this.read_scalar(args[0])?.to_ptr()?; + let old_size = this.read_scalar(args[1])?.to_usize(this)?; + let align = this.read_scalar(args[2])?.to_usize(this)?; if old_size == 0 { return err!(HeapAllocZeroBytes); } if !align.is_power_of_two() { return err!(HeapAllocNonPowerOfTwoAlignment(align)); } - self.memory_mut().deallocate( + this.memory_mut().deallocate( ptr, Some((Size::from_bytes(old_size), Align::from_bytes(align).unwrap())), MiriMemoryKind::Rust.into(), )?; } "__rust_realloc" => { - let ptr = self.read_scalar(args[0])?.to_ptr()?; - let old_size = self.read_scalar(args[1])?.to_usize(self)?; - let align = self.read_scalar(args[2])?.to_usize(self)?; - let new_size = self.read_scalar(args[3])?.to_usize(self)?; + let ptr = this.read_scalar(args[0])?.to_ptr()?; + let old_size = this.read_scalar(args[1])?.to_usize(this)?; + let align = this.read_scalar(args[2])?.to_usize(this)?; + let new_size = this.read_scalar(args[3])?.to_usize(this)?; if old_size == 0 || new_size == 0 { return err!(HeapAllocZeroBytes); } if !align.is_power_of_two() { return err!(HeapAllocNonPowerOfTwoAlignment(align)); } - let new_ptr = self.memory_mut().reallocate( + let new_ptr = this.memory_mut().reallocate( ptr, Size::from_bytes(old_size), Align::from_bytes(align).unwrap(), @@ -191,7 +174,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo Align::from_bytes(align).unwrap(), MiriMemoryKind::Rust.into(), )?; - self.write_scalar(Scalar::Ptr(new_ptr.with_default_tag()), dest)?; + this.write_scalar(Scalar::Ptr(new_ptr.with_default_tag()), dest)?; } "syscall" => { @@ -200,7 +183,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo // // libc::syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), GRND_NONBLOCK) // is called if a `HashMap` is created the regular way. - match self.read_scalar(args[0])?.to_usize(self)? { + match this.read_scalar(args[0])?.to_usize(this)? { 318 | 511 => { return err!(Unimplemented( "miri does not support random number generators".to_owned(), @@ -215,9 +198,9 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo } "dlsym" => { - let _handle = self.read_scalar(args[0])?; - let symbol = self.read_scalar(args[1])?.to_ptr()?; - let symbol_name = self.memory().get(symbol.alloc_id)?.read_c_str(tcx, symbol)?; + let _handle = this.read_scalar(args[0])?; + let symbol = this.read_scalar(args[1])?.to_ptr()?; + let symbol_name = this.memory().get(symbol.alloc_id)?.read_c_str(tcx, symbol)?; let err = format!("bad c unicode symbol: {:?}", symbol_name); let symbol_name = ::std::str::from_utf8(symbol_name).unwrap_or(&err); return err!(Unimplemented(format!( @@ -229,24 +212,24 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo "__rust_maybe_catch_panic" => { // fn __rust_maybe_catch_panic(f: fn(*mut u8), data: *mut u8, data_ptr: *mut usize, vtable_ptr: *mut usize) -> u32 // We abort on panic, so not much is going on here, but we still have to call the closure - let f = self.read_scalar(args[0])?.to_ptr()?; - let data = self.read_scalar(args[1])?.not_undef()?; - let f_instance = self.memory().get_fn(f)?; - self.write_null(dest)?; + let f = this.read_scalar(args[0])?.to_ptr()?; + let data = this.read_scalar(args[1])?.not_undef()?; + let f_instance = this.memory().get_fn(f)?; + this.write_null(dest)?; trace!("__rust_maybe_catch_panic: {:?}", f_instance); // Now we make a function call. TODO: Consider making this re-usable? EvalContext::step does sth. similar for the TLS dtors, // and of course eval_main. - let mir = self.load_mir(f_instance.def)?; - let ret_place = MPlaceTy::dangling(self.layout_of(self.tcx.mk_unit())?, self).into(); - self.push_stack_frame( + let mir = this.load_mir(f_instance.def)?; + let ret_place = MPlaceTy::dangling(this.layout_of(this.tcx.mk_unit())?, this).into(); + this.push_stack_frame( f_instance, mir.span, mir, Some(ret_place), StackPopCleanup::Goto(Some(ret)), // directly return to caller )?; - let mut args = self.frame().mir.args_iter(); + let mut args = this.frame().mir.args_iter(); let arg_local = args.next().ok_or_else(|| EvalErrorKind::AbiViolation( @@ -254,13 +237,13 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo .to_owned(), ), )?; - let arg_dest = self.eval_place(&mir::Place::Local(arg_local))?; - self.write_scalar(data, arg_dest)?; + let arg_dest = this.eval_place(&mir::Place::Local(arg_local))?; + this.write_scalar(data, arg_dest)?; assert!(args.next().is_none(), "__rust_maybe_catch_panic argument has more arguments than expected"); // We ourselves will return 0, eventually (because we will not return if we paniced) - self.write_null(dest)?; + this.write_null(dest)?; // Don't fall through, we do NOT want to `goto_block`! return Ok(()); @@ -270,13 +253,13 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo return err!(MachineError("the evaluated program panicked".to_string())), "memcmp" => { - let left = self.read_scalar(args[0])?.not_undef()?; - let right = self.read_scalar(args[1])?.not_undef()?; - let n = Size::from_bytes(self.read_scalar(args[2])?.to_usize(self)?); + let left = this.read_scalar(args[0])?.not_undef()?; + let right = this.read_scalar(args[1])?.not_undef()?; + let n = Size::from_bytes(this.read_scalar(args[2])?.to_usize(this)?); let result = { - let left_bytes = self.memory().read_bytes(left, n)?; - let right_bytes = self.memory().read_bytes(right, n)?; + let left_bytes = this.memory().read_bytes(left, n)?; + let right_bytes = this.memory().read_bytes(right, n)?; use std::cmp::Ordering::*; match left_bytes.cmp(right_bytes) { @@ -286,84 +269,84 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo } }; - self.write_scalar( + this.write_scalar( Scalar::from_int(result, Size::from_bits(32)), dest, )?; } "memrchr" => { - let ptr = self.read_scalar(args[0])?.not_undef()?; - let val = self.read_scalar(args[1])?.to_bytes()? as u8; - let num = self.read_scalar(args[2])?.to_usize(self)?; - if let Some(idx) = self.memory().read_bytes(ptr, Size::from_bytes(num))? + let ptr = this.read_scalar(args[0])?.not_undef()?; + let val = this.read_scalar(args[1])?.to_bytes()? as u8; + let num = this.read_scalar(args[2])?.to_usize(this)?; + if let Some(idx) = this.memory().read_bytes(ptr, Size::from_bytes(num))? .iter().rev().position(|&c| c == val) { - let new_ptr = ptr.ptr_offset(Size::from_bytes(num - idx as u64 - 1), self)?; - self.write_scalar(new_ptr, dest)?; + let new_ptr = ptr.ptr_offset(Size::from_bytes(num - idx as u64 - 1), this)?; + this.write_scalar(new_ptr, dest)?; } else { - self.write_null(dest)?; + this.write_null(dest)?; } } "memchr" => { - let ptr = self.read_scalar(args[0])?.not_undef()?; - let val = self.read_scalar(args[1])?.to_bytes()? as u8; - let num = self.read_scalar(args[2])?.to_usize(self)?; - if let Some(idx) = self.memory().read_bytes(ptr, Size::from_bytes(num))?.iter().position( + let ptr = this.read_scalar(args[0])?.not_undef()?; + let val = this.read_scalar(args[1])?.to_bytes()? as u8; + let num = this.read_scalar(args[2])?.to_usize(this)?; + if let Some(idx) = this.memory().read_bytes(ptr, Size::from_bytes(num))?.iter().position( |&c| c == val, ) { - let new_ptr = ptr.ptr_offset(Size::from_bytes(idx as u64), self)?; - self.write_scalar(new_ptr, dest)?; + let new_ptr = ptr.ptr_offset(Size::from_bytes(idx as u64), this)?; + this.write_scalar(new_ptr, dest)?; } else { - self.write_null(dest)?; + this.write_null(dest)?; } } "getenv" => { let result = { - let name_ptr = self.read_scalar(args[0])?.to_ptr()?; - let name = self.memory().get(name_ptr.alloc_id)?.read_c_str(tcx, name_ptr)?; - match self.machine.env_vars.get(name) { + let name_ptr = this.read_scalar(args[0])?.to_ptr()?; + let name = this.memory().get(name_ptr.alloc_id)?.read_c_str(tcx, name_ptr)?; + match this.machine.env_vars.get(name) { Some(&var) => Scalar::Ptr(var), - None => Scalar::ptr_null(&*self.tcx), + None => Scalar::ptr_null(&*this.tcx), } }; - self.write_scalar(result, dest)?; + this.write_scalar(result, dest)?; } "unsetenv" => { let mut success = None; { - let name_ptr = self.read_scalar(args[0])?.not_undef()?; - if !name_ptr.is_null_ptr(self) { + let name_ptr = this.read_scalar(args[0])?.not_undef()?; + if !name_ptr.is_null_ptr(this) { let name_ptr = name_ptr.to_ptr()?; - let name = self.memory().get(name_ptr.alloc_id)?.read_c_str(tcx, name_ptr)?.to_owned(); + let name = this.memory().get(name_ptr.alloc_id)?.read_c_str(tcx, name_ptr)?.to_owned(); if !name.is_empty() && !name.contains(&b'=') { - success = Some(self.machine.env_vars.remove(&name)); + success = Some(this.machine.env_vars.remove(&name)); } } } if let Some(old) = success { if let Some(var) = old { - self.memory_mut().deallocate(var, None, MiriMemoryKind::Env.into())?; + this.memory_mut().deallocate(var, None, MiriMemoryKind::Env.into())?; } - self.write_null(dest)?; + this.write_null(dest)?; } else { - self.write_scalar(Scalar::from_int(-1, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_int(-1, dest.layout.size), dest)?; } } "setenv" => { let mut new = None; { - let name_ptr = self.read_scalar(args[0])?.not_undef()?; - let value_ptr = self.read_scalar(args[1])?.to_ptr()?; - let value = self.memory().get(value_ptr.alloc_id)?.read_c_str(tcx, value_ptr)?; - if !name_ptr.is_null_ptr(self) { + let name_ptr = this.read_scalar(args[0])?.not_undef()?; + let value_ptr = this.read_scalar(args[1])?.to_ptr()?; + let value = this.memory().get(value_ptr.alloc_id)?.read_c_str(tcx, value_ptr)?; + if !name_ptr.is_null_ptr(this) { let name_ptr = name_ptr.to_ptr()?; - let name = self.memory().get(name_ptr.alloc_id)?.read_c_str(tcx, name_ptr)?; + let name = this.memory().get(name_ptr.alloc_id)?.read_c_str(tcx, name_ptr)?; if !name.is_empty() && !name.contains(&b'=') { new = Some((name.to_owned(), value.to_owned())); } @@ -371,40 +354,40 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo } if let Some((name, value)) = new { // +1 for the null terminator - let value_copy = self.memory_mut().allocate( + let value_copy = this.memory_mut().allocate( Size::from_bytes((value.len() + 1) as u64), Align::from_bytes(1).unwrap(), MiriMemoryKind::Env.into(), )?.with_default_tag(); { - let alloc = self.memory_mut().get_mut(value_copy.alloc_id)?; + let alloc = this.memory_mut().get_mut(value_copy.alloc_id)?; alloc.write_bytes(tcx, value_copy, &value)?; let trailing_zero_ptr = value_copy.offset(Size::from_bytes(value.len() as u64), tcx)?; alloc.write_bytes(tcx, trailing_zero_ptr, &[0])?; } - if let Some(var) = self.machine.env_vars.insert( + if let Some(var) = this.machine.env_vars.insert( name.to_owned(), value_copy, ) { - self.memory_mut().deallocate(var, None, MiriMemoryKind::Env.into())?; + this.memory_mut().deallocate(var, None, MiriMemoryKind::Env.into())?; } - self.write_null(dest)?; + this.write_null(dest)?; } else { - self.write_scalar(Scalar::from_int(-1, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_int(-1, dest.layout.size), dest)?; } } "write" => { - let fd = self.read_scalar(args[0])?.to_bytes()?; - let buf = self.read_scalar(args[1])?.not_undef()?; - let n = self.read_scalar(args[2])?.to_bytes()? as u64; + let fd = this.read_scalar(args[0])?.to_bytes()?; + let buf = this.read_scalar(args[1])?.not_undef()?; + let n = this.read_scalar(args[2])?.to_bytes()? as u64; trace!("Called write({:?}, {:?}, {:?})", fd, buf, n); let result = if fd == 1 || fd == 2 { // stdout/stderr use std::io::{self, Write}; - let buf_cont = self.memory().read_bytes(buf, Size::from_bytes(n))?; + let buf_cont = this.memory().read_bytes(buf, Size::from_bytes(n))?; let res = if fd == 1 { io::stdout().write(buf_cont) } else { @@ -418,25 +401,25 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo warn!("Ignored output to FD {}", fd); n as i64 // pretend it all went well }; // now result is the value we return back to the program - self.write_scalar( + this.write_scalar( Scalar::from_int(result, dest.layout.size), dest, )?; } "strlen" => { - let ptr = self.read_scalar(args[0])?.to_ptr()?; - let n = self.memory().get(ptr.alloc_id)?.read_c_str(tcx, ptr)?.len(); - self.write_scalar(Scalar::from_uint(n as u64, dest.layout.size), dest)?; + let ptr = this.read_scalar(args[0])?.to_ptr()?; + let n = this.memory().get(ptr.alloc_id)?.read_c_str(tcx, ptr)?.len(); + this.write_scalar(Scalar::from_uint(n as u64, dest.layout.size), dest)?; } // Some things needed for sys::thread initialization to go through "signal" | "sigaction" | "sigaltstack" => { - self.write_scalar(Scalar::from_int(0, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_int(0, dest.layout.size), dest)?; } "sysconf" => { - let name = self.read_scalar(args[0])?.to_i32()?; + let name = this.read_scalar(args[0])?.to_i32()?; trace!("sysconf() called with name {}", name); // cache the sysconf integers via miri's global cache @@ -446,13 +429,13 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo ]; let mut result = None; for &(path, path_value) in paths { - if let Ok(instance) = self.resolve_path(path) { + if let Ok(instance) = this.resolve_path(path) { let cid = GlobalId { instance, promoted: None, }; - let const_val = self.const_eval_raw(cid)?; - let const_val = self.read_scalar(const_val.into())?; + let const_val = this.const_eval_raw(cid)?; + let const_val = this.read_scalar(const_val.into())?; let value = const_val.to_i32()?; if value == name { result = Some(path_value); @@ -461,7 +444,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo } } if let Some(result) = result { - self.write_scalar(result, dest)?; + this.write_scalar(result, dest)?; } else { return err!(Unimplemented( format!("Unimplemented sysconf name: {}", name), @@ -471,13 +454,13 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo // Hook pthread calls that go to the thread-local storage memory subsystem "pthread_key_create" => { - let key_ptr = self.read_scalar(args[0])?.to_ptr()?; + let key_ptr = this.read_scalar(args[0])?.to_ptr()?; // Extract the function type out of the signature (that seems easier than constructing it ourselves...) - let dtor = match self.read_scalar(args[1])?.not_undef()? { - Scalar::Ptr(dtor_ptr) => Some(self.memory().get_fn(dtor_ptr)?), + let dtor = match this.read_scalar(args[1])?.not_undef()? { + Scalar::Ptr(dtor_ptr) => Some(this.memory().get_fn(dtor_ptr)?), Scalar::Bits { bits: 0, size } => { - assert_eq!(size as u64, self.memory().pointer_size().bytes()); + assert_eq!(size as u64, this.memory().pointer_size().bytes()); None }, Scalar::Bits { .. } => return err!(ReadBytesAsPointer), @@ -486,16 +469,16 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo // Figure out how large a pthread TLS key actually is. This is libc::pthread_key_t. let key_type = args[0].layout.ty.builtin_deref(true) .ok_or_else(|| EvalErrorKind::AbiViolation("Wrong signature used for pthread_key_create: First argument must be a raw pointer.".to_owned()))?.ty; - let key_layout = self.layout_of(key_type)?; + let key_layout = this.layout_of(key_type)?; // Create key and write it into the memory where key_ptr wants it - let key = self.machine.tls.create_tls_key(dtor, tcx) as u128; + let key = this.machine.tls.create_tls_key(dtor, tcx) as u128; if key_layout.size.bits() < 128 && key >= (1u128 << key_layout.size.bits() as u128) { return err!(OutOfTls); } - self.memory().check_align(key_ptr.into(), key_layout.align.abi)?; - self.memory_mut().get_mut(key_ptr.alloc_id)?.write_scalar( + this.memory().check_align(key_ptr.into(), key_layout.align.abi)?; + this.memory_mut().get_mut(key_ptr.alloc_id)?.write_scalar( tcx, key_ptr, Scalar::from_uint(key, key_layout.size).into(), @@ -503,26 +486,26 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo )?; // Return success (0) - self.write_null(dest)?; + this.write_null(dest)?; } "pthread_key_delete" => { - let key = self.read_scalar(args[0])?.to_bytes()?; - self.machine.tls.delete_tls_key(key)?; + let key = this.read_scalar(args[0])?.to_bytes()?; + this.machine.tls.delete_tls_key(key)?; // Return success (0) - self.write_null(dest)?; + this.write_null(dest)?; } "pthread_getspecific" => { - let key = self.read_scalar(args[0])?.to_bytes()?; - let ptr = self.machine.tls.load_tls(key)?; - self.write_scalar(ptr, dest)?; + let key = this.read_scalar(args[0])?.to_bytes()?; + let ptr = this.machine.tls.load_tls(key)?; + this.write_scalar(ptr, dest)?; } "pthread_setspecific" => { - let key = self.read_scalar(args[0])?.to_bytes()?; - let new_ptr = self.read_scalar(args[1])?.not_undef()?; - self.machine.tls.store_tls(key, new_ptr)?; + let key = this.read_scalar(args[0])?.to_bytes()?; + let new_ptr = this.read_scalar(args[1])?.not_undef()?; + this.machine.tls.store_tls(key, new_ptr)?; // Return success (0) - self.write_null(dest)?; + this.write_null(dest)?; } "_tlv_atexit" => { @@ -532,19 +515,19 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo // Determining stack base address "pthread_attr_init" | "pthread_attr_destroy" | "pthread_attr_get_np" | "pthread_getattr_np" | "pthread_self" | "pthread_get_stacksize_np" => { - self.write_null(dest)?; + this.write_null(dest)?; } "pthread_attr_getstack" => { // second argument is where we are supposed to write the stack size - let ptr = self.deref_operand(args[1])?; + let ptr = this.deref_operand(args[1])?; let stackaddr = Scalar::from_int(0x80000, args[1].layout.size); // just any address - self.write_scalar(stackaddr, ptr.into())?; + this.write_scalar(stackaddr, ptr.into())?; // return 0 - self.write_null(dest)?; + this.write_null(dest)?; } "pthread_get_stackaddr_np" => { let stackaddr = Scalar::from_int(0x80000, dest.layout.size); // just any address - self.write_scalar(stackaddr, dest)?; + this.write_scalar(stackaddr, dest)?; } // Stub out calls for condvar, mutex and rwlock to just return 0 @@ -554,22 +537,22 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo "pthread_rwlock_wrlock" | "pthread_rwlock_destroy" | "pthread_condattr_init" | "pthread_condattr_setclock" | "pthread_cond_init" | "pthread_condattr_destroy" | "pthread_cond_destroy" => { - self.write_null(dest)?; + this.write_null(dest)?; } "mmap" => { // This is a horrible hack, but well... the guard page mechanism calls mmap and expects a particular return value, so we give it that value - let addr = self.read_scalar(args[0])?.not_undef()?; - self.write_scalar(addr, dest)?; + let addr = this.read_scalar(args[0])?.not_undef()?; + this.write_scalar(addr, dest)?; } "mprotect" => { - self.write_null(dest)?; + this.write_null(dest)?; } // Windows API subs "AddVectoredExceptionHandler" => { // any non zero value works for the stdlib. This is just used for stackoverflows anyway - self.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?; }, "InitializeCriticalSection" | "EnterCriticalSection" | @@ -582,11 +565,11 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo "GetProcAddress" | "TryEnterCriticalSection" => { // pretend these do not exist/nothing happened, by returning zero - self.write_null(dest)?; + this.write_null(dest)?; }, "GetLastError" => { // this is c::ERROR_CALL_NOT_IMPLEMENTED - self.write_scalar(Scalar::from_int(120, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_int(120, dest.layout.size), dest)?; }, // Windows TLS @@ -594,26 +577,26 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo // This just creates a key; Windows does not natively support TLS dtors. // Create key and return it - let key = self.machine.tls.create_tls_key(None, tcx) as u128; + let key = this.machine.tls.create_tls_key(None, tcx) as u128; // Figure out how large a TLS key actually is. This is c::DWORD. if dest.layout.size.bits() < 128 && key >= (1u128 << dest.layout.size.bits() as u128) { return err!(OutOfTls); } - self.write_scalar(Scalar::from_uint(key, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_uint(key, dest.layout.size), dest)?; } "TlsGetValue" => { - let key = self.read_scalar(args[0])?.to_bytes()?; - let ptr = self.machine.tls.load_tls(key)?; - self.write_scalar(ptr, dest)?; + let key = this.read_scalar(args[0])?.to_bytes()?; + let ptr = this.machine.tls.load_tls(key)?; + this.write_scalar(ptr, dest)?; } "TlsSetValue" => { - let key = self.read_scalar(args[0])?.to_bytes()?; - let new_ptr = self.read_scalar(args[1])?.not_undef()?; - self.machine.tls.store_tls(key, new_ptr)?; + let key = this.read_scalar(args[0])?.to_bytes()?; + let new_ptr = this.read_scalar(args[1])?.not_undef()?; + this.machine.tls.store_tls(key, new_ptr)?; // Return success (1) - self.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?; } // We can't execute anything else @@ -624,12 +607,12 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo } } - self.goto_block(Some(ret))?; - self.dump_place(*dest); + this.goto_block(Some(ret))?; + this.dump_place(*dest); Ok(()) } fn write_null(&mut self, dest: PlaceTy<'tcx, Borrow>) -> EvalResult<'tcx> { - self.write_scalar(Scalar::from_int(0, dest.layout.size), dest) + self.eval_context_mut().write_scalar(Scalar::from_int(0, dest.layout.size), dest) } } diff --git a/src/helpers.rs b/src/helpers.rs index 2b1a28fe9e..7be1567605 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -30,43 +30,31 @@ impl ScalarExt for ScalarMaybeUndef { } } -pub trait EvalContextExt<'tcx> { - fn resolve_path(&self, path: &[&str]) -> EvalResult<'tcx, ty::Instance<'tcx>>; - - /// Visit the memory covered by `place`, sensitive to freezing: The 3rd parameter - /// will be true if this is frozen, false if this is in an `UnsafeCell`. - fn visit_freeze_sensitive( - &self, - place: MPlaceTy<'tcx, Borrow>, - size: Size, - action: impl FnMut(Pointer, Size, bool) -> EvalResult<'tcx>, - ) -> EvalResult<'tcx>; -} - - -impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super::Evaluator<'tcx>> { +impl<'a, 'mir, 'tcx> EvalContextExt<'a, 'mir, 'tcx> for crate::MiriEvalContext<'a, 'mir, 'tcx> {} +pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, 'mir, 'tcx> { /// Get an instance for a path. fn resolve_path(&self, path: &[&str]) -> EvalResult<'tcx, ty::Instance<'tcx>> { - self.tcx + let this = self.eval_context_ref(); + this.tcx .crates() .iter() - .find(|&&krate| self.tcx.original_crate_name(krate) == path[0]) + .find(|&&krate| this.tcx.original_crate_name(krate) == path[0]) .and_then(|krate| { let krate = DefId { krate: *krate, index: CRATE_DEF_INDEX, }; - let mut items = self.tcx.item_children(krate); + let mut items = this.tcx.item_children(krate); let mut path_it = path.iter().skip(1).peekable(); while let Some(segment) = path_it.next() { for item in mem::replace(&mut items, Default::default()).iter() { if item.ident.name == *segment { if path_it.peek().is_none() { - return Some(ty::Instance::mono(self.tcx.tcx, item.def.def_id())); + return Some(ty::Instance::mono(this.tcx.tcx, item.def.def_id())); } - items = self.tcx.item_children(item.def.def_id()); + items = this.tcx.item_children(item.def.def_id()); break; } } @@ -79,15 +67,18 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: }) } + /// Visit the memory covered by `place`, sensitive to freezing: The 3rd parameter + /// will be true if this is frozen, false if this is in an `UnsafeCell`. fn visit_freeze_sensitive( &self, place: MPlaceTy<'tcx, Borrow>, size: Size, mut action: impl FnMut(Pointer, Size, bool) -> EvalResult<'tcx>, ) -> EvalResult<'tcx> { + let this = self.eval_context_ref(); trace!("visit_frozen(place={:?}, size={:?})", *place, size); debug_assert_eq!(size, - self.size_and_align_of_mplace(place)? + this.size_and_align_of_mplace(place)? .map(|(size, _)| size) .unwrap_or_else(|| place.layout.size) ); @@ -106,8 +97,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: } // We assume that we are given the fields in increasing offset order, // and nothing else changes. - let unsafe_cell_offset = unsafe_cell_ptr.get_ptr_offset(self); - let end_offset = end_ptr.get_ptr_offset(self); + let unsafe_cell_offset = unsafe_cell_ptr.get_ptr_offset(this); + let end_offset = end_ptr.get_ptr_offset(this); assert!(unsafe_cell_offset >= end_offset); let frozen_size = unsafe_cell_offset - end_offset; // Everything between the end_ptr and this `UnsafeCell` is frozen. @@ -119,18 +110,18 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: action(unsafe_cell_ptr.to_ptr()?, unsafe_cell_size, /*frozen*/false)?; } // Update end end_ptr. - end_ptr = unsafe_cell_ptr.ptr_wrapping_offset(unsafe_cell_size, self); + end_ptr = unsafe_cell_ptr.ptr_wrapping_offset(unsafe_cell_size, this); // Done Ok(()) }; // Run a visitor { let mut visitor = UnsafeCellVisitor { - ecx: self, + ecx: this, unsafe_cell_action: |place| { trace!("unsafe_cell_action on {:?}", place.ptr); // We need a size to go on. - let unsafe_cell_size = self.size_and_align_of_mplace(place)? + let unsafe_cell_size = this.size_and_align_of_mplace(place)? .map(|(size, _)| size) // for extern types, just cover what we can .unwrap_or_else(|| place.layout.size); @@ -146,7 +137,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: } // The part between the end_ptr and the end of the place is also frozen. // So pretend there is a 0-sized `UnsafeCell` at the end. - unsafe_cell_action(place.ptr.ptr_wrapping_offset(size, self), Size::ZERO)?; + unsafe_cell_action(place.ptr.ptr_wrapping_offset(size, this), Size::ZERO)?; // Done! return Ok(()); diff --git a/src/intrinsic.rs b/src/intrinsic.rs index c9b16525e5..35182ba513 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -9,47 +9,40 @@ use crate::{ ScalarExt, OperatorEvalContextExt }; -pub trait EvalContextExt<'tcx> { - fn call_intrinsic( - &mut self, - instance: ty::Instance<'tcx>, - args: &[OpTy<'tcx, Borrow>], - dest: PlaceTy<'tcx, Borrow>, - ) -> EvalResult<'tcx>; -} - -impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, 'tcx> { +impl<'a, 'mir, 'tcx> EvalContextExt<'a, 'mir, 'tcx> for crate::MiriEvalContext<'a, 'mir, 'tcx> {} +pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, 'mir, 'tcx> { fn call_intrinsic( &mut self, instance: ty::Instance<'tcx>, args: &[OpTy<'tcx, Borrow>], dest: PlaceTy<'tcx, Borrow>, ) -> EvalResult<'tcx> { - if self.emulate_intrinsic(instance, args, dest)? { + let this = self.eval_context_mut(); + if this.emulate_intrinsic(instance, args, dest)? { return Ok(()); } - let tcx = &{self.tcx.tcx}; + let tcx = &{this.tcx.tcx}; let substs = instance.substs; // All these intrinsics take raw pointers, so if we access memory directly // (as opposed to through a place), we have to remember to erase any tag // that might still hang around! - let intrinsic_name = &self.tcx.item_name(instance.def_id()).as_str()[..]; + let intrinsic_name = &this.tcx.item_name(instance.def_id()).as_str()[..]; match intrinsic_name { "arith_offset" => { - let offset = self.read_scalar(args[1])?.to_isize(self)?; - let ptr = self.read_scalar(args[0])?.not_undef()?; + let offset = this.read_scalar(args[1])?.to_isize(this)?; + let ptr = this.read_scalar(args[0])?.not_undef()?; let pointee_ty = substs.type_at(0); - let pointee_size = self.layout_of(pointee_ty)?.size.bytes() as i64; + let pointee_size = this.layout_of(pointee_ty)?.size.bytes() as i64; let offset = offset.overflowing_mul(pointee_size).0; - let result_ptr = ptr.ptr_wrapping_signed_offset(offset, self); - self.write_scalar(result_ptr, dest)?; + let result_ptr = ptr.ptr_wrapping_signed_offset(offset, this); + this.write_scalar(result_ptr, dest)?; } "assume" => { - let cond = self.read_scalar(args[0])?.to_bool()?; + let cond = this.read_scalar(args[0])?.to_bool()?; if !cond { return err!(AssumptionNotHeld); } @@ -59,18 +52,18 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' "atomic_load_relaxed" | "atomic_load_acq" | "volatile_load" => { - let ptr = self.deref_operand(args[0])?; - let val = self.read_scalar(ptr.into())?; // make sure it fits into a scalar; otherwise it cannot be atomic - self.write_scalar(val, dest)?; + let ptr = this.deref_operand(args[0])?; + let val = this.read_scalar(ptr.into())?; // make sure it fits into a scalar; otherwise it cannot be atomic + this.write_scalar(val, dest)?; } "atomic_store" | "atomic_store_relaxed" | "atomic_store_rel" | "volatile_store" => { - let ptr = self.deref_operand(args[0])?; - let val = self.read_scalar(args[1])?; // make sure it fits into a scalar; otherwise it cannot be atomic - self.write_scalar(val, ptr.into())?; + let ptr = this.deref_operand(args[0])?; + let val = this.read_scalar(args[1])?; // make sure it fits into a scalar; otherwise it cannot be atomic + this.write_scalar(val, ptr.into())?; } "atomic_fence_acq" => { @@ -78,25 +71,25 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' } _ if intrinsic_name.starts_with("atomic_xchg") => { - let ptr = self.deref_operand(args[0])?; - let new = self.read_scalar(args[1])?; - let old = self.read_scalar(ptr.into())?; - self.write_scalar(old, dest)?; // old value is returned - self.write_scalar(new, ptr.into())?; + let ptr = this.deref_operand(args[0])?; + let new = this.read_scalar(args[1])?; + let old = this.read_scalar(ptr.into())?; + this.write_scalar(old, dest)?; // old value is returned + this.write_scalar(new, ptr.into())?; } _ if intrinsic_name.starts_with("atomic_cxchg") => { - let ptr = self.deref_operand(args[0])?; - let expect_old = self.read_immediate(args[1])?; // read as immediate for the sake of `binary_op_imm()` - let new = self.read_scalar(args[2])?; - let old = self.read_immediate(ptr.into())?; // read as immediate for the sake of `binary_op_imm()` + let ptr = this.deref_operand(args[0])?; + let expect_old = this.read_immediate(args[1])?; // read as immediate for the sake of `binary_op_imm()` + let new = this.read_scalar(args[2])?; + let old = this.read_immediate(ptr.into())?; // read as immediate for the sake of `binary_op_imm()` // binary_op_imm will bail if either of them is not a scalar - let (eq, _) = self.binary_op_imm(mir::BinOp::Eq, old, expect_old)?; + let (eq, _) = this.binary_op_imm(mir::BinOp::Eq, old, expect_old)?; let res = Immediate::ScalarPair(old.to_scalar_or_undef(), eq.into()); - self.write_immediate(res, dest)?; // old value is returned + this.write_immediate(res, dest)?; // old value is returned // update ptr depending on comparison if eq.to_bool()? { - self.write_scalar(new, ptr.into())?; + this.write_scalar(new, ptr.into())?; } } @@ -125,13 +118,13 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' "atomic_xsub_rel" | "atomic_xsub_acqrel" | "atomic_xsub_relaxed" => { - let ptr = self.deref_operand(args[0])?; + let ptr = this.deref_operand(args[0])?; if !ptr.layout.ty.is_integral() { return err!(Unimplemented(format!("Atomic arithmetic operations only work on integer types"))); } - let rhs = self.read_immediate(args[1])?; - let old = self.read_immediate(ptr.into())?; - self.write_immediate(*old, dest)?; // old value is returned + let rhs = this.read_immediate(args[1])?; + let old = this.read_immediate(ptr.into())?; + this.write_immediate(*old, dest)?; // old value is returned let op = match intrinsic_name.split('_').nth(1).unwrap() { "or" => mir::BinOp::BitOr, "xor" => mir::BinOp::BitXor, @@ -141,7 +134,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' _ => bug!(), }; // Atomics wrap around on overflow. - self.binop_ignore_overflow(op, old, rhs, ptr.into())?; + this.binop_ignore_overflow(op, old, rhs, ptr.into())?; } "breakpoint" => unimplemented!(), // halt miri @@ -149,14 +142,14 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' "copy" | "copy_nonoverlapping" => { let elem_ty = substs.type_at(0); - let elem_layout = self.layout_of(elem_ty)?; + let elem_layout = this.layout_of(elem_ty)?; let elem_size = elem_layout.size.bytes(); - let count = self.read_scalar(args[2])?.to_usize(self)?; + let count = this.read_scalar(args[2])?.to_usize(this)?; let elem_align = elem_layout.align.abi; // erase tags: this is a raw ptr operation - let src = self.read_scalar(args[0])?.not_undef()?; - let dest = self.read_scalar(args[1])?.not_undef()?; - self.memory_mut().copy( + let src = this.read_scalar(args[0])?.not_undef()?; + let dest = this.read_scalar(args[1])?.not_undef()?; + this.memory_mut().copy( src, elem_align, dest, @@ -167,14 +160,14 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' } "discriminant_value" => { - let place = self.deref_operand(args[0])?; - let discr_val = self.read_discriminant(place.into())?.0; - self.write_scalar(Scalar::from_uint(discr_val, dest.layout.size), dest)?; + let place = this.deref_operand(args[0])?; + let discr_val = this.read_discriminant(place.into())?.0; + this.write_scalar(Scalar::from_uint(discr_val, dest.layout.size), dest)?; } "sinf32" | "fabsf32" | "cosf32" | "sqrtf32" | "expf32" | "exp2f32" | "logf32" | "log10f32" | "log2f32" | "floorf32" | "ceilf32" | "truncf32" => { - let f = self.read_scalar(args[0])?.to_f32()?; + let f = this.read_scalar(args[0])?.to_f32()?; let f = match intrinsic_name { "sinf32" => f.sin(), "fabsf32" => f.abs(), @@ -190,12 +183,12 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' "truncf32" => f.trunc(), _ => bug!(), }; - self.write_scalar(Scalar::from_f32(f), dest)?; + this.write_scalar(Scalar::from_f32(f), dest)?; } "sinf64" | "fabsf64" | "cosf64" | "sqrtf64" | "expf64" | "exp2f64" | "logf64" | "log10f64" | "log2f64" | "floorf64" | "ceilf64" | "truncf64" => { - let f = self.read_scalar(args[0])?.to_f64()?; + let f = this.read_scalar(args[0])?.to_f64()?; let f = match intrinsic_name { "sinf64" => f.sin(), "fabsf64" => f.abs(), @@ -211,12 +204,12 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' "truncf64" => f.trunc(), _ => bug!(), }; - self.write_scalar(Scalar::from_f64(f), dest)?; + this.write_scalar(Scalar::from_f64(f), dest)?; } "fadd_fast" | "fsub_fast" | "fmul_fast" | "fdiv_fast" | "frem_fast" => { - let a = self.read_immediate(args[0])?; - let b = self.read_immediate(args[1])?; + let a = this.read_immediate(args[0])?; + let b = this.read_immediate(args[1])?; let op = match intrinsic_name { "fadd_fast" => mir::BinOp::Add, "fsub_fast" => mir::BinOp::Sub, @@ -225,19 +218,19 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' "frem_fast" => mir::BinOp::Rem, _ => bug!(), }; - self.binop_ignore_overflow(op, a, b, dest)?; + this.binop_ignore_overflow(op, a, b, dest)?; } "exact_div" => { // Performs an exact division, resulting in undefined behavior where // `x % y != 0` or `y == 0` or `x == T::min_value() && y == -1` - let a = self.read_immediate(args[0])?; - let b = self.read_immediate(args[1])?; + let a = this.read_immediate(args[0])?; + let b = this.read_immediate(args[1])?; // check x % y != 0 - if self.binary_op_imm(mir::BinOp::Rem, a, b)?.0.to_bytes()? != 0 { + if this.binary_op_imm(mir::BinOp::Rem, a, b)?.0.to_bytes()? != 0 { return err!(ValidationFailure(format!("exact_div: {:?} cannot be divided by {:?}", a, b))); } - self.binop_ignore_overflow(mir::BinOp::Div, a, b, dest)?; + this.binop_ignore_overflow(mir::BinOp::Div, a, b, dest)?; }, "likely" | "unlikely" | "forget" => {} @@ -252,21 +245,21 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' if !dest.layout.is_zst() { // nothing to do for ZST match dest.layout.abi { layout::Abi::Scalar(ref s) => { - let x = Scalar::from_int(0, s.value.size(self)); - self.write_immediate(Immediate::Scalar(x.into()), dest)?; + let x = Scalar::from_int(0, s.value.size(this)); + this.write_immediate(Immediate::Scalar(x.into()), dest)?; } layout::Abi::ScalarPair(ref s1, ref s2) => { - let x = Scalar::from_int(0, s1.value.size(self)); - let y = Scalar::from_int(0, s2.value.size(self)); - self.write_immediate(Immediate::ScalarPair(x.into(), y.into()), dest)?; + let x = Scalar::from_int(0, s1.value.size(this)); + let y = Scalar::from_int(0, s2.value.size(this)); + this.write_immediate(Immediate::ScalarPair(x.into(), y.into()), dest)?; } _ => { // Do it in memory - let mplace = self.force_allocation(dest)?; + let mplace = this.force_allocation(dest)?; assert!(mplace.meta.is_none()); // not a zst, must be valid pointer let ptr = mplace.ptr.to_ptr()?; - self.memory_mut().get_mut(ptr.alloc_id)?.write_repeat(tcx, ptr, 0, dest.layout.size)?; + this.memory_mut().get_mut(ptr.alloc_id)?.write_repeat(tcx, ptr, 0, dest.layout.size)?; } } } @@ -274,87 +267,87 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' "pref_align_of" => { let ty = substs.type_at(0); - let layout = self.layout_of(ty)?; + let layout = this.layout_of(ty)?; let align = layout.align.pref.bytes(); - let ptr_size = self.pointer_size(); + let ptr_size = this.pointer_size(); let align_val = Scalar::from_uint(align as u128, ptr_size); - self.write_scalar(align_val, dest)?; + this.write_scalar(align_val, dest)?; } "move_val_init" => { - let ptr = self.deref_operand(args[0])?; - self.copy_op(args[1], ptr.into())?; + let ptr = this.deref_operand(args[0])?; + this.copy_op(args[1], ptr.into())?; } "offset" => { - let offset = self.read_scalar(args[1])?.to_isize(self)?; - let ptr = self.read_scalar(args[0])?.not_undef()?; - let result_ptr = self.pointer_offset_inbounds(ptr, substs.type_at(0), offset)?; - self.write_scalar(result_ptr, dest)?; + let offset = this.read_scalar(args[1])?.to_isize(this)?; + let ptr = this.read_scalar(args[0])?.not_undef()?; + let result_ptr = this.pointer_offset_inbounds(ptr, substs.type_at(0), offset)?; + this.write_scalar(result_ptr, dest)?; } "powf32" => { - let f = self.read_scalar(args[0])?.to_f32()?; - let f2 = self.read_scalar(args[1])?.to_f32()?; - self.write_scalar( + let f = this.read_scalar(args[0])?.to_f32()?; + let f2 = this.read_scalar(args[1])?.to_f32()?; + this.write_scalar( Scalar::from_f32(f.powf(f2)), dest, )?; } "powf64" => { - let f = self.read_scalar(args[0])?.to_f64()?; - let f2 = self.read_scalar(args[1])?.to_f64()?; - self.write_scalar( + let f = this.read_scalar(args[0])?.to_f64()?; + let f2 = this.read_scalar(args[1])?.to_f64()?; + this.write_scalar( Scalar::from_f64(f.powf(f2)), dest, )?; } "fmaf32" => { - let a = self.read_scalar(args[0])?.to_f32()?; - let b = self.read_scalar(args[1])?.to_f32()?; - let c = self.read_scalar(args[2])?.to_f32()?; - self.write_scalar( + let a = this.read_scalar(args[0])?.to_f32()?; + let b = this.read_scalar(args[1])?.to_f32()?; + let c = this.read_scalar(args[2])?.to_f32()?; + this.write_scalar( Scalar::from_f32(a * b + c), dest, )?; } "fmaf64" => { - let a = self.read_scalar(args[0])?.to_f64()?; - let b = self.read_scalar(args[1])?.to_f64()?; - let c = self.read_scalar(args[2])?.to_f64()?; - self.write_scalar( + let a = this.read_scalar(args[0])?.to_f64()?; + let b = this.read_scalar(args[1])?.to_f64()?; + let c = this.read_scalar(args[2])?.to_f64()?; + this.write_scalar( Scalar::from_f64(a * b + c), dest, )?; } "powif32" => { - let f = self.read_scalar(args[0])?.to_f32()?; - let i = self.read_scalar(args[1])?.to_i32()?; - self.write_scalar( + let f = this.read_scalar(args[0])?.to_f32()?; + let i = this.read_scalar(args[1])?.to_i32()?; + this.write_scalar( Scalar::from_f32(f.powi(i)), dest, )?; } "powif64" => { - let f = self.read_scalar(args[0])?.to_f64()?; - let i = self.read_scalar(args[1])?.to_i32()?; - self.write_scalar( + let f = this.read_scalar(args[0])?.to_f64()?; + let i = this.read_scalar(args[1])?.to_i32()?; + this.write_scalar( Scalar::from_f64(f.powi(i)), dest, )?; } "size_of_val" => { - let mplace = self.deref_operand(args[0])?; - let (size, _) = self.size_and_align_of_mplace(mplace)? + let mplace = this.deref_operand(args[0])?; + let (size, _) = this.size_and_align_of_mplace(mplace)? .expect("size_of_val called on extern type"); - let ptr_size = self.pointer_size(); - self.write_scalar( + let ptr_size = this.pointer_size(); + this.write_scalar( Scalar::from_uint(size.bytes() as u128, ptr_size), dest, )?; @@ -362,11 +355,11 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' "min_align_of_val" | "align_of_val" => { - let mplace = self.deref_operand(args[0])?; - let (_, align) = self.size_and_align_of_mplace(mplace)? + let mplace = this.deref_operand(args[0])?; + let (_, align) = this.size_and_align_of_mplace(mplace)? .expect("size_of_val called on extern type"); - let ptr_size = self.pointer_size(); - self.write_scalar( + let ptr_size = this.pointer_size(); + this.write_scalar( Scalar::from_uint(align.bytes(), ptr_size), dest, )?; @@ -375,18 +368,18 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' "type_name" => { let ty = substs.type_at(0); let ty_name = ty.to_string(); - let value = self.str_to_immediate(&ty_name)?; - self.write_immediate(value, dest)?; + let value = this.str_to_immediate(&ty_name)?; + this.write_immediate(value, dest)?; } "unchecked_div" => { - let l = self.read_immediate(args[0])?; - let r = self.read_immediate(args[1])?; + let l = this.read_immediate(args[0])?; + let r = this.read_immediate(args[1])?; let rval = r.to_scalar()?.to_bytes()?; if rval == 0 { return err!(Intrinsic(format!("Division by 0 in unchecked_div"))); } - self.binop_ignore_overflow( + this.binop_ignore_overflow( mir::BinOp::Div, l, r, @@ -395,13 +388,13 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' } "unchecked_rem" => { - let l = self.read_immediate(args[0])?; - let r = self.read_immediate(args[1])?; + let l = this.read_immediate(args[0])?; + let r = this.read_immediate(args[1])?; let rval = r.to_scalar()?.to_bytes()?; if rval == 0 { return err!(Intrinsic(format!("Division by 0 in unchecked_rem"))); } - self.binop_ignore_overflow( + this.binop_ignore_overflow( mir::BinOp::Rem, l, r, @@ -420,18 +413,18 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' match dest.layout.abi { layout::Abi::Scalar(..) => { let x = ScalarMaybeUndef::Undef; - self.write_immediate(Immediate::Scalar(x), dest)?; + this.write_immediate(Immediate::Scalar(x), dest)?; } layout::Abi::ScalarPair(..) => { let x = ScalarMaybeUndef::Undef; - self.write_immediate(Immediate::ScalarPair(x, x), dest)?; + this.write_immediate(Immediate::ScalarPair(x, x), dest)?; } _ => { // Do it in memory - let mplace = self.force_allocation(dest)?; + let mplace = this.force_allocation(dest)?; assert!(mplace.meta.is_none()); let ptr = mplace.ptr.to_ptr()?; - self.memory_mut() + this.memory_mut() .get_mut(ptr.alloc_id)? .mark_definedness(ptr, dest.layout.size, false)?; } @@ -441,15 +434,15 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' "write_bytes" => { let ty = substs.type_at(0); - let ty_layout = self.layout_of(ty)?; - let val_byte = self.read_scalar(args[1])?.to_u8()?; - let ptr = self.read_scalar(args[0])?.not_undef()?; - let count = self.read_scalar(args[2])?.to_usize(self)?; - self.memory().check_align(ptr, ty_layout.align.abi)?; + let ty_layout = this.layout_of(ty)?; + let val_byte = this.read_scalar(args[1])?.to_u8()?; + let ptr = this.read_scalar(args[0])?.not_undef()?; + let count = this.read_scalar(args[2])?.to_usize(this)?; + this.memory().check_align(ptr, ty_layout.align.abi)?; let byte_count = ty_layout.size * count; if byte_count.bytes() != 0 { let ptr = ptr.to_ptr()?; - self.memory_mut() + this.memory_mut() .get_mut(ptr.alloc_id)? .write_repeat(tcx, ptr, val_byte, byte_count)?; } diff --git a/src/lib.rs b/src/lib.rs index 9641670a2e..aabfa36a4b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -277,6 +277,21 @@ impl<'tcx> Evaluator<'tcx> { #[allow(dead_code)] // FIXME https://github.com/rust-lang/rust/issues/47131 type MiriEvalContext<'a, 'mir, 'tcx> = EvalContext<'a, 'mir, 'tcx, Evaluator<'tcx>>; +// A little trait that's useful to be inherited by extension traits +pub trait MiriEvalContextExt<'a, 'mir, 'tcx> { + fn eval_context_ref(&self) -> &MiriEvalContext<'a, 'mir, 'tcx>; + fn eval_context_mut(&mut self) -> &mut MiriEvalContext<'a, 'mir, 'tcx>; +} +impl<'a, 'mir, 'tcx> MiriEvalContextExt<'a, 'mir, 'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { + #[inline(always)] + fn eval_context_ref(&self) -> &MiriEvalContext<'a, 'mir, 'tcx> { + self + } + #[inline(always)] + fn eval_context_mut(&mut self) -> &mut MiriEvalContext<'a, 'mir, 'tcx> { + self + } +} impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { type MemoryKinds = MiriMemoryKind; diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index e9fb0aa777..17da5c1526 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -516,60 +516,14 @@ impl<'tcx> Stacks { } } - - -pub trait EvalContextExt<'tcx> { - fn ptr_dereference( - &self, - place: MPlaceTy<'tcx, Borrow>, - size: Size, - mutability: Option, - ) -> EvalResult<'tcx>; - - fn tag_new_allocation( - &mut self, - id: AllocId, - kind: MemoryKind, - ) -> Borrow; - - /// Reborrow the given place, returning the newly tagged ptr to it. - fn reborrow( - &mut self, - place: MPlaceTy<'tcx, Borrow>, - size: Size, - fn_barrier: bool, - new_bor: Borrow - ) -> EvalResult<'tcx>; - - /// Retag an indidual pointer, returning the retagged version. - fn retag_reference( - &mut self, - ptr: ImmTy<'tcx, Borrow>, - mutbl: Mutability, - fn_barrier: bool, - two_phase: bool, - ) -> EvalResult<'tcx, Immediate>; - - fn retag( - &mut self, - fn_entry: bool, - two_phase: bool, - place: PlaceTy<'tcx, Borrow> - ) -> EvalResult<'tcx>; - - fn escape_to_raw( - &mut self, - place: MPlaceTy<'tcx, Borrow>, - size: Size, - ) -> EvalResult<'tcx>; -} - -impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { +impl<'a, 'mir, 'tcx> EvalContextExt<'a, 'mir, 'tcx> for crate::MiriEvalContext<'a, 'mir, 'tcx> {} +pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, 'mir, 'tcx> { fn tag_new_allocation( &mut self, id: AllocId, kind: MemoryKind, ) -> Borrow { + let this = self.eval_context_mut(); let time = match kind { MemoryKind::Stack => { // New unique borrow. This `Uniq` is not accessible by the program, @@ -580,7 +534,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { // `reset` which the blog post [1] says to perform when accessing a local. // // [1] https://www.ralfj.de/blog/2018/08/07/stacked-borrows.html - self.machine.stacked_borrows.increment_clock() + this.machine.stacked_borrows.increment_clock() } _ => { // Nothing to do for everything else @@ -588,7 +542,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { } }; // Make this the active borrow for this allocation - let alloc = self.memory_mut().get_mut(id).expect("This is a new allocation, it must still exist"); + let alloc = this.memory_mut().get_mut(id).expect("This is a new allocation, it must still exist"); let size = Size::from_bytes(alloc.bytes.len() as u64); alloc.extra.first_item(BorStackItem::Uniq(time), size); Borrow::Uniq(time) @@ -604,6 +558,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { size: Size, mutability: Option, ) -> EvalResult<'tcx> { + let this = self.eval_context_ref(); trace!("ptr_dereference: Accessing {} reference for {:?} (pointee {})", if let Some(mutability) = mutability { format!("{:?}", mutability) } else { format!("raw") }, place.ptr, place.layout.ty); @@ -614,13 +569,13 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { } // Get the allocation - let alloc = self.memory().get(ptr.alloc_id)?; - alloc.check_bounds(self, ptr, size)?; + let alloc = this.memory().get(ptr.alloc_id)?; + alloc.check_bounds(this, ptr, size)?; // If we got here, we do some checking, *but* we leave the tag unchanged. if let Borrow::Shr(Some(_)) = ptr.tag { assert_eq!(mutability, Some(MutImmutable)); // We need a frozen-sensitive check - self.visit_freeze_sensitive(place, size, |cur_ptr, size, frozen| { + this.visit_freeze_sensitive(place, size, |cur_ptr, size, frozen| { let kind = if frozen { RefKind::Frozen } else { RefKind::Raw }; alloc.extra.deref(cur_ptr, size, kind) })?; @@ -641,7 +596,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { place: MPlaceTy<'tcx, Borrow>, size: Size, ) -> EvalResult<'tcx> { - self.reborrow(place, size, /*fn_barrier*/ false, Borrow::default())?; + let this = self.eval_context_mut(); + this.reborrow(place, size, /*fn_barrier*/ false, Borrow::default())?; Ok(()) } @@ -652,18 +608,19 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { fn_barrier: bool, new_bor: Borrow ) -> EvalResult<'tcx> { + let this = self.eval_context_mut(); let ptr = place.ptr.to_ptr()?; - let barrier = if fn_barrier { Some(self.frame().extra) } else { None }; + let barrier = if fn_barrier { Some(this.frame().extra) } else { None }; trace!("reborrow: Creating new reference for {:?} (pointee {}): {:?}", ptr, place.layout.ty, new_bor); // Get the allocation. It might not be mutable, so we cannot use `get_mut`. - let alloc = self.memory().get(ptr.alloc_id)?; - alloc.check_bounds(self, ptr, size)?; + let alloc = this.memory().get(ptr.alloc_id)?; + alloc.check_bounds(this, ptr, size)?; // Update the stacks. if let Borrow::Shr(Some(_)) = new_bor { // Reference that cares about freezing. We need a frozen-sensitive reborrow. - self.visit_freeze_sensitive(place, size, |cur_ptr, size, frozen| { + this.visit_freeze_sensitive(place, size, |cur_ptr, size, frozen| { let kind = if frozen { RefKind::Frozen } else { RefKind::Raw }; alloc.extra.reborrow(cur_ptr, size, barrier, new_bor, kind) })?; @@ -675,6 +632,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { Ok(()) } + /// Retag an indidual pointer, returning the retagged version. fn retag_reference( &mut self, val: ImmTy<'tcx, Borrow>, @@ -682,9 +640,10 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { fn_barrier: bool, two_phase: bool, ) -> EvalResult<'tcx, Immediate> { + let this = self.eval_context_mut(); // We want a place for where the ptr *points to*, so we get one. - let place = self.ref_to_mplace(val)?; - let size = self.size_and_align_of_mplace(place)? + let place = this.ref_to_mplace(val)?; + let size = this.size_and_align_of_mplace(place)? .map(|(size, _)| size) .unwrap_or_else(|| place.layout.size); if size == Size::ZERO { @@ -693,22 +652,22 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { } // Compute new borrow. - let time = self.machine.stacked_borrows.increment_clock(); + let time = this.machine.stacked_borrows.increment_clock(); let new_bor = match mutbl { MutMutable => Borrow::Uniq(time), MutImmutable => Borrow::Shr(Some(time)), }; // Reborrow. - self.reborrow(place, size, fn_barrier, new_bor)?; + this.reborrow(place, size, fn_barrier, new_bor)?; let new_place = place.with_tag(new_bor); // Handle two-phase borrows. if two_phase { assert!(mutbl == MutMutable, "two-phase shared borrows make no sense"); // We immediately share it, to allow read accesses - let two_phase_time = self.machine.stacked_borrows.increment_clock(); + let two_phase_time = this.machine.stacked_borrows.increment_clock(); let two_phase_bor = Borrow::Shr(Some(two_phase_time)); - self.reborrow(new_place, size, /*fn_barrier*/false, two_phase_bor)?; + this.reborrow(new_place, size, /*fn_barrier*/false, two_phase_bor)?; } // Return new ptr. @@ -721,6 +680,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { two_phase: bool, place: PlaceTy<'tcx, Borrow> ) -> EvalResult<'tcx> { + let this = self.eval_context_mut(); // Determine mutability and whether to add a barrier. // Cannot use `builtin_deref` because that reports *immutable* for `Box`, // making it useless. @@ -740,14 +700,14 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { // avoids allocating. if let Some((mutbl, barrier)) = qualify(place.layout.ty, fn_entry) { // fast path - let val = self.read_immediate(self.place_to_op(place)?)?; - let val = self.retag_reference(val, mutbl, barrier, two_phase)?; - self.write_immediate(val, place)?; + let val = this.read_immediate(this.place_to_op(place)?)?; + let val = this.retag_reference(val, mutbl, barrier, two_phase)?; + this.write_immediate(val, place)?; return Ok(()); } - let place = self.force_allocation(place)?; + let place = this.force_allocation(place)?; - let mut visitor = RetagVisitor { ecx: self, fn_entry, two_phase }; + let mut visitor = RetagVisitor { ecx: this, fn_entry, two_phase }; visitor.visit_value(place)?; // The actual visitor diff --git a/src/tls.rs b/src/tls.rs index af1d7b138b..5411e02161 100644 --- a/src/tls.rs +++ b/src/tls.rs @@ -34,10 +34,6 @@ impl<'tcx> Default for TlsData<'tcx> { } } -pub trait EvalContextExt<'tcx> { - fn run_tls_dtors(&mut self) -> EvalResult<'tcx>; -} - impl<'tcx> TlsData<'tcx> { pub fn create_tls_key( &mut self, @@ -133,35 +129,37 @@ impl<'tcx> TlsData<'tcx> { } } -impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, 'tcx> { +impl<'a, 'mir, 'tcx> EvalContextExt<'a, 'mir, 'tcx> for crate::MiriEvalContext<'a, 'mir, 'tcx> {} +pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, 'mir, 'tcx> { fn run_tls_dtors(&mut self) -> EvalResult<'tcx> { - let mut dtor = self.machine.tls.fetch_tls_dtor(None, &*self.tcx); + let this = self.eval_context_mut(); + let mut dtor = this.machine.tls.fetch_tls_dtor(None, &*this.tcx); // FIXME: replace loop by some structure that works with stepping while let Some((instance, ptr, key)) = dtor { trace!("Running TLS dtor {:?} on {:?}", instance, ptr); // TODO: Potentially, this has to support all the other possible instances? // See eval_fn_call in interpret/terminator/mod.rs - let mir = self.load_mir(instance.def)?; - let ret_place = MPlaceTy::dangling(self.layout_of(self.tcx.mk_unit())?, self).into(); - self.push_stack_frame( + let mir = this.load_mir(instance.def)?; + let ret_place = MPlaceTy::dangling(this.layout_of(this.tcx.mk_unit())?, this).into(); + this.push_stack_frame( instance, mir.span, mir, Some(ret_place), StackPopCleanup::None { cleanup: true }, )?; - let arg_local = self.frame().mir.args_iter().next().ok_or_else( + let arg_local = this.frame().mir.args_iter().next().ok_or_else( || EvalErrorKind::AbiViolation("TLS dtor does not take enough arguments.".to_owned()), )?; - let dest = self.eval_place(&mir::Place::Local(arg_local))?; - self.write_scalar(ptr, dest)?; + let dest = this.eval_place(&mir::Place::Local(arg_local))?; + this.write_scalar(ptr, dest)?; // step until out of stackframes - self.run()?; + this.run()?; - dtor = match self.machine.tls.fetch_tls_dtor(Some(key), &*self.tcx) { + dtor = match this.machine.tls.fetch_tls_dtor(Some(key), &*this.tcx) { dtor @ Some(_) => dtor, - None => self.machine.tls.fetch_tls_dtor(None, &*self.tcx), + None => this.machine.tls.fetch_tls_dtor(None, &*this.tcx), }; } // FIXME: On a windows target, call `unsafe extern "system" fn on_tls_callback`. From 383d215386f7b9cb4b08bde9b7fd0db4c3f8112a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 11 Dec 2018 14:18:51 +0100 Subject: [PATCH 2/3] make some functions private to StackedBorrows --- src/stacked_borrows.rs | 149 +++++++++++++++++++++-------------------- 1 file changed, 76 insertions(+), 73 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 17da5c1526..748ac020d6 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -516,6 +516,82 @@ impl<'tcx> Stacks { } } +impl<'a, 'mir, 'tcx> EvalContextPrivExt<'a, 'mir, 'tcx> for crate::MiriEvalContext<'a, 'mir, 'tcx> {} +trait EvalContextPrivExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, 'mir, 'tcx> { + fn reborrow( + &mut self, + place: MPlaceTy<'tcx, Borrow>, + size: Size, + fn_barrier: bool, + new_bor: Borrow + ) -> EvalResult<'tcx> { + let this = self.eval_context_mut(); + let ptr = place.ptr.to_ptr()?; + let barrier = if fn_barrier { Some(this.frame().extra) } else { None }; + trace!("reborrow: Creating new reference for {:?} (pointee {}): {:?}", + ptr, place.layout.ty, new_bor); + + // Get the allocation. It might not be mutable, so we cannot use `get_mut`. + let alloc = this.memory().get(ptr.alloc_id)?; + alloc.check_bounds(this, ptr, size)?; + // Update the stacks. + if let Borrow::Shr(Some(_)) = new_bor { + // Reference that cares about freezing. We need a frozen-sensitive reborrow. + this.visit_freeze_sensitive(place, size, |cur_ptr, size, frozen| { + let kind = if frozen { RefKind::Frozen } else { RefKind::Raw }; + alloc.extra.reborrow(cur_ptr, size, barrier, new_bor, kind) + })?; + } else { + // Just treat this as one big chunk. + let kind = if new_bor.is_unique() { RefKind::Unique } else { RefKind::Raw }; + alloc.extra.reborrow(ptr, size, barrier, new_bor, kind)?; + } + Ok(()) + } + + /// Retag an indidual pointer, returning the retagged version. + fn retag_reference( + &mut self, + val: ImmTy<'tcx, Borrow>, + mutbl: Mutability, + fn_barrier: bool, + two_phase: bool, + ) -> EvalResult<'tcx, Immediate> { + let this = self.eval_context_mut(); + // We want a place for where the ptr *points to*, so we get one. + let place = this.ref_to_mplace(val)?; + let size = this.size_and_align_of_mplace(place)? + .map(|(size, _)| size) + .unwrap_or_else(|| place.layout.size); + if size == Size::ZERO { + // Nothing to do for ZSTs. + return Ok(*val); + } + + // Compute new borrow. + let time = this.machine.stacked_borrows.increment_clock(); + let new_bor = match mutbl { + MutMutable => Borrow::Uniq(time), + MutImmutable => Borrow::Shr(Some(time)), + }; + + // Reborrow. + this.reborrow(place, size, fn_barrier, new_bor)?; + let new_place = place.with_tag(new_bor); + // Handle two-phase borrows. + if two_phase { + assert!(mutbl == MutMutable, "two-phase shared borrows make no sense"); + // We immediately share it, to allow read accesses + let two_phase_time = this.machine.stacked_borrows.increment_clock(); + let two_phase_bor = Borrow::Shr(Some(two_phase_time)); + this.reborrow(new_place, size, /*fn_barrier*/false, two_phase_bor)?; + } + + // Return new ptr. + Ok(new_place.to_ref()) + } +} + impl<'a, 'mir, 'tcx> EvalContextExt<'a, 'mir, 'tcx> for crate::MiriEvalContext<'a, 'mir, 'tcx> {} pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, 'mir, 'tcx> { fn tag_new_allocation( @@ -601,79 +677,6 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, Ok(()) } - fn reborrow( - &mut self, - place: MPlaceTy<'tcx, Borrow>, - size: Size, - fn_barrier: bool, - new_bor: Borrow - ) -> EvalResult<'tcx> { - let this = self.eval_context_mut(); - let ptr = place.ptr.to_ptr()?; - let barrier = if fn_barrier { Some(this.frame().extra) } else { None }; - trace!("reborrow: Creating new reference for {:?} (pointee {}): {:?}", - ptr, place.layout.ty, new_bor); - - // Get the allocation. It might not be mutable, so we cannot use `get_mut`. - let alloc = this.memory().get(ptr.alloc_id)?; - alloc.check_bounds(this, ptr, size)?; - // Update the stacks. - if let Borrow::Shr(Some(_)) = new_bor { - // Reference that cares about freezing. We need a frozen-sensitive reborrow. - this.visit_freeze_sensitive(place, size, |cur_ptr, size, frozen| { - let kind = if frozen { RefKind::Frozen } else { RefKind::Raw }; - alloc.extra.reborrow(cur_ptr, size, barrier, new_bor, kind) - })?; - } else { - // Just treat this as one big chunk. - let kind = if new_bor.is_unique() { RefKind::Unique } else { RefKind::Raw }; - alloc.extra.reborrow(ptr, size, barrier, new_bor, kind)?; - } - Ok(()) - } - - /// Retag an indidual pointer, returning the retagged version. - fn retag_reference( - &mut self, - val: ImmTy<'tcx, Borrow>, - mutbl: Mutability, - fn_barrier: bool, - two_phase: bool, - ) -> EvalResult<'tcx, Immediate> { - let this = self.eval_context_mut(); - // We want a place for where the ptr *points to*, so we get one. - let place = this.ref_to_mplace(val)?; - let size = this.size_and_align_of_mplace(place)? - .map(|(size, _)| size) - .unwrap_or_else(|| place.layout.size); - if size == Size::ZERO { - // Nothing to do for ZSTs. - return Ok(*val); - } - - // Compute new borrow. - let time = this.machine.stacked_borrows.increment_clock(); - let new_bor = match mutbl { - MutMutable => Borrow::Uniq(time), - MutImmutable => Borrow::Shr(Some(time)), - }; - - // Reborrow. - this.reborrow(place, size, fn_barrier, new_bor)?; - let new_place = place.with_tag(new_bor); - // Handle two-phase borrows. - if two_phase { - assert!(mutbl == MutMutable, "two-phase shared borrows make no sense"); - // We immediately share it, to allow read accesses - let two_phase_time = this.machine.stacked_borrows.increment_clock(); - let two_phase_bor = Borrow::Shr(Some(two_phase_time)); - this.reborrow(new_place, size, /*fn_barrier*/false, two_phase_bor)?; - } - - // Return new ptr. - Ok(new_place.to_ref()) - } - fn retag( &mut self, fn_entry: bool, From 6b376dc3940513b5f7414333a42ce28b47268965 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 11 Dec 2018 14:32:59 +0100 Subject: [PATCH 3/3] get rid of to_bytes hack --- src/fn_call.rs | 18 +++++++++--------- src/helpers.rs | 25 ------------------------- src/intrinsic.rs | 8 ++++---- src/lib.rs | 2 +- 4 files changed, 14 insertions(+), 39 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index ea913417a5..5d41848b64 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -277,7 +277,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, "memrchr" => { let ptr = this.read_scalar(args[0])?.not_undef()?; - let val = this.read_scalar(args[1])?.to_bytes()? as u8; + let val = this.read_scalar(args[1])?.to_i32()? as u8; let num = this.read_scalar(args[2])?.to_usize(this)?; if let Some(idx) = this.memory().read_bytes(ptr, Size::from_bytes(num))? .iter().rev().position(|&c| c == val) @@ -291,7 +291,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, "memchr" => { let ptr = this.read_scalar(args[0])?.not_undef()?; - let val = this.read_scalar(args[1])?.to_bytes()? as u8; + let val = this.read_scalar(args[1])?.to_i32()? as u8; let num = this.read_scalar(args[2])?.to_usize(this)?; if let Some(idx) = this.memory().read_bytes(ptr, Size::from_bytes(num))?.iter().position( |&c| c == val, @@ -379,9 +379,9 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, } "write" => { - let fd = this.read_scalar(args[0])?.to_bytes()?; + let fd = this.read_scalar(args[0])?.to_i32()?; let buf = this.read_scalar(args[1])?.not_undef()?; - let n = this.read_scalar(args[2])?.to_bytes()? as u64; + let n = this.read_scalar(args[2])?.to_usize(&*this.tcx)?; trace!("Called write({:?}, {:?}, {:?})", fd, buf, n); let result = if fd == 1 || fd == 2 { // stdout/stderr @@ -489,18 +489,18 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, this.write_null(dest)?; } "pthread_key_delete" => { - let key = this.read_scalar(args[0])?.to_bytes()?; + let key = this.read_scalar(args[0])?.to_bits(args[0].layout.size)?; this.machine.tls.delete_tls_key(key)?; // Return success (0) this.write_null(dest)?; } "pthread_getspecific" => { - let key = this.read_scalar(args[0])?.to_bytes()?; + let key = this.read_scalar(args[0])?.to_bits(args[0].layout.size)?; let ptr = this.machine.tls.load_tls(key)?; this.write_scalar(ptr, dest)?; } "pthread_setspecific" => { - let key = this.read_scalar(args[0])?.to_bytes()?; + let key = this.read_scalar(args[0])?.to_bits(args[0].layout.size)?; let new_ptr = this.read_scalar(args[1])?.not_undef()?; this.machine.tls.store_tls(key, new_ptr)?; @@ -586,12 +586,12 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, this.write_scalar(Scalar::from_uint(key, dest.layout.size), dest)?; } "TlsGetValue" => { - let key = this.read_scalar(args[0])?.to_bytes()?; + let key = this.read_scalar(args[0])?.to_bits(args[0].layout.size)?; let ptr = this.machine.tls.load_tls(key)?; this.write_scalar(ptr, dest)?; } "TlsSetValue" => { - let key = this.read_scalar(args[0])?.to_bytes()?; + let key = this.read_scalar(args[0])?.to_bits(args[0].layout.size)?; let new_ptr = this.read_scalar(args[1])?.not_undef()?; this.machine.tls.store_tls(key, new_ptr)?; diff --git a/src/helpers.rs b/src/helpers.rs index 7be1567605..fab0c67d0a 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -5,31 +5,6 @@ use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX}; use crate::*; -pub trait ScalarExt { - /// HACK: this function just extracts all bits if `defined != 0` - /// Mainly used for args of C-functions and we should totally correctly fetch the size - /// of their arguments - fn to_bytes(self) -> EvalResult<'static, u128>; -} - -impl ScalarExt for Scalar { - fn to_bytes(self) -> EvalResult<'static, u128> { - match self { - Scalar::Bits { bits, size } => { - assert_ne!(size, 0); - Ok(bits) - }, - Scalar::Ptr(_) => err!(ReadPointerAsBytes), - } - } -} - -impl ScalarExt for ScalarMaybeUndef { - fn to_bytes(self) -> EvalResult<'static, u128> { - self.not_undef()?.to_bytes() - } -} - impl<'a, 'mir, 'tcx> EvalContextExt<'a, 'mir, 'tcx> for crate::MiriEvalContext<'a, 'mir, 'tcx> {} pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, 'mir, 'tcx> { /// Get an instance for a path. diff --git a/src/intrinsic.rs b/src/intrinsic.rs index 35182ba513..0f7382b61b 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -6,7 +6,7 @@ use rustc::mir::interpret::{EvalResult, PointerArithmetic}; use crate::{ PlaceTy, OpTy, Immediate, Scalar, ScalarMaybeUndef, Borrow, - ScalarExt, OperatorEvalContextExt + OperatorEvalContextExt }; impl<'a, 'mir, 'tcx> EvalContextExt<'a, 'mir, 'tcx> for crate::MiriEvalContext<'a, 'mir, 'tcx> {} @@ -227,7 +227,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, let a = this.read_immediate(args[0])?; let b = this.read_immediate(args[1])?; // check x % y != 0 - if this.binary_op_imm(mir::BinOp::Rem, a, b)?.0.to_bytes()? != 0 { + if this.binary_op_imm(mir::BinOp::Rem, a, b)?.0.to_bits(dest.layout.size)? != 0 { return err!(ValidationFailure(format!("exact_div: {:?} cannot be divided by {:?}", a, b))); } this.binop_ignore_overflow(mir::BinOp::Div, a, b, dest)?; @@ -375,7 +375,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, "unchecked_div" => { let l = this.read_immediate(args[0])?; let r = this.read_immediate(args[1])?; - let rval = r.to_scalar()?.to_bytes()?; + let rval = r.to_scalar()?.to_bits(args[1].layout.size)?; if rval == 0 { return err!(Intrinsic(format!("Division by 0 in unchecked_div"))); } @@ -390,7 +390,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, "unchecked_rem" => { let l = this.read_immediate(args[0])?; let r = this.read_immediate(args[1])?; - let rval = r.to_scalar()?.to_bytes()?; + let rval = r.to_scalar()?.to_bits(args[1].layout.size)?; if rval == 0 { return err!(Intrinsic(format!("Division by 0 in unchecked_rem"))); } diff --git a/src/lib.rs b/src/lib.rs index aabfa36a4b..28639976aa 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -43,7 +43,7 @@ pub use crate::intrinsic::EvalContextExt as IntrinsicEvalContextExt; pub use crate::tls::{EvalContextExt as TlsEvalContextExt, TlsData}; use crate::range_map::RangeMap; #[allow(unused_imports)] // FIXME rustc bug https://github.com/rust-lang/rust/issues/53682 -pub use crate::helpers::{ScalarExt, EvalContextExt as HelpersEvalContextExt}; +pub use crate::helpers::{EvalContextExt as HelpersEvalContextExt}; use crate::mono_hash_map::MonoHashMap; pub use crate::stacked_borrows::{EvalContextExt as StackedBorEvalContextExt};