1 mod backtrace; 2 pub mod foreign_items; 3 pub mod intrinsics; 4 pub mod posix; 5 pub mod windows; 6 7 pub mod dlsym; 8 pub mod env; 9 pub mod os_str; 10 pub mod panic; 11 pub mod time; 12 pub mod tls; 13 14 // End module management, begin local code 15 16 use log::trace; 17 18 use rustc_middle::{mir, ty}; 19 use rustc_target::spec::abi::Abi; 20 21 use crate::*; 22 use helpers::check_arg_count; 23 24 impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} 25 pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { find_mir_or_eval_fn( &mut self, instance: ty::Instance<'tcx>, abi: Abi, args: &[OpTy<'tcx, Tag>], ret: Option<(&PlaceTy<'tcx, Tag>, mir::BasicBlock)>, unwind: StackPopUnwind, ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>>26 fn find_mir_or_eval_fn( 27 &mut self, 28 instance: ty::Instance<'tcx>, 29 abi: Abi, 30 args: &[OpTy<'tcx, Tag>], 31 ret: Option<(&PlaceTy<'tcx, Tag>, mir::BasicBlock)>, 32 unwind: StackPopUnwind, 33 ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> { 34 let this = self.eval_context_mut(); 35 trace!("eval_fn_call: {:#?}, {:?}", instance, ret.map(|p| p.0)); 36 37 // There are some more lang items we want to hook that CTFE does not hook (yet). 38 if this.tcx.lang_items().align_offset_fn() == Some(instance.def.def_id()) { 39 let &[ref ptr, ref align] = check_arg_count(args)?; 40 if this.align_offset(ptr, align, ret, unwind)? { 41 return Ok(None); 42 } 43 } 44 45 // Try to see if we can do something about foreign items. 46 if this.tcx.is_foreign_item(instance.def_id()) { 47 // An external function call that does not have a MIR body. We either find MIR elsewhere 48 // or emulate its effect. 49 // This will be Ok(None) if we're emulating the intrinsic entirely within Miri (no need 50 // to run extra MIR), and Ok(Some(body)) if we found MIR to run for the 51 // foreign function 52 // Any needed call to `goto_block` will be performed by `emulate_foreign_item`. 53 return this.emulate_foreign_item(instance.def_id(), abi, args, ret, unwind); 54 } 55 56 // Otherwise, load the MIR. 57 Ok(Some(&*this.load_mir(instance.def, None)?)) 58 } 59 60 /// Returns `true` if the computation was performed, and `false` if we should just evaluate 61 /// the actual MIR of `align_offset`. align_offset( &mut self, ptr_op: &OpTy<'tcx, Tag>, align_op: &OpTy<'tcx, Tag>, ret: Option<(&PlaceTy<'tcx, Tag>, mir::BasicBlock)>, unwind: StackPopUnwind, ) -> InterpResult<'tcx, bool>62 fn align_offset( 63 &mut self, 64 ptr_op: &OpTy<'tcx, Tag>, 65 align_op: &OpTy<'tcx, Tag>, 66 ret: Option<(&PlaceTy<'tcx, Tag>, mir::BasicBlock)>, 67 unwind: StackPopUnwind, 68 ) -> InterpResult<'tcx, bool> { 69 let this = self.eval_context_mut(); 70 let (dest, ret) = ret.unwrap(); 71 72 if this.memory.extra.check_alignment != AlignmentCheck::Symbolic { 73 // Just use actual implementation. 74 return Ok(false); 75 } 76 77 let req_align = this.read_scalar(align_op)?.to_machine_usize(this)?; 78 79 // Stop if the alignment is not a power of two. 80 if !req_align.is_power_of_two() { 81 this.start_panic("align_offset: align is not a power-of-two", unwind)?; 82 return Ok(true); // nothing left to do 83 } 84 85 let ptr = this.read_pointer(ptr_op)?; 86 if let Ok(ptr) = ptr.into_pointer_or_addr() { 87 // Only do anything if we can identify the allocation this goes to. 88 let (_, cur_align) = 89 this.memory.get_size_and_align(ptr.provenance.alloc_id, AllocCheck::MaybeDead)?; 90 if cur_align.bytes() >= req_align { 91 // If the allocation alignment is at least the required alignment we use the 92 // real implementation. 93 return Ok(false); 94 } 95 } 96 97 // Return error result (usize::MAX), and jump to caller. 98 this.write_scalar(Scalar::from_machine_usize(this.machine_usize_max(), this), dest)?; 99 this.go_to_block(ret); 100 Ok(true) 101 } 102 } 103