2 use rustc::ty::layout::{Align, LayoutOf, Size};
3 use rustc::hir::def_id::DefId;
6 use syntax::symbol::sym;
12 impl<'a, 'mir, 'tcx> EvalContextExt<'a, 'mir, 'tcx> for crate::MiriEvalContext<'a, 'mir, 'tcx> {}
13 pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<'a, '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)?;
564 // Some things needed for `sys::thread` initialization to go through.
565 "signal" | "sigaction" | "sigaltstack" => {
566 this.write_scalar(Scalar::from_int(0, dest.layout.size), dest)?;
570 let name = this.read_scalar(args[0])?.to_i32()?;
572 trace!("sysconf() called with name {}", name);
573 // Cache the sysconf integers via Miri's global cache.
575 (&["libc", "_SC_PAGESIZE"], Scalar::from_int(4096, dest.layout.size)),
576 (&["libc", "_SC_GETPW_R_SIZE_MAX"], Scalar::from_int(-1, dest.layout.size)),
577 (&["libc", "_SC_NPROCESSORS_ONLN"], Scalar::from_int(1, dest.layout.size)),
579 let mut result = None;
580 for &(path, path_value) in paths {
581 if let Some(val) = this.eval_path_scalar(path)? {
582 let val = val.to_i32()?;
584 result = Some(path_value);
590 if let Some(result) = result {
591 this.write_scalar(result, dest)?;
593 return err!(Unimplemented(
594 format!("Unimplemented sysconf name: {}", name),
600 this.write_null(dest)?;
603 // Hook pthread calls that go to the thread-local storage memory subsystem.
604 "pthread_key_create" => {
605 let key_ptr = this.read_scalar(args[0])?.to_ptr()?;
607 // Extract the function type out of the signature (that seems easier than constructing it ourselves).
608 let dtor = match this.read_scalar(args[1])?.not_undef()? {
609 Scalar::Ptr(dtor_ptr) => Some(this.memory().get_fn(dtor_ptr)?),
610 Scalar::Raw { data: 0, size } => {
612 assert_eq!(size as u64, this.memory().pointer_size().bytes());
615 Scalar::Raw { .. } => return err!(ReadBytesAsPointer),
618 // Figure out how large a pthread TLS key actually is.
619 // This is `libc::pthread_key_t`.
620 let key_type = args[0].layout.ty
622 .ok_or_else(|| InterpError::AbiViolation("wrong signature used for `pthread_key_create`: first argument must be a raw pointer.".to_owned()))?
624 let key_layout = this.layout_of(key_type)?;
626 // Create key and write it into the memory where `key_ptr` wants it.
627 let key = this.machine.tls.create_tls_key(dtor, tcx) as u128;
628 if key_layout.size.bits() < 128 && key >= (1u128 << key_layout.size.bits() as u128) {
629 return err!(OutOfTls);
632 this.memory().check_align(key_ptr.into(), key_layout.align.abi)?;
633 this.memory_mut().get_mut(key_ptr.alloc_id)?.write_scalar(
636 Scalar::from_uint(key, key_layout.size).into(),
640 // Return success (`0`).
641 this.write_null(dest)?;
643 "pthread_key_delete" => {
644 let key = this.read_scalar(args[0])?.to_bits(args[0].layout.size)?;
645 this.machine.tls.delete_tls_key(key)?;
646 // Return success (0)
647 this.write_null(dest)?;
649 "pthread_getspecific" => {
650 let key = this.read_scalar(args[0])?.to_bits(args[0].layout.size)?;
651 let ptr = this.machine.tls.load_tls(key)?;
652 this.write_scalar(ptr, dest)?;
654 "pthread_setspecific" => {
655 let key = this.read_scalar(args[0])?.to_bits(args[0].layout.size)?;
656 let new_ptr = this.read_scalar(args[1])?.not_undef()?;
657 this.machine.tls.store_tls(key, new_ptr)?;
659 // Return success (`0`).
660 this.write_null(dest)?;
663 // Determine stack base address.
664 "pthread_attr_init" | "pthread_attr_destroy" | "pthread_attr_get_np" |
665 "pthread_getattr_np" | "pthread_self" | "pthread_get_stacksize_np" => {
666 this.write_null(dest)?;
668 "pthread_attr_getstack" => {
669 // Second argument is where we are supposed to write the stack size.
670 let ptr = this.deref_operand(args[1])?;
672 let stack_addr = Scalar::from_int(0x80000, args[1].layout.size);
673 this.write_scalar(stack_addr, ptr.into())?;
674 // Return success (`0`).
675 this.write_null(dest)?;
677 "pthread_get_stackaddr_np" => {
679 let stack_addr = Scalar::from_int(0x80000, dest.layout.size);
680 this.write_scalar(stack_addr, dest)?;
683 // Stub out calls for condvar, mutex and rwlock, to just return `0`.
684 "pthread_mutexattr_init" | "pthread_mutexattr_settype" | "pthread_mutex_init" |
685 "pthread_mutexattr_destroy" | "pthread_mutex_lock" | "pthread_mutex_unlock" |
686 "pthread_mutex_destroy" | "pthread_rwlock_rdlock" | "pthread_rwlock_unlock" |
687 "pthread_rwlock_wrlock" | "pthread_rwlock_destroy" | "pthread_condattr_init" |
688 "pthread_condattr_setclock" | "pthread_cond_init" | "pthread_condattr_destroy" |
689 "pthread_cond_destroy" => {
690 this.write_null(dest)?;
693 // We don't support fork so we don't have to do anything for atfork.
694 "pthread_atfork" => {
695 this.write_null(dest)?;
699 // 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.
700 let addr = this.read_scalar(args[0])?.not_undef()?;
701 this.write_scalar(addr, dest)?;
704 this.write_null(dest)?;
709 // FIXME: register the destructor.
712 this.write_scalar(Scalar::Ptr(this.machine.argc.unwrap()), dest)?;
715 this.write_scalar(Scalar::Ptr(this.machine.argv.unwrap()), dest)?;
717 "SecRandomCopyBytes" => {
718 let len = this.read_scalar(args[1])?.to_usize(this)?;
719 let ptr = this.read_scalar(args[2])?.not_undef()?;
720 gen_random(this, len as usize, ptr)?;
721 this.write_null(dest)?;
724 // Windows API stubs.
726 // DWORD = ULONG = u32
728 "GetProcessHeap" => {
729 // Just fake a HANDLE
730 this.write_scalar(Scalar::from_int(1, this.pointer_size()), dest)?;
733 let _handle = this.read_scalar(args[0])?.to_isize(this)?;
734 let flags = this.read_scalar(args[1])?.to_u32()?;
735 let size = this.read_scalar(args[2])?.to_usize(this)?;
736 let zero_init = (flags & 0x00000008) != 0; // HEAP_ZERO_MEMORY
737 let res = this.malloc(size, zero_init);
738 this.write_scalar(res, dest)?;
741 let _handle = this.read_scalar(args[0])?.to_isize(this)?;
742 let _flags = this.read_scalar(args[1])?.to_u32()?;
743 let ptr = this.read_scalar(args[2])?.not_undef()?;
745 this.write_scalar(Scalar::from_int(1, Size::from_bytes(4)), dest)?;
748 let _handle = this.read_scalar(args[0])?.to_isize(this)?;
749 let _flags = this.read_scalar(args[1])?.to_u32()?;
750 let ptr = this.read_scalar(args[2])?.not_undef()?;
751 let size = this.read_scalar(args[3])?.to_usize(this)?;
752 let res = this.realloc(ptr, size)?;
753 this.write_scalar(res, dest)?;
757 let err = this.read_scalar(args[0])?.to_u32()?;
758 this.machine.last_error = err;
761 this.write_scalar(Scalar::from_u32(this.machine.last_error), dest)?;
764 "AddVectoredExceptionHandler" => {
765 // Any non zero value works for the stdlib. This is just used for stack overflows anyway.
766 this.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?;
768 "InitializeCriticalSection" |
769 "EnterCriticalSection" |
770 "LeaveCriticalSection" |
771 "DeleteCriticalSection" => {
772 // Nothing to do, not even a return value.
776 "TryEnterCriticalSection" |
777 "GetConsoleScreenBufferInfo" |
778 "SetConsoleTextAttribute" => {
779 // Pretend these do not exist / nothing happened, by returning zero.
780 this.write_null(dest)?;
783 let system_info = this.deref_operand(args[0])?;
784 let system_info_ptr = system_info.ptr.to_ptr()?;
785 // Initialize with `0`.
786 this.memory_mut().get_mut(system_info_ptr.alloc_id)?
787 .write_repeat(tcx, system_info_ptr, 0, system_info.layout.size)?;
788 // Set number of processors to `1`.
789 let dword_size = Size::from_bytes(4);
790 let offset = 2*dword_size + 3*tcx.pointer_size();
791 this.memory_mut().get_mut(system_info_ptr.alloc_id)?
794 system_info_ptr.offset(offset, tcx)?,
795 Scalar::from_int(1, dword_size).into(),
801 // This just creates a key; Windows does not natively support TLS destructors.
803 // Create key and return it.
804 let key = this.machine.tls.create_tls_key(None, tcx) as u128;
806 // Figure out how large a TLS key actually is. This is `c::DWORD`.
807 if dest.layout.size.bits() < 128
808 && key >= (1u128 << dest.layout.size.bits() as u128) {
809 return err!(OutOfTls);
811 this.write_scalar(Scalar::from_uint(key, dest.layout.size), dest)?;
814 let key = this.read_scalar(args[0])?.to_u32()? as u128;
815 let ptr = this.machine.tls.load_tls(key)?;
816 this.write_scalar(ptr, dest)?;
819 let key = this.read_scalar(args[0])?.to_u32()? as u128;
820 let new_ptr = this.read_scalar(args[1])?.not_undef()?;
821 this.machine.tls.store_tls(key, new_ptr)?;
823 // Return success (`1`).
824 this.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?;
827 let which = this.read_scalar(args[0])?.to_i32()?;
828 // We just make this the identity function, so we know later in `WriteFile`
830 this.write_scalar(Scalar::from_int(which, this.pointer_size()), dest)?;
833 let handle = this.read_scalar(args[0])?.to_isize(this)?;
834 let buf = this.read_scalar(args[1])?.not_undef()?;
835 let n = this.read_scalar(args[2])?.to_u32()?;
836 let written_place = this.deref_operand(args[3])?;
837 // Spec says to always write `0` first.
838 this.write_null(written_place.into())?;
839 let written = if handle == -11 || handle == -12 {
841 use std::io::{self, Write};
843 let buf_cont = this.memory().read_bytes(buf, Size::from_bytes(u64::from(n)))?;
844 let res = if handle == -11 {
845 io::stdout().write(buf_cont)
847 io::stderr().write(buf_cont)
849 res.ok().map(|n| n as u32)
851 eprintln!("Miri: Ignored output to handle {}", handle);
852 // Pretend it all went well.
855 // If there was no error, write back how much was written.
856 if let Some(n) = written {
857 this.write_scalar(Scalar::from_u32(n), written_place.into())?;
859 // Return whether this was a success.
861 Scalar::from_int(if written.is_some() { 1 } else { 0 }, dest.layout.size),
865 "GetConsoleMode" => {
866 // Everything is a pipe.
867 this.write_null(dest)?;
869 "GetEnvironmentVariableW" => {
870 // This is not the env var you are looking for.
871 this.machine.last_error = 203; // ERROR_ENVVAR_NOT_FOUND
872 this.write_null(dest)?;
874 "GetCommandLineW" => {
875 this.write_scalar(Scalar::Ptr(this.machine.cmd_line.unwrap()), dest)?;
877 // The actual name of 'RtlGenRandom'
878 "SystemFunction036" => {
879 let ptr = this.read_scalar(args[0])?.not_undef()?;
880 let len = this.read_scalar(args[1])?.to_u32()?;
881 gen_random(this, len as usize, ptr)?;
882 this.write_scalar(Scalar::from_bool(true), dest)?;
885 // We can't execute anything else.
887 return err!(Unimplemented(
888 format!("can't call foreign function: {}", link_name),
893 this.goto_block(Some(ret))?;
894 this.dump_place(*dest);
898 fn write_null(&mut self, dest: PlaceTy<'tcx, Tag>) -> InterpResult<'tcx> {
899 self.eval_context_mut().write_scalar(Scalar::from_int(0, dest.layout.size), dest)
902 /// Evaluates the scalar at the specified path. Returns Some(val)
903 /// if the path could be resolved, and None otherwise
904 fn eval_path_scalar(&mut self, path: &[&str]) -> InterpResult<'tcx, Option<ScalarMaybeUndef<Tag>>> {
905 let this = self.eval_context_mut();
906 if let Ok(instance) = this.resolve_path(path) {
911 let const_val = this.const_eval_raw(cid)?;
912 let const_val = this.read_scalar(const_val.into())?;
913 return Ok(Some(const_val));
919 fn gen_random<'a, 'mir, 'tcx>(
920 this: &mut MiriEvalContext<'a, 'mir, 'tcx>,
923 ) -> InterpResult<'tcx> {
928 let ptr = dest.to_ptr()?;
930 let data = match &mut this.machine.rng {
932 let mut data = vec![0; len];
933 rng.fill_bytes(&mut data);
937 return err!(Unimplemented(
938 "miri does not support gathering system entropy in deterministic mode!
939 Use '-Zmiri-seed=<seed>' to enable random number generation.
940 WARNING: Miri does *not* generate cryptographically secure entropy -
941 do not use Miri to run any program that needs secure random number generation".to_owned(),
945 let tcx = &{this.tcx.tcx};
946 this.memory_mut().get_mut(ptr.alloc_id)?
947 .write_bytes(tcx, ptr, &data)