2 use rustc::ty::layout::{Align, LayoutOf, Size};
3 use rustc::hir::def_id::DefId;
11 impl<'a, 'mir, 'tcx> EvalContextExt<'a, 'mir, 'tcx> for crate::MiriEvalContext<'a, 'mir, 'tcx> {}
12 pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<'a, 'mir, 'tcx> {
15 instance: ty::Instance<'tcx>,
16 args: &[OpTy<'tcx, Tag>],
17 dest: Option<PlaceTy<'tcx, Tag>>,
18 ret: Option<mir::BasicBlock>,
19 ) -> EvalResult<'tcx, Option<&'mir mir::Mir<'tcx>>> {
20 let this = self.eval_context_mut();
21 trace!("eval_fn_call: {:#?}, {:?}", instance, dest.map(|place| *place));
23 // First, run the common hooks also supported by CTFE.
24 if this.hook_fn(instance, args, dest)? {
25 this.goto_block(ret)?;
28 // There are some more lang items we want to hook that CTFE does not hook (yet).
29 if this.tcx.lang_items().align_offset_fn() == Some(instance.def.def_id()) {
30 // FIXME: return a real value in case the target allocation has an
31 // alignment bigger than the one requested.
32 let n = u128::max_value();
33 let dest = dest.unwrap();
34 let n = this.truncate(n, dest.layout);
35 this.write_scalar(Scalar::from_uint(n, dest.layout.size), dest)?;
36 this.goto_block(ret)?;
40 // Try to see if we can do something about foreign items.
41 if this.tcx.is_foreign_item(instance.def_id()) {
42 // An external function that we cannot find MIR for, but we can still run enough
43 // of them to make miri viable.
44 this.emulate_foreign_item(instance.def_id(), args, dest, ret)?;
45 // `goto_block` already handled.
49 // Otherwise, load the MIR.
50 Ok(Some(this.load_mir(instance.def)?))
53 /// Emulates calling a foreign item, failing if the item is not supported.
54 /// This function will handle `goto_block` if needed.
55 fn emulate_foreign_item(
58 args: &[OpTy<'tcx, Tag>],
59 dest: Option<PlaceTy<'tcx, Tag>>,
60 ret: Option<mir::BasicBlock>,
61 ) -> EvalResult<'tcx> {
62 let this = self.eval_context_mut();
63 let attrs = this.tcx.get_attrs(def_id);
64 let link_name = match attr::first_attr_value_str_by_name(&attrs, "link_name") {
65 Some(name) => name.as_str(),
66 None => this.tcx.item_name(def_id).as_str(),
68 // Strip linker suffixes (seen on 32-bit macOS).
69 let link_name = link_name.get().trim_end_matches("$UNIX2003");
70 let tcx = &{this.tcx.tcx};
72 // First: functions that could diverge.
74 "__rust_start_panic" | "panic_impl" => {
75 return err!(MachineError("the evaluated program panicked".to_string()));
77 _ => if dest.is_none() {
78 return err!(Unimplemented(
79 format!("can't call diverging foreign function: {}", link_name),
84 // Next: functions that assume a ret and dest.
85 let dest = dest.expect("we already checked for a dest");
86 let ret = ret.expect("dest is `Some` but ret is `None`");
89 let size = this.read_scalar(args[0])?.to_usize(this)?;
91 this.write_null(dest)?;
93 let align = this.tcx.data_layout.pointer_align.abi;
94 let ptr = this.memory_mut().allocate(Size::from_bytes(size), align, MiriMemoryKind::C.into());
95 this.write_scalar(Scalar::Ptr(ptr), dest)?;
99 let items = this.read_scalar(args[0])?.to_usize(this)?;
100 let len = this.read_scalar(args[1])?.to_usize(this)?;
101 let bytes = items.checked_mul(len).ok_or_else(|| InterpError::Overflow(mir::BinOp::Mul))?;
104 this.write_null(dest)?;
106 let size = Size::from_bytes(bytes);
107 let align = this.tcx.data_layout.pointer_align.abi;
108 let ptr = this.memory_mut().allocate(size, align, MiriMemoryKind::C.into());
109 this.memory_mut().get_mut(ptr.alloc_id)?.write_repeat(tcx, ptr, 0, size)?;
110 this.write_scalar(Scalar::Ptr(ptr), dest)?;
113 "posix_memalign" => {
114 let ret = this.deref_operand(args[0])?;
115 let align = this.read_scalar(args[1])?.to_usize(this)?;
116 let size = this.read_scalar(args[2])?.to_usize(this)?;
117 // Align must be power of 2, and also at least ptr-sized (POSIX rules).
118 if !align.is_power_of_two() {
119 return err!(HeapAllocNonPowerOfTwoAlignment(align));
121 if align < this.pointer_size().bytes() {
122 return err!(MachineError(format!(
123 "posix_memalign: alignment must be at least the size of a pointer, but is {}",
128 this.write_null(ret.into())?;
130 let ptr = this.memory_mut().allocate(
131 Size::from_bytes(size),
132 Align::from_bytes(align).unwrap(),
133 MiriMemoryKind::C.into()
135 this.write_scalar(Scalar::Ptr(ptr), ret.into())?;
137 this.write_null(dest)?;
141 let ptr = this.read_scalar(args[0])?.not_undef()?;
142 if !ptr.is_null_ptr(this) {
143 this.memory_mut().deallocate(
146 MiriMemoryKind::C.into(),
151 let old_ptr = this.read_scalar(args[0])?.not_undef()?;
152 let new_size = this.read_scalar(args[1])?.to_usize(this)?;
153 let align = this.tcx.data_layout.pointer_align.abi;
154 if old_ptr.is_null_ptr(this) {
156 this.write_null(dest)?;
158 let new_ptr = this.memory_mut().allocate(
159 Size::from_bytes(new_size),
161 MiriMemoryKind::C.into()
163 this.write_scalar(Scalar::Ptr(new_ptr), dest)?;
166 let old_ptr = old_ptr.to_ptr()?;
167 let memory = this.memory_mut();
168 let old_size = Size::from_bytes(memory.get(old_ptr.alloc_id)?.bytes.len() as u64);
172 Some((old_size, align)),
173 MiriMemoryKind::C.into(),
175 this.write_null(dest)?;
177 let new_ptr = memory.reallocate(
181 Size::from_bytes(new_size),
183 MiriMemoryKind::C.into(),
185 this.write_scalar(Scalar::Ptr(new_ptr), dest)?;
191 let size = this.read_scalar(args[0])?.to_usize(this)?;
192 let align = this.read_scalar(args[1])?.to_usize(this)?;
194 return err!(HeapAllocZeroBytes);
196 if !align.is_power_of_two() {
197 return err!(HeapAllocNonPowerOfTwoAlignment(align));
199 let ptr = this.memory_mut()
201 Size::from_bytes(size),
202 Align::from_bytes(align).unwrap(),
203 MiriMemoryKind::Rust.into()
205 this.write_scalar(Scalar::Ptr(ptr), dest)?;
207 "__rust_alloc_zeroed" => {
208 let size = this.read_scalar(args[0])?.to_usize(this)?;
209 let align = this.read_scalar(args[1])?.to_usize(this)?;
211 return err!(HeapAllocZeroBytes);
213 if !align.is_power_of_two() {
214 return err!(HeapAllocNonPowerOfTwoAlignment(align));
216 let ptr = this.memory_mut()
218 Size::from_bytes(size),
219 Align::from_bytes(align).unwrap(),
220 MiriMemoryKind::Rust.into()
223 .get_mut(ptr.alloc_id)?
224 .write_repeat(tcx, ptr, 0, Size::from_bytes(size))?;
225 this.write_scalar(Scalar::Ptr(ptr), dest)?;
227 "__rust_dealloc" => {
228 let ptr = this.read_scalar(args[0])?.to_ptr()?;
229 let old_size = this.read_scalar(args[1])?.to_usize(this)?;
230 let align = this.read_scalar(args[2])?.to_usize(this)?;
232 return err!(HeapAllocZeroBytes);
234 if !align.is_power_of_two() {
235 return err!(HeapAllocNonPowerOfTwoAlignment(align));
237 this.memory_mut().deallocate(
239 Some((Size::from_bytes(old_size), Align::from_bytes(align).unwrap())),
240 MiriMemoryKind::Rust.into(),
243 "__rust_realloc" => {
244 let ptr = this.read_scalar(args[0])?.to_ptr()?;
245 let old_size = this.read_scalar(args[1])?.to_usize(this)?;
246 let align = this.read_scalar(args[2])?.to_usize(this)?;
247 let new_size = this.read_scalar(args[3])?.to_usize(this)?;
248 if old_size == 0 || new_size == 0 {
249 return err!(HeapAllocZeroBytes);
251 if !align.is_power_of_two() {
252 return err!(HeapAllocNonPowerOfTwoAlignment(align));
254 let new_ptr = this.memory_mut().reallocate(
256 Size::from_bytes(old_size),
257 Align::from_bytes(align).unwrap(),
258 Size::from_bytes(new_size),
259 Align::from_bytes(align).unwrap(),
260 MiriMemoryKind::Rust.into(),
262 this.write_scalar(Scalar::Ptr(new_ptr), dest)?;
266 let sys_getrandom = this.eval_path_scalar(&["libc", "SYS_getrandom"])?
267 .expect("Failed to get libc::SYS_getrandom")
270 // `libc::syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), GRND_NONBLOCK)`
271 // is called if a `HashMap` is created the regular way (e.g. HashMap<K, V>).
272 match this.read_scalar(args[0])?.to_usize(this)? {
273 id if id == sys_getrandom => {
274 let ptr = this.read_scalar(args[1])?.to_ptr()?;
275 let len = this.read_scalar(args[2])?.to_usize(this)?;
277 // The only supported flags are GRND_RANDOM and GRND_NONBLOCK,
278 // neither of which have any effect on our current PRNG
279 let _flags = this.read_scalar(args[3])?.to_i32()?;
282 let data = gen_random(this, len as usize)?;
283 this.memory_mut().get_mut(ptr.alloc_id)?
284 .write_bytes(tcx, ptr, &data)?;
287 this.write_scalar(Scalar::from_uint(len, dest.layout.size), dest)?;
290 return err!(Unimplemented(
291 format!("miri does not support syscall ID {}", id),
298 let _handle = this.read_scalar(args[0])?;
299 let symbol = this.read_scalar(args[1])?.to_ptr()?;
300 let symbol_name = this.memory().get(symbol.alloc_id)?.read_c_str(tcx, symbol)?;
301 let err = format!("bad c unicode symbol: {:?}", symbol_name);
302 let symbol_name = ::std::str::from_utf8(symbol_name).unwrap_or(&err);
303 return err!(Unimplemented(format!(
304 "miri does not support dynamically loading libraries (requested symbol: {})",
309 "__rust_maybe_catch_panic" => {
310 // fn __rust_maybe_catch_panic(
313 // data_ptr: *mut usize,
314 // vtable_ptr: *mut usize,
316 // We abort on panic, so not much is going on here, but we still have to call the closure.
317 let f = this.read_scalar(args[0])?.to_ptr()?;
318 let data = this.read_scalar(args[1])?.not_undef()?;
319 let f_instance = this.memory().get_fn(f)?;
320 this.write_null(dest)?;
321 trace!("__rust_maybe_catch_panic: {:?}", f_instance);
323 // Now we make a function call.
324 // TODO: consider making this reusable? `InterpretCx::step` does something similar
325 // for the TLS destructors, and of course `eval_main`.
326 let mir = this.load_mir(f_instance.def)?;
327 let ret_place = MPlaceTy::dangling(this.layout_of(this.tcx.mk_unit())?, this).into();
328 this.push_stack_frame(
333 // Directly return to caller.
334 StackPopCleanup::Goto(Some(ret)),
336 let mut args = this.frame().mir.args_iter();
338 let arg_local = args.next().ok_or_else(||
339 InterpError::AbiViolation(
340 "Argument to __rust_maybe_catch_panic does not take enough arguments."
344 let arg_dest = this.eval_place(&mir::Place::Base(mir::PlaceBase::Local(arg_local)))?;
345 this.write_scalar(data, arg_dest)?;
347 assert!(args.next().is_none(), "__rust_maybe_catch_panic argument has more arguments than expected");
349 // We ourselves will return `0`, eventually (because we will not return if we paniced).
350 this.write_null(dest)?;
352 // Don't fall through, we do *not* want to `goto_block`!
357 let left = this.read_scalar(args[0])?.not_undef()?;
358 let right = this.read_scalar(args[1])?.not_undef()?;
359 let n = Size::from_bytes(this.read_scalar(args[2])?.to_usize(this)?);
362 let left_bytes = this.memory().read_bytes(left, n)?;
363 let right_bytes = this.memory().read_bytes(right, n)?;
365 use std::cmp::Ordering::*;
366 match left_bytes.cmp(right_bytes) {
374 Scalar::from_int(result, Size::from_bits(32)),
380 let ptr = this.read_scalar(args[0])?.not_undef()?;
381 let val = this.read_scalar(args[1])?.to_i32()? as u8;
382 let num = this.read_scalar(args[2])?.to_usize(this)?;
383 if let Some(idx) = this.memory().read_bytes(ptr, Size::from_bytes(num))?
384 .iter().rev().position(|&c| c == val)
386 let new_ptr = ptr.ptr_offset(Size::from_bytes(num - idx as u64 - 1), this)?;
387 this.write_scalar(new_ptr, dest)?;
389 this.write_null(dest)?;
394 let ptr = this.read_scalar(args[0])?.not_undef()?;
395 let val = this.read_scalar(args[1])?.to_i32()? as u8;
396 let num = this.read_scalar(args[2])?.to_usize(this)?;
399 .read_bytes(ptr, Size::from_bytes(num))?
401 .position(|&c| c == val);
402 if let Some(idx) = idx {
403 let new_ptr = ptr.ptr_offset(Size::from_bytes(idx as u64), this)?;
404 this.write_scalar(new_ptr, dest)?;
406 this.write_null(dest)?;
412 let name_ptr = this.read_scalar(args[0])?.to_ptr()?;
413 let name = this.memory().get(name_ptr.alloc_id)?.read_c_str(tcx, name_ptr)?;
414 match this.machine.env_vars.get(name) {
415 Some(&var) => Scalar::Ptr(var),
416 None => Scalar::ptr_null(&*this.tcx),
419 this.write_scalar(result, dest)?;
423 let mut success = None;
425 let name_ptr = this.read_scalar(args[0])?.not_undef()?;
426 if !name_ptr.is_null_ptr(this) {
427 let name_ptr = name_ptr.to_ptr()?;
430 .get(name_ptr.alloc_id)?
431 .read_c_str(tcx, name_ptr)?
433 if !name.is_empty() && !name.contains(&b'=') {
434 success = Some(this.machine.env_vars.remove(&name));
438 if let Some(old) = success {
439 if let Some(var) = old {
440 this.memory_mut().deallocate(var, None, MiriMemoryKind::Env.into())?;
442 this.write_null(dest)?;
444 this.write_scalar(Scalar::from_int(-1, dest.layout.size), dest)?;
451 let name_ptr = this.read_scalar(args[0])?.not_undef()?;
452 let value_ptr = this.read_scalar(args[1])?.to_ptr()?;
453 let value = this.memory().get(value_ptr.alloc_id)?.read_c_str(tcx, value_ptr)?;
454 if !name_ptr.is_null_ptr(this) {
455 let name_ptr = name_ptr.to_ptr()?;
456 let name = this.memory().get(name_ptr.alloc_id)?.read_c_str(tcx, name_ptr)?;
457 if !name.is_empty() && !name.contains(&b'=') {
458 new = Some((name.to_owned(), value.to_owned()));
462 if let Some((name, value)) = new {
463 // `+1` for the null terminator.
464 let value_copy = this.memory_mut().allocate(
465 Size::from_bytes((value.len() + 1) as u64),
466 Align::from_bytes(1).unwrap(),
467 MiriMemoryKind::Env.into(),
470 let alloc = this.memory_mut().get_mut(value_copy.alloc_id)?;
471 alloc.write_bytes(tcx, value_copy, &value)?;
472 let trailing_zero_ptr = value_copy.offset(
473 Size::from_bytes(value.len() as u64),
476 alloc.write_bytes(tcx, trailing_zero_ptr, &[0])?;
478 if let Some(var) = this.machine.env_vars.insert(
483 this.memory_mut().deallocate(var, None, MiriMemoryKind::Env.into())?;
485 this.write_null(dest)?;
487 this.write_scalar(Scalar::from_int(-1, dest.layout.size), dest)?;
492 let fd = this.read_scalar(args[0])?.to_i32()?;
493 let buf = this.read_scalar(args[1])?.not_undef()?;
494 let n = this.read_scalar(args[2])?.to_usize(&*this.tcx)?;
495 trace!("Called write({:?}, {:?}, {:?})", fd, buf, n);
496 let result = if fd == 1 || fd == 2 {
498 use std::io::{self, Write};
500 let buf_cont = this.memory().read_bytes(buf, Size::from_bytes(n))?;
501 // We need to flush to make sure this actually appears on the screen
502 let res = if fd == 1 {
503 // Stdout is buffered, flush to make sure it appears on the screen.
504 // This is the write() syscall of the interpreted program, we want it
505 // to correspond to a write() syscall on the host -- there is no good
506 // in adding extra buffering here.
507 let res = io::stdout().write(buf_cont);
508 io::stdout().flush().unwrap();
511 // No need to flush, stderr is not buffered.
512 io::stderr().write(buf_cont)
519 eprintln!("Miri: Ignored output to FD {}", fd);
520 // Pretend it all went well.
523 // Now, `result` is the value we return back to the program.
525 Scalar::from_int(result, dest.layout.size),
531 let ptr = this.read_scalar(args[0])?.to_ptr()?;
532 let n = this.memory().get(ptr.alloc_id)?.read_c_str(tcx, ptr)?.len();
533 this.write_scalar(Scalar::from_uint(n as u64, dest.layout.size), dest)?;
536 // Some things needed for `sys::thread` initialization to go through.
537 "signal" | "sigaction" | "sigaltstack" => {
538 this.write_scalar(Scalar::from_int(0, dest.layout.size), dest)?;
542 let name = this.read_scalar(args[0])?.to_i32()?;
544 trace!("sysconf() called with name {}", name);
545 // Cache the sysconf integers via Miri's global cache.
547 (&["libc", "_SC_PAGESIZE"], Scalar::from_int(4096, dest.layout.size)),
548 (&["libc", "_SC_GETPW_R_SIZE_MAX"], Scalar::from_int(-1, dest.layout.size)),
549 (&["libc", "_SC_NPROCESSORS_ONLN"], Scalar::from_int(1, dest.layout.size)),
551 let mut result = None;
552 for &(path, path_value) in paths {
553 if let Some(val) = this.eval_path_scalar(path)? {
554 let val = val.to_i32()?;
556 result = Some(path_value);
562 if let Some(result) = result {
563 this.write_scalar(result, dest)?;
565 return err!(Unimplemented(
566 format!("Unimplemented sysconf name: {}", name),
572 this.write_null(dest)?;
575 // Hook pthread calls that go to the thread-local storage memory subsystem.
576 "pthread_key_create" => {
577 let key_ptr = this.read_scalar(args[0])?.to_ptr()?;
579 // Extract the function type out of the signature (that seems easier than constructing it ourselves).
580 let dtor = match this.read_scalar(args[1])?.not_undef()? {
581 Scalar::Ptr(dtor_ptr) => Some(this.memory().get_fn(dtor_ptr)?),
582 Scalar::Bits { bits: 0, size } => {
583 assert_eq!(size as u64, this.memory().pointer_size().bytes());
586 Scalar::Bits { .. } => return err!(ReadBytesAsPointer),
589 // Figure out how large a pthread TLS key actually is.
590 // This is `libc::pthread_key_t`.
591 let key_type = args[0].layout.ty
593 .ok_or_else(|| InterpError::AbiViolation("wrong signature used for `pthread_key_create`: first argument must be a raw pointer.".to_owned()))?
595 let key_layout = this.layout_of(key_type)?;
597 // Create key and write it into the memory where `key_ptr` wants it.
598 let key = this.machine.tls.create_tls_key(dtor, tcx) as u128;
599 if key_layout.size.bits() < 128 && key >= (1u128 << key_layout.size.bits() as u128) {
600 return err!(OutOfTls);
603 this.memory().check_align(key_ptr.into(), key_layout.align.abi)?;
604 this.memory_mut().get_mut(key_ptr.alloc_id)?.write_scalar(
607 Scalar::from_uint(key, key_layout.size).into(),
611 // Return success (`0`).
612 this.write_null(dest)?;
614 "pthread_key_delete" => {
615 let key = this.read_scalar(args[0])?.to_bits(args[0].layout.size)?;
616 this.machine.tls.delete_tls_key(key)?;
617 // Return success (0)
618 this.write_null(dest)?;
620 "pthread_getspecific" => {
621 let key = this.read_scalar(args[0])?.to_bits(args[0].layout.size)?;
622 let ptr = this.machine.tls.load_tls(key)?;
623 this.write_scalar(ptr, dest)?;
625 "pthread_setspecific" => {
626 let key = this.read_scalar(args[0])?.to_bits(args[0].layout.size)?;
627 let new_ptr = this.read_scalar(args[1])?.not_undef()?;
628 this.machine.tls.store_tls(key, new_ptr)?;
630 // Return success (`0`).
631 this.write_null(dest)?;
634 // Determine stack base address.
635 "pthread_attr_init" | "pthread_attr_destroy" | "pthread_attr_get_np" |
636 "pthread_getattr_np" | "pthread_self" | "pthread_get_stacksize_np" => {
637 this.write_null(dest)?;
639 "pthread_attr_getstack" => {
640 // Second argument is where we are supposed to write the stack size.
641 let ptr = this.deref_operand(args[1])?;
643 let stack_addr = Scalar::from_int(0x80000, args[1].layout.size);
644 this.write_scalar(stack_addr, ptr.into())?;
645 // Return success (`0`).
646 this.write_null(dest)?;
648 "pthread_get_stackaddr_np" => {
650 let stack_addr = Scalar::from_int(0x80000, dest.layout.size);
651 this.write_scalar(stack_addr, dest)?;
654 // Stub out calls for condvar, mutex and rwlock, to just return `0`.
655 "pthread_mutexattr_init" | "pthread_mutexattr_settype" | "pthread_mutex_init" |
656 "pthread_mutexattr_destroy" | "pthread_mutex_lock" | "pthread_mutex_unlock" |
657 "pthread_mutex_destroy" | "pthread_rwlock_rdlock" | "pthread_rwlock_unlock" |
658 "pthread_rwlock_wrlock" | "pthread_rwlock_destroy" | "pthread_condattr_init" |
659 "pthread_condattr_setclock" | "pthread_cond_init" | "pthread_condattr_destroy" |
660 "pthread_cond_destroy" => {
661 this.write_null(dest)?;
664 // We don't support fork so we don't have to do anything for atfork.
665 "pthread_atfork" => {
666 this.write_null(dest)?;
670 // 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.
671 let addr = this.read_scalar(args[0])?.not_undef()?;
672 this.write_scalar(addr, dest)?;
675 this.write_null(dest)?;
680 // FIXME: register the destructor.
683 this.write_scalar(Scalar::Ptr(this.machine.argc.unwrap()), dest)?;
686 this.write_scalar(Scalar::Ptr(this.machine.argv.unwrap()), dest)?;
689 // Windows API stubs.
691 let err = this.read_scalar(args[0])?.to_u32()?;
692 this.machine.last_error = err;
695 this.write_scalar(Scalar::from_uint(this.machine.last_error, Size::from_bits(32)), dest)?;
698 "AddVectoredExceptionHandler" => {
699 // Any non zero value works for the stdlib. This is just used for stack overflows anyway.
700 this.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?;
702 "InitializeCriticalSection" |
703 "EnterCriticalSection" |
704 "LeaveCriticalSection" |
705 "DeleteCriticalSection" => {
706 // Nothing to do, not even a return value.
710 "TryEnterCriticalSection" |
711 "GetConsoleScreenBufferInfo" |
712 "SetConsoleTextAttribute" => {
713 // Pretend these do not exist / nothing happened, by returning zero.
714 this.write_null(dest)?;
717 let system_info = this.deref_operand(args[0])?;
718 let system_info_ptr = system_info.ptr.to_ptr()?;
719 // Initialize with `0`.
720 this.memory_mut().get_mut(system_info_ptr.alloc_id)?
721 .write_repeat(tcx, system_info_ptr, 0, system_info.layout.size)?;
722 // Set number of processors to `1`.
723 let dword_size = Size::from_bytes(4);
724 let offset = 2*dword_size + 3*tcx.pointer_size();
725 this.memory_mut().get_mut(system_info_ptr.alloc_id)?
728 system_info_ptr.offset(offset, tcx)?,
729 Scalar::from_int(1, dword_size).into(),
735 // This just creates a key; Windows does not natively support TLS destructors.
737 // Create key and return it.
738 let key = this.machine.tls.create_tls_key(None, tcx) as u128;
740 // Figure out how large a TLS key actually is. This is `c::DWORD`.
741 if dest.layout.size.bits() < 128
742 && key >= (1u128 << dest.layout.size.bits() as u128) {
743 return err!(OutOfTls);
745 this.write_scalar(Scalar::from_uint(key, dest.layout.size), dest)?;
748 let key = this.read_scalar(args[0])?.to_u32()? as u128;
749 let ptr = this.machine.tls.load_tls(key)?;
750 this.write_scalar(ptr, dest)?;
753 let key = this.read_scalar(args[0])?.to_u32()? as u128;
754 let new_ptr = this.read_scalar(args[1])?.not_undef()?;
755 this.machine.tls.store_tls(key, new_ptr)?;
757 // Return success (`1`).
758 this.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?;
761 let which = this.read_scalar(args[0])?.to_i32()?;
762 // We just make this the identity function, so we know later in `WriteFile`
764 this.write_scalar(Scalar::from_int(which, this.pointer_size()), dest)?;
767 let handle = this.read_scalar(args[0])?.to_isize(this)?;
768 let buf = this.read_scalar(args[1])?.not_undef()?;
769 let n = this.read_scalar(args[2])?.to_u32()?;
770 let written_place = this.deref_operand(args[3])?;
771 // Spec says to always write `0` first.
772 this.write_null(written_place.into())?;
773 let written = if handle == -11 || handle == -12 {
775 use std::io::{self, Write};
777 let buf_cont = this.memory().read_bytes(buf, Size::from_bytes(u64::from(n)))?;
778 let res = if handle == -11 {
779 io::stdout().write(buf_cont)
781 io::stderr().write(buf_cont)
783 res.ok().map(|n| n as u32)
785 eprintln!("Miri: Ignored output to handle {}", handle);
786 // Pretend it all went well.
789 // If there was no error, write back how much was written.
790 if let Some(n) = written {
791 this.write_scalar(Scalar::from_uint(n, Size::from_bits(32)), written_place.into())?;
793 // Return whether this was a success.
795 Scalar::from_int(if written.is_some() { 1 } else { 0 }, dest.layout.size),
799 "GetConsoleMode" => {
800 // Everything is a pipe.
801 this.write_null(dest)?;
803 "GetEnvironmentVariableW" => {
804 // This is not the env var you are looking for.
805 this.machine.last_error = 203; // ERROR_ENVVAR_NOT_FOUND
806 this.write_null(dest)?;
808 "GetCommandLineW" => {
809 this.write_scalar(Scalar::Ptr(this.machine.cmd_line.unwrap()), dest)?;
811 // The actual name of 'RtlGenRandom'
812 "SystemFunction036" => {
813 let ptr = this.read_scalar(args[0])?.to_ptr()?;
814 let len = this.read_scalar(args[1])?.to_u32()?;
817 let data = gen_random(this, len as usize)?;
818 this.memory_mut().get_mut(ptr.alloc_id)?
819 .write_bytes(tcx, ptr, &data)?;
822 this.write_scalar(Scalar::from_bool(true), dest)?;
825 // We can't execute anything else.
827 return err!(Unimplemented(
828 format!("can't call foreign function: {}", link_name),
833 this.goto_block(Some(ret))?;
834 this.dump_place(*dest);
838 fn write_null(&mut self, dest: PlaceTy<'tcx, Tag>) -> EvalResult<'tcx> {
839 self.eval_context_mut().write_scalar(Scalar::from_int(0, dest.layout.size), dest)
842 /// Evaluates the scalar at the specified path. Returns Some(val)
843 /// if the path could be resolved, and None otherwise
844 fn eval_path_scalar(&mut self, path: &[&str]) -> EvalResult<'tcx, Option<ScalarMaybeUndef<Tag>>> {
845 let this = self.eval_context_mut();
846 if let Ok(instance) = this.resolve_path(path) {
851 let const_val = this.const_eval_raw(cid)?;
852 let const_val = this.read_scalar(const_val.into())?;
853 return Ok(Some(const_val));
859 fn gen_random<'a, 'mir, 'tcx>(
860 this: &mut MiriEvalContext<'a, 'mir, 'tcx>,
862 ) -> Result<Vec<u8>, EvalError<'tcx>> {
864 match &mut this.machine.rng {
866 let mut data = vec![0; len];
867 rng.fill_bytes(&mut data);
872 "miri does not support gathering system entropy in deterministic mode!
873 Use '-Zmiri-seed=<seed>' to enable random number generation.
874 WARNING: Miri does *not* generate cryptographically secure entropy -
875 do not use Miri to run any program that needs secure random number generation".to_owned(),