2 use rustc::ty::layout::{Align, LayoutOf, Size};
3 use rustc::hir::def_id::DefId;
6 use syntax::symbol::sym;
12 impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
13 pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
16 instance: ty::Instance<'tcx>,
17 args: &[OpTy<'tcx, Tag>],
18 dest: Option<PlaceTy<'tcx, Tag>>,
19 ret: Option<mir::BasicBlock>,
20 ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> {
21 let this = self.eval_context_mut();
22 trace!("eval_fn_call: {:#?}, {:?}", instance, dest.map(|place| *place));
24 // First, run the common hooks also supported by CTFE.
25 if this.hook_fn(instance, args, dest)? {
26 this.goto_block(ret)?;
29 // There are some more lang items we want to hook that CTFE does not hook (yet).
30 if this.tcx.lang_items().align_offset_fn() == Some(instance.def.def_id()) {
31 // FIXME: return a real value in case the target allocation has an
32 // alignment bigger than the one requested.
33 let n = u128::max_value();
34 let dest = dest.unwrap();
35 let n = this.truncate(n, dest.layout);
36 this.write_scalar(Scalar::from_uint(n, dest.layout.size), dest)?;
37 this.goto_block(ret)?;
41 // Try to see if we can do something about foreign items.
42 if this.tcx.is_foreign_item(instance.def_id()) {
43 // An external function that we cannot find MIR for, but we can still run enough
44 // of them to make miri viable.
45 this.emulate_foreign_item(instance.def_id(), args, dest, ret)?;
46 // `goto_block` already handled.
50 // Otherwise, load the MIR.
51 Ok(Some(this.load_mir(instance.def)?))
59 let this = self.eval_context_mut();
60 let tcx = &{this.tcx.tcx};
62 Scalar::from_int(0, this.pointer_size())
64 let align = this.tcx.data_layout.pointer_align.abi;
65 let ptr = this.memory_mut().allocate(Size::from_bytes(size), align, MiriMemoryKind::C.into());
67 // We just allocated this, the access cannot fail
69 .get_mut(ptr.alloc_id).unwrap()
70 .write_repeat(tcx, ptr, 0, Size::from_bytes(size)).unwrap();
79 ) -> InterpResult<'tcx> {
80 let this = self.eval_context_mut();
81 if !ptr.is_null_ptr(this) {
82 this.memory_mut().deallocate(
85 MiriMemoryKind::C.into(),
95 ) -> InterpResult<'tcx, Scalar<Tag>> {
96 let this = self.eval_context_mut();
97 let align = this.tcx.data_layout.pointer_align.abi;
98 if old_ptr.is_null_ptr(this) {
100 Ok(Scalar::from_int(0, this.pointer_size()))
102 let new_ptr = this.memory_mut().allocate(
103 Size::from_bytes(new_size),
105 MiriMemoryKind::C.into()
107 Ok(Scalar::Ptr(new_ptr))
110 let old_ptr = old_ptr.to_ptr()?;
111 let memory = this.memory_mut();
112 let old_size = Size::from_bytes(memory.get(old_ptr.alloc_id)?.bytes.len() as u64);
116 Some((old_size, align)),
117 MiriMemoryKind::C.into(),
119 Ok(Scalar::from_int(0, this.pointer_size()))
121 let new_ptr = memory.reallocate(
125 Size::from_bytes(new_size),
127 MiriMemoryKind::C.into(),
129 Ok(Scalar::Ptr(new_ptr))
134 /// Emulates calling a foreign item, failing if the item is not supported.
135 /// This function will handle `goto_block` if needed.
136 fn emulate_foreign_item(
139 args: &[OpTy<'tcx, Tag>],
140 dest: Option<PlaceTy<'tcx, Tag>>,
141 ret: Option<mir::BasicBlock>,
142 ) -> InterpResult<'tcx> {
143 let this = self.eval_context_mut();
144 let attrs = this.tcx.get_attrs(def_id);
145 let link_name = match attr::first_attr_value_str_by_name(&attrs, sym::link_name) {
146 Some(name) => name.as_str(),
147 None => this.tcx.item_name(def_id).as_str(),
149 // Strip linker suffixes (seen on 32-bit macOS).
150 let link_name = link_name.get().trim_end_matches("$UNIX2003");
151 let tcx = &{this.tcx.tcx};
153 // First: functions that diverge.
155 "__rust_start_panic" | "panic_impl" => {
156 return err!(MachineError("the evaluated program panicked".to_string()));
158 "exit" | "ExitProcess" => {
159 // it's really u32 for ExitProcess, but we have to put it into the `Exit` error variant anyway
160 let code = this.read_scalar(args[0])?.to_i32()?;
161 return err!(Exit(code));
163 _ => if dest.is_none() {
164 return err!(Unimplemented(
165 format!("can't call diverging foreign function: {}", link_name),
170 // Next: functions that assume a ret and dest.
171 let dest = dest.expect("we already checked for a dest");
172 let ret = ret.expect("dest is `Some` but ret is `None`");
175 let size = this.read_scalar(args[0])?.to_usize(this)?;
176 let res = this.malloc(size, /*zero_init:*/ false);
177 this.write_scalar(res, dest)?;
180 let items = this.read_scalar(args[0])?.to_usize(this)?;
181 let len = this.read_scalar(args[1])?.to_usize(this)?;
182 let size = items.checked_mul(len).ok_or_else(|| InterpError::Overflow(mir::BinOp::Mul))?;
183 let res = this.malloc(size, /*zero_init:*/ true);
184 this.write_scalar(res, dest)?;
186 "posix_memalign" => {
187 let ret = this.deref_operand(args[0])?;
188 let align = this.read_scalar(args[1])?.to_usize(this)?;
189 let size = this.read_scalar(args[2])?.to_usize(this)?;
190 // Align must be power of 2, and also at least ptr-sized (POSIX rules).
191 if !align.is_power_of_two() {
192 return err!(HeapAllocNonPowerOfTwoAlignment(align));
194 if align < this.pointer_size().bytes() {
195 return err!(MachineError(format!(
196 "posix_memalign: alignment must be at least the size of a pointer, but is {}",
201 this.write_null(ret.into())?;
203 let ptr = this.memory_mut().allocate(
204 Size::from_bytes(size),
205 Align::from_bytes(align).unwrap(),
206 MiriMemoryKind::C.into()
208 this.write_scalar(Scalar::Ptr(ptr), ret.into())?;
210 this.write_null(dest)?;
213 let ptr = this.read_scalar(args[0])?.not_undef()?;
217 let old_ptr = this.read_scalar(args[0])?.not_undef()?;
218 let new_size = this.read_scalar(args[1])?.to_usize(this)?;
219 let res = this.realloc(old_ptr, new_size)?;
220 this.write_scalar(res, dest)?;
224 let size = this.read_scalar(args[0])?.to_usize(this)?;
225 let align = this.read_scalar(args[1])?.to_usize(this)?;
227 return err!(HeapAllocZeroBytes);
229 if !align.is_power_of_two() {
230 return err!(HeapAllocNonPowerOfTwoAlignment(align));
232 let ptr = this.memory_mut()
234 Size::from_bytes(size),
235 Align::from_bytes(align).unwrap(),
236 MiriMemoryKind::Rust.into()
238 this.write_scalar(Scalar::Ptr(ptr), dest)?;
240 "__rust_alloc_zeroed" => {
241 let size = this.read_scalar(args[0])?.to_usize(this)?;
242 let align = this.read_scalar(args[1])?.to_usize(this)?;
244 return err!(HeapAllocZeroBytes);
246 if !align.is_power_of_two() {
247 return err!(HeapAllocNonPowerOfTwoAlignment(align));
249 let ptr = this.memory_mut()
251 Size::from_bytes(size),
252 Align::from_bytes(align).unwrap(),
253 MiriMemoryKind::Rust.into()
256 .get_mut(ptr.alloc_id)?
257 .write_repeat(tcx, ptr, 0, Size::from_bytes(size))?;
258 this.write_scalar(Scalar::Ptr(ptr), dest)?;
260 "__rust_dealloc" => {
261 let ptr = this.read_scalar(args[0])?.to_ptr()?;
262 let old_size = this.read_scalar(args[1])?.to_usize(this)?;
263 let align = this.read_scalar(args[2])?.to_usize(this)?;
265 return err!(HeapAllocZeroBytes);
267 if !align.is_power_of_two() {
268 return err!(HeapAllocNonPowerOfTwoAlignment(align));
270 this.memory_mut().deallocate(
272 Some((Size::from_bytes(old_size), Align::from_bytes(align).unwrap())),
273 MiriMemoryKind::Rust.into(),
276 "__rust_realloc" => {
277 let ptr = this.read_scalar(args[0])?.to_ptr()?;
278 let old_size = this.read_scalar(args[1])?.to_usize(this)?;
279 let align = this.read_scalar(args[2])?.to_usize(this)?;
280 let new_size = this.read_scalar(args[3])?.to_usize(this)?;
281 if old_size == 0 || new_size == 0 {
282 return err!(HeapAllocZeroBytes);
284 if !align.is_power_of_two() {
285 return err!(HeapAllocNonPowerOfTwoAlignment(align));
287 let new_ptr = this.memory_mut().reallocate(
289 Size::from_bytes(old_size),
290 Align::from_bytes(align).unwrap(),
291 Size::from_bytes(new_size),
292 Align::from_bytes(align).unwrap(),
293 MiriMemoryKind::Rust.into(),
295 this.write_scalar(Scalar::Ptr(new_ptr), dest)?;
299 let sys_getrandom = this.eval_path_scalar(&["libc", "SYS_getrandom"])?
300 .expect("Failed to get libc::SYS_getrandom")
303 // `libc::syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), GRND_NONBLOCK)`
304 // is called if a `HashMap` is created the regular way (e.g. HashMap<K, V>).
305 match this.read_scalar(args[0])?.to_usize(this)? {
306 id if id == sys_getrandom => {
307 let ptr = this.read_scalar(args[1])?.not_undef()?;
308 let len = this.read_scalar(args[2])?.to_usize(this)?;
310 // The only supported flags are GRND_RANDOM and GRND_NONBLOCK,
311 // neither of which have any effect on our current PRNG
312 let _flags = this.read_scalar(args[3])?.to_i32()?;
314 gen_random(this, len as usize, ptr)?;
315 this.write_scalar(Scalar::from_uint(len, dest.layout.size), dest)?;
318 return err!(Unimplemented(
319 format!("miri does not support syscall ID {}", id),
326 let _handle = this.read_scalar(args[0])?;
327 let symbol = this.read_scalar(args[1])?.to_ptr()?;
328 let symbol_name = this.memory().get(symbol.alloc_id)?.read_c_str(tcx, symbol)?;
329 let err = format!("bad c unicode symbol: {:?}", symbol_name);
330 let symbol_name = ::std::str::from_utf8(symbol_name).unwrap_or(&err);
331 return err!(Unimplemented(format!(
332 "miri does not support dynamically loading libraries (requested symbol: {})",
337 "__rust_maybe_catch_panic" => {
338 // fn __rust_maybe_catch_panic(
341 // data_ptr: *mut usize,
342 // vtable_ptr: *mut usize,
344 // We abort on panic, so not much is going on here, but we still have to call the closure.
345 let f = this.read_scalar(args[0])?.to_ptr()?;
346 let data = this.read_scalar(args[1])?.not_undef()?;
347 let f_instance = this.memory().get_fn(f)?;
348 this.write_null(dest)?;
349 trace!("__rust_maybe_catch_panic: {:?}", f_instance);
351 // Now we make a function call.
352 // TODO: consider making this reusable? `InterpretCx::step` does something similar
353 // for the TLS destructors, and of course `eval_main`.
354 let mir = this.load_mir(f_instance.def)?;
355 let ret_place = MPlaceTy::dangling(this.layout_of(this.tcx.mk_unit())?, this).into();
356 this.push_stack_frame(
361 // Directly return to caller.
362 StackPopCleanup::Goto(Some(ret)),
364 let mut args = this.frame().body.args_iter();
366 let arg_local = args.next().ok_or_else(||
367 InterpError::AbiViolation(
368 "Argument to __rust_maybe_catch_panic does not take enough arguments."
372 let arg_dest = this.eval_place(&mir::Place::Base(mir::PlaceBase::Local(arg_local)))?;
373 this.write_scalar(data, arg_dest)?;
375 assert!(args.next().is_none(), "__rust_maybe_catch_panic argument has more arguments than expected");
377 // We ourselves will return `0`, eventually (because we will not return if we paniced).
378 this.write_null(dest)?;
380 // Don't fall through, we do *not* want to `goto_block`!
385 let left = this.read_scalar(args[0])?.not_undef()?;
386 let right = this.read_scalar(args[1])?.not_undef()?;
387 let n = Size::from_bytes(this.read_scalar(args[2])?.to_usize(this)?);
390 let left_bytes = this.memory().read_bytes(left, n)?;
391 let right_bytes = this.memory().read_bytes(right, n)?;
393 use std::cmp::Ordering::*;
394 match left_bytes.cmp(right_bytes) {
402 Scalar::from_int(result, Size::from_bits(32)),
408 let ptr = this.read_scalar(args[0])?.not_undef()?;
409 let val = this.read_scalar(args[1])?.to_i32()? as u8;
410 let num = this.read_scalar(args[2])?.to_usize(this)?;
411 if let Some(idx) = this.memory().read_bytes(ptr, Size::from_bytes(num))?
412 .iter().rev().position(|&c| c == val)
414 let new_ptr = ptr.ptr_offset(Size::from_bytes(num - idx as u64 - 1), this)?;
415 this.write_scalar(new_ptr, dest)?;
417 this.write_null(dest)?;
422 let ptr = this.read_scalar(args[0])?.not_undef()?;
423 let val = this.read_scalar(args[1])?.to_i32()? as u8;
424 let num = this.read_scalar(args[2])?.to_usize(this)?;
427 .read_bytes(ptr, Size::from_bytes(num))?
429 .position(|&c| c == val);
430 if let Some(idx) = idx {
431 let new_ptr = ptr.ptr_offset(Size::from_bytes(idx as u64), this)?;
432 this.write_scalar(new_ptr, dest)?;
434 this.write_null(dest)?;
440 let name_ptr = this.read_scalar(args[0])?.to_ptr()?;
441 let name = this.memory().get(name_ptr.alloc_id)?.read_c_str(tcx, name_ptr)?;
442 match this.machine.env_vars.get(name) {
443 Some(&var) => Scalar::Ptr(var),
444 None => Scalar::ptr_null(&*this.tcx),
447 this.write_scalar(result, dest)?;
451 let mut success = None;
453 let name_ptr = this.read_scalar(args[0])?.not_undef()?;
454 if !name_ptr.is_null_ptr(this) {
455 let name_ptr = name_ptr.to_ptr()?;
458 .get(name_ptr.alloc_id)?
459 .read_c_str(tcx, name_ptr)?
461 if !name.is_empty() && !name.contains(&b'=') {
462 success = Some(this.machine.env_vars.remove(&name));
466 if let Some(old) = success {
467 if let Some(var) = old {
468 this.memory_mut().deallocate(var, None, MiriMemoryKind::Env.into())?;
470 this.write_null(dest)?;
472 this.write_scalar(Scalar::from_int(-1, dest.layout.size), dest)?;
479 let name_ptr = this.read_scalar(args[0])?.not_undef()?;
480 let value_ptr = this.read_scalar(args[1])?.to_ptr()?;
481 let value = this.memory().get(value_ptr.alloc_id)?.read_c_str(tcx, value_ptr)?;
482 if !name_ptr.is_null_ptr(this) {
483 let name_ptr = name_ptr.to_ptr()?;
484 let name = this.memory().get(name_ptr.alloc_id)?.read_c_str(tcx, name_ptr)?;
485 if !name.is_empty() && !name.contains(&b'=') {
486 new = Some((name.to_owned(), value.to_owned()));
490 if let Some((name, value)) = new {
491 // `+1` for the null terminator.
492 let value_copy = this.memory_mut().allocate(
493 Size::from_bytes((value.len() + 1) as u64),
494 Align::from_bytes(1).unwrap(),
495 MiriMemoryKind::Env.into(),
498 let alloc = this.memory_mut().get_mut(value_copy.alloc_id)?;
499 alloc.write_bytes(tcx, value_copy, &value)?;
500 let trailing_zero_ptr = value_copy.offset(
501 Size::from_bytes(value.len() as u64),
504 alloc.write_bytes(tcx, trailing_zero_ptr, &[0])?;
506 if let Some(var) = this.machine.env_vars.insert(
511 this.memory_mut().deallocate(var, None, MiriMemoryKind::Env.into())?;
513 this.write_null(dest)?;
515 this.write_scalar(Scalar::from_int(-1, dest.layout.size), dest)?;
520 let fd = this.read_scalar(args[0])?.to_i32()?;
521 let buf = this.read_scalar(args[1])?.not_undef()?;
522 let n = this.read_scalar(args[2])?.to_usize(&*this.tcx)?;
523 trace!("Called write({:?}, {:?}, {:?})", fd, buf, n);
524 let result = if fd == 1 || fd == 2 {
526 use std::io::{self, Write};
528 let buf_cont = this.memory().read_bytes(buf, Size::from_bytes(n))?;
529 // We need to flush to make sure this actually appears on the screen
530 let res = if fd == 1 {
531 // Stdout is buffered, flush to make sure it appears on the screen.
532 // This is the write() syscall of the interpreted program, we want it
533 // to correspond to a write() syscall on the host -- there is no good
534 // in adding extra buffering here.
535 let res = io::stdout().write(buf_cont);
536 io::stdout().flush().unwrap();
539 // No need to flush, stderr is not buffered.
540 io::stderr().write(buf_cont)
547 eprintln!("Miri: Ignored output to FD {}", fd);
548 // Pretend it all went well.
551 // Now, `result` is the value we return back to the program.
553 Scalar::from_int(result, dest.layout.size),
559 let ptr = this.read_scalar(args[0])?.to_ptr()?;
560 let n = this.memory().get(ptr.alloc_id)?.read_c_str(tcx, ptr)?.len();
561 this.write_scalar(Scalar::from_uint(n as u64, dest.layout.size), dest)?;
566 "cbrtf" | "coshf" | "sinhf" |"tanf" => {
567 // FIXME: Using host floats.
568 let f = f32::from_bits(this.read_scalar(args[0])?.to_u32()?);
569 let f = match link_name {
576 this.write_scalar(Scalar::from_u32(f.to_bits()), dest)?;
578 // underscore case for windows
579 "_hypotf" | "hypotf" | "atan2f" => {
580 // FIXME: Using host floats.
581 let f1 = f32::from_bits(this.read_scalar(args[0])?.to_u32()?);
582 let f2 = f32::from_bits(this.read_scalar(args[1])?.to_u32()?);
583 let n = match link_name {
584 "_hypotf" | "hypotf" => f1.hypot(f2),
585 "atan2f" => f1.atan2(f2),
588 this.write_scalar(Scalar::from_u32(n.to_bits()), dest)?;
591 "cbrt" | "cosh" | "sinh" | "tan" => {
592 // FIXME: Using host floats.
593 let f = f64::from_bits(this.read_scalar(args[0])?.to_u64()?);
594 let f = match link_name {
601 this.write_scalar(Scalar::from_u64(f.to_bits()), dest)?;
603 // underscore case for windows
604 "_hypot" | "hypot" | "atan2" => {
605 // FIXME: Using host floats.
606 let f1 = f64::from_bits(this.read_scalar(args[0])?.to_u64()?);
607 let f2 = f64::from_bits(this.read_scalar(args[1])?.to_u64()?);
608 let n = match link_name {
609 "_hypot" | "hypot" => f1.hypot(f2),
610 "atan2" => f1.atan2(f2),
613 this.write_scalar(Scalar::from_u64(n.to_bits()), dest)?;
616 // Some things needed for `sys::thread` initialization to go through.
617 "signal" | "sigaction" | "sigaltstack" => {
618 this.write_scalar(Scalar::from_int(0, dest.layout.size), dest)?;
622 let name = this.read_scalar(args[0])?.to_i32()?;
624 trace!("sysconf() called with name {}", name);
625 // Cache the sysconf integers via Miri's global cache.
627 (&["libc", "_SC_PAGESIZE"], Scalar::from_int(4096, dest.layout.size)),
628 (&["libc", "_SC_GETPW_R_SIZE_MAX"], Scalar::from_int(-1, dest.layout.size)),
629 (&["libc", "_SC_NPROCESSORS_ONLN"], Scalar::from_int(1, dest.layout.size)),
631 let mut result = None;
632 for &(path, path_value) in paths {
633 if let Some(val) = this.eval_path_scalar(path)? {
634 let val = val.to_i32()?;
636 result = Some(path_value);
642 if let Some(result) = result {
643 this.write_scalar(result, dest)?;
645 return err!(Unimplemented(
646 format!("Unimplemented sysconf name: {}", name),
652 this.write_null(dest)?;
655 // Hook pthread calls that go to the thread-local storage memory subsystem.
656 "pthread_key_create" => {
657 let key_ptr = this.read_scalar(args[0])?.not_undef()?;
659 // Extract the function type out of the signature (that seems easier than constructing it ourselves).
660 let dtor = match this.read_scalar(args[1])?.not_undef()? {
661 Scalar::Ptr(dtor_ptr) => Some(this.memory().get_fn(dtor_ptr)?),
662 Scalar::Raw { data: 0, size } => {
664 assert_eq!(size as u64, this.memory().pointer_size().bytes());
667 Scalar::Raw { .. } => return err!(ReadBytesAsPointer),
670 // Figure out how large a pthread TLS key actually is.
671 // This is `libc::pthread_key_t`.
672 let key_type = args[0].layout.ty
674 .ok_or_else(|| InterpError::AbiViolation("wrong signature used for `pthread_key_create`: first argument must be a raw pointer.".to_owned()))?
676 let key_layout = this.layout_of(key_type)?;
678 // Create key and write it into the memory where `key_ptr` wants it.
679 let key = this.machine.tls.create_tls_key(dtor, tcx) as u128;
680 if key_layout.size.bits() < 128 && key >= (1u128 << key_layout.size.bits() as u128) {
681 return err!(OutOfTls);
684 let key_ptr = this.memory().check_ptr_access(key_ptr, key_layout.size, key_layout.align.abi)?
685 .expect("cannot be a ZST");
686 this.memory_mut().get_mut(key_ptr.alloc_id)?.write_scalar(
689 Scalar::from_uint(key, key_layout.size).into(),
693 // Return success (`0`).
694 this.write_null(dest)?;
696 "pthread_key_delete" => {
697 let key = this.read_scalar(args[0])?.to_bits(args[0].layout.size)?;
698 this.machine.tls.delete_tls_key(key)?;
699 // Return success (0)
700 this.write_null(dest)?;
702 "pthread_getspecific" => {
703 let key = this.read_scalar(args[0])?.to_bits(args[0].layout.size)?;
704 let ptr = this.machine.tls.load_tls(key)?;
705 this.write_scalar(ptr, dest)?;
707 "pthread_setspecific" => {
708 let key = this.read_scalar(args[0])?.to_bits(args[0].layout.size)?;
709 let new_ptr = this.read_scalar(args[1])?.not_undef()?;
710 this.machine.tls.store_tls(key, new_ptr)?;
712 // Return success (`0`).
713 this.write_null(dest)?;
716 // Determine stack base address.
717 "pthread_attr_init" | "pthread_attr_destroy" | "pthread_attr_get_np" |
718 "pthread_getattr_np" | "pthread_self" | "pthread_get_stacksize_np" => {
719 this.write_null(dest)?;
721 "pthread_attr_getstack" => {
722 // Second argument is where we are supposed to write the stack size.
723 let ptr = this.deref_operand(args[1])?;
725 let stack_addr = Scalar::from_int(0x80000, args[1].layout.size);
726 this.write_scalar(stack_addr, ptr.into())?;
727 // Return success (`0`).
728 this.write_null(dest)?;
730 "pthread_get_stackaddr_np" => {
732 let stack_addr = Scalar::from_int(0x80000, dest.layout.size);
733 this.write_scalar(stack_addr, dest)?;
736 // Stub out calls for condvar, mutex and rwlock, to just return `0`.
737 "pthread_mutexattr_init" | "pthread_mutexattr_settype" | "pthread_mutex_init" |
738 "pthread_mutexattr_destroy" | "pthread_mutex_lock" | "pthread_mutex_unlock" |
739 "pthread_mutex_destroy" | "pthread_rwlock_rdlock" | "pthread_rwlock_unlock" |
740 "pthread_rwlock_wrlock" | "pthread_rwlock_destroy" | "pthread_condattr_init" |
741 "pthread_condattr_setclock" | "pthread_cond_init" | "pthread_condattr_destroy" |
742 "pthread_cond_destroy" => {
743 this.write_null(dest)?;
746 // We don't support fork so we don't have to do anything for atfork.
747 "pthread_atfork" => {
748 this.write_null(dest)?;
752 // This is a horrible hack, but since the guard page mechanism calls mmap and expects a particular return value, we just give it that value.
753 let addr = this.read_scalar(args[0])?.not_undef()?;
754 this.write_scalar(addr, dest)?;
757 this.write_null(dest)?;
762 // FIXME: register the destructor.
765 this.write_scalar(Scalar::Ptr(this.machine.argc.unwrap()), dest)?;
768 this.write_scalar(Scalar::Ptr(this.machine.argv.unwrap()), dest)?;
770 "SecRandomCopyBytes" => {
771 let len = this.read_scalar(args[1])?.to_usize(this)?;
772 let ptr = this.read_scalar(args[2])?.not_undef()?;
773 gen_random(this, len as usize, ptr)?;
774 this.write_null(dest)?;
777 // Windows API stubs.
779 // DWORD = ULONG = u32
781 "GetProcessHeap" => {
782 // Just fake a HANDLE
783 this.write_scalar(Scalar::from_int(1, this.pointer_size()), dest)?;
786 let _handle = this.read_scalar(args[0])?.to_isize(this)?;
787 let flags = this.read_scalar(args[1])?.to_u32()?;
788 let size = this.read_scalar(args[2])?.to_usize(this)?;
789 let zero_init = (flags & 0x00000008) != 0; // HEAP_ZERO_MEMORY
790 let res = this.malloc(size, zero_init);
791 this.write_scalar(res, dest)?;
794 let _handle = this.read_scalar(args[0])?.to_isize(this)?;
795 let _flags = this.read_scalar(args[1])?.to_u32()?;
796 let ptr = this.read_scalar(args[2])?.not_undef()?;
798 this.write_scalar(Scalar::from_int(1, Size::from_bytes(4)), dest)?;
801 let _handle = this.read_scalar(args[0])?.to_isize(this)?;
802 let _flags = this.read_scalar(args[1])?.to_u32()?;
803 let ptr = this.read_scalar(args[2])?.not_undef()?;
804 let size = this.read_scalar(args[3])?.to_usize(this)?;
805 let res = this.realloc(ptr, size)?;
806 this.write_scalar(res, dest)?;
810 let err = this.read_scalar(args[0])?.to_u32()?;
811 this.machine.last_error = err;
814 this.write_scalar(Scalar::from_u32(this.machine.last_error), dest)?;
817 "AddVectoredExceptionHandler" => {
818 // Any non zero value works for the stdlib. This is just used for stack overflows anyway.
819 this.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?;
821 "InitializeCriticalSection" |
822 "EnterCriticalSection" |
823 "LeaveCriticalSection" |
824 "DeleteCriticalSection" => {
825 // Nothing to do, not even a return value.
829 "TryEnterCriticalSection" |
830 "GetConsoleScreenBufferInfo" |
831 "SetConsoleTextAttribute" => {
832 // Pretend these do not exist / nothing happened, by returning zero.
833 this.write_null(dest)?;
836 let system_info = this.deref_operand(args[0])?;
837 let system_info_ptr = system_info.ptr.to_ptr()?;
838 // Initialize with `0`.
839 this.memory_mut().get_mut(system_info_ptr.alloc_id)?
840 .write_repeat(tcx, system_info_ptr, 0, system_info.layout.size)?;
841 // Set number of processors to `1`.
842 let dword_size = Size::from_bytes(4);
843 let offset = 2*dword_size + 3*tcx.pointer_size();
844 this.memory_mut().get_mut(system_info_ptr.alloc_id)?
847 system_info_ptr.offset(offset, tcx)?,
848 Scalar::from_int(1, dword_size).into(),
854 // This just creates a key; Windows does not natively support TLS destructors.
856 // Create key and return it.
857 let key = this.machine.tls.create_tls_key(None, tcx) as u128;
859 // Figure out how large a TLS key actually is. This is `c::DWORD`.
860 if dest.layout.size.bits() < 128
861 && key >= (1u128 << dest.layout.size.bits() as u128) {
862 return err!(OutOfTls);
864 this.write_scalar(Scalar::from_uint(key, dest.layout.size), dest)?;
867 let key = this.read_scalar(args[0])?.to_u32()? as u128;
868 let ptr = this.machine.tls.load_tls(key)?;
869 this.write_scalar(ptr, dest)?;
872 let key = this.read_scalar(args[0])?.to_u32()? as u128;
873 let new_ptr = this.read_scalar(args[1])?.not_undef()?;
874 this.machine.tls.store_tls(key, new_ptr)?;
876 // Return success (`1`).
877 this.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?;
880 let which = this.read_scalar(args[0])?.to_i32()?;
881 // We just make this the identity function, so we know later in `WriteFile`
883 this.write_scalar(Scalar::from_int(which, this.pointer_size()), dest)?;
886 let handle = this.read_scalar(args[0])?.to_isize(this)?;
887 let buf = this.read_scalar(args[1])?.not_undef()?;
888 let n = this.read_scalar(args[2])?.to_u32()?;
889 let written_place = this.deref_operand(args[3])?;
890 // Spec says to always write `0` first.
891 this.write_null(written_place.into())?;
892 let written = if handle == -11 || handle == -12 {
894 use std::io::{self, Write};
896 let buf_cont = this.memory().read_bytes(buf, Size::from_bytes(u64::from(n)))?;
897 let res = if handle == -11 {
898 io::stdout().write(buf_cont)
900 io::stderr().write(buf_cont)
902 res.ok().map(|n| n as u32)
904 eprintln!("Miri: Ignored output to handle {}", handle);
905 // Pretend it all went well.
908 // If there was no error, write back how much was written.
909 if let Some(n) = written {
910 this.write_scalar(Scalar::from_u32(n), written_place.into())?;
912 // Return whether this was a success.
914 Scalar::from_int(if written.is_some() { 1 } else { 0 }, dest.layout.size),
918 "GetConsoleMode" => {
919 // Everything is a pipe.
920 this.write_null(dest)?;
922 "GetEnvironmentVariableW" => {
923 // This is not the env var you are looking for.
924 this.machine.last_error = 203; // ERROR_ENVVAR_NOT_FOUND
925 this.write_null(dest)?;
927 "GetCommandLineW" => {
928 this.write_scalar(Scalar::Ptr(this.machine.cmd_line.unwrap()), dest)?;
930 // The actual name of 'RtlGenRandom'
931 "SystemFunction036" => {
932 let ptr = this.read_scalar(args[0])?.not_undef()?;
933 let len = this.read_scalar(args[1])?.to_u32()?;
934 gen_random(this, len as usize, ptr)?;
935 this.write_scalar(Scalar::from_bool(true), dest)?;
938 // We can't execute anything else.
940 return err!(Unimplemented(
941 format!("can't call foreign function: {}", link_name),
946 this.goto_block(Some(ret))?;
947 this.dump_place(*dest);
951 fn write_null(&mut self, dest: PlaceTy<'tcx, Tag>) -> InterpResult<'tcx> {
952 self.eval_context_mut().write_scalar(Scalar::from_int(0, dest.layout.size), dest)
955 /// Evaluates the scalar at the specified path. Returns Some(val)
956 /// if the path could be resolved, and None otherwise
957 fn eval_path_scalar(&mut self, path: &[&str]) -> InterpResult<'tcx, Option<ScalarMaybeUndef<Tag>>> {
958 let this = self.eval_context_mut();
959 if let Ok(instance) = this.resolve_path(path) {
964 let const_val = this.const_eval_raw(cid)?;
965 let const_val = this.read_scalar(const_val.into())?;
966 return Ok(Some(const_val));
972 fn gen_random<'mir, 'tcx>(
973 this: &mut MiriEvalContext<'mir, 'tcx>,
976 ) -> InterpResult<'tcx> {
981 let ptr = dest.to_ptr()?;
983 let data = match &mut this.memory_mut().extra.rng {
985 let mut rng = rng.borrow_mut();
986 let mut data = vec![0; len];
987 rng.fill_bytes(&mut data);
991 return err!(Unimplemented(
992 "miri does not support gathering system entropy in deterministic mode!
993 Use '-Zmiri-seed=<seed>' to enable random number generation.
994 WARNING: Miri does *not* generate cryptographically secure entropy -
995 do not use Miri to run any program that needs secure random number generation".to_owned(),
999 let tcx = &{this.tcx.tcx};
1000 this.memory_mut().get_mut(ptr.alloc_id)?
1001 .write_bytes(tcx, ptr, &data)