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, Borrow>],
17 dest: Option<PlaceTy<'tcx, Borrow>>,
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, Borrow>],
59 dest: Option<PlaceTy<'tcx, Borrow>>,
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.with_default_tag()), 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()).with_default_tag();
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.with_default_tag()), 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(),
152 let size = this.read_scalar(args[0])?.to_usize(this)?;
153 let align = this.read_scalar(args[1])?.to_usize(this)?;
155 return err!(HeapAllocZeroBytes);
157 if !align.is_power_of_two() {
158 return err!(HeapAllocNonPowerOfTwoAlignment(align));
160 let ptr = this.memory_mut()
162 Size::from_bytes(size),
163 Align::from_bytes(align).unwrap(),
164 MiriMemoryKind::Rust.into()
167 this.write_scalar(Scalar::Ptr(ptr), dest)?;
169 "__rust_alloc_zeroed" => {
170 let size = this.read_scalar(args[0])?.to_usize(this)?;
171 let align = this.read_scalar(args[1])?.to_usize(this)?;
173 return err!(HeapAllocZeroBytes);
175 if !align.is_power_of_two() {
176 return err!(HeapAllocNonPowerOfTwoAlignment(align));
178 let ptr = this.memory_mut()
180 Size::from_bytes(size),
181 Align::from_bytes(align).unwrap(),
182 MiriMemoryKind::Rust.into()
186 .get_mut(ptr.alloc_id)?
187 .write_repeat(tcx, ptr, 0, Size::from_bytes(size))?;
188 this.write_scalar(Scalar::Ptr(ptr), dest)?;
190 "__rust_dealloc" => {
191 let ptr = this.read_scalar(args[0])?.to_ptr()?;
192 let old_size = this.read_scalar(args[1])?.to_usize(this)?;
193 let align = this.read_scalar(args[2])?.to_usize(this)?;
195 return err!(HeapAllocZeroBytes);
197 if !align.is_power_of_two() {
198 return err!(HeapAllocNonPowerOfTwoAlignment(align));
200 this.memory_mut().deallocate(
202 Some((Size::from_bytes(old_size), Align::from_bytes(align).unwrap())),
203 MiriMemoryKind::Rust.into(),
206 "__rust_realloc" => {
207 let ptr = this.read_scalar(args[0])?.to_ptr()?;
208 let old_size = this.read_scalar(args[1])?.to_usize(this)?;
209 let align = this.read_scalar(args[2])?.to_usize(this)?;
210 let new_size = this.read_scalar(args[3])?.to_usize(this)?;
211 if old_size == 0 || new_size == 0 {
212 return err!(HeapAllocZeroBytes);
214 if !align.is_power_of_two() {
215 return err!(HeapAllocNonPowerOfTwoAlignment(align));
217 let new_ptr = this.memory_mut().reallocate(
219 Size::from_bytes(old_size),
220 Align::from_bytes(align).unwrap(),
221 Size::from_bytes(new_size),
222 Align::from_bytes(align).unwrap(),
223 MiriMemoryKind::Rust.into(),
225 this.write_scalar(Scalar::Ptr(new_ptr.with_default_tag()), dest)?;
229 let sys_getrandom = this.eval_path_scalar(&["libc", "SYS_getrandom"])?
230 .expect("Failed to get libc::SYS_getrandom")
233 // `libc::syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), GRND_NONBLOCK)`
234 // is called if a `HashMap` is created the regular way (e.g. HashMap<K, V>).
235 match this.read_scalar(args[0])?.to_usize(this)? {
236 id if id == sys_getrandom => {
237 let ptr = this.read_scalar(args[1])?.to_ptr()?;
238 let len = this.read_scalar(args[2])?.to_usize(this)?;
240 // The only supported flags are GRND_RANDOM and GRND_NONBLOCK,
241 // neither of which have any effect on our current PRNG
242 let _flags = this.read_scalar(args[3])?.to_i32()?;
244 let data = gen_random(this, len as usize)?;
245 this.memory_mut().get_mut(ptr.alloc_id)?
246 .write_bytes(tcx, ptr, &data)?;
248 this.write_scalar(Scalar::from_uint(len, dest.layout.size), dest)?;
251 return err!(Unimplemented(
252 format!("miri does not support syscall ID {}", id),
259 let _handle = this.read_scalar(args[0])?;
260 let symbol = this.read_scalar(args[1])?.to_ptr()?;
261 let symbol_name = this.memory().get(symbol.alloc_id)?.read_c_str(tcx, symbol)?;
262 let err = format!("bad c unicode symbol: {:?}", symbol_name);
263 let symbol_name = ::std::str::from_utf8(symbol_name).unwrap_or(&err);
264 return err!(Unimplemented(format!(
265 "miri does not support dynamically loading libraries (requested symbol: {})",
270 "__rust_maybe_catch_panic" => {
271 // fn __rust_maybe_catch_panic(
274 // data_ptr: *mut usize,
275 // vtable_ptr: *mut usize,
277 // We abort on panic, so not much is going on here, but we still have to call the closure.
278 let f = this.read_scalar(args[0])?.to_ptr()?;
279 let data = this.read_scalar(args[1])?.not_undef()?;
280 let f_instance = this.memory().get_fn(f)?;
281 this.write_null(dest)?;
282 trace!("__rust_maybe_catch_panic: {:?}", f_instance);
284 // Now we make a function call.
285 // TODO: consider making this reusable? `InterpretCx::step` does something similar
286 // for the TLS destructors, and of course `eval_main`.
287 let mir = this.load_mir(f_instance.def)?;
288 let ret_place = MPlaceTy::dangling(this.layout_of(this.tcx.mk_unit())?, this).into();
289 this.push_stack_frame(
294 // Directly return to caller.
295 StackPopCleanup::Goto(Some(ret)),
297 let mut args = this.frame().mir.args_iter();
299 let arg_local = args.next().ok_or_else(||
300 InterpError::AbiViolation(
301 "Argument to __rust_maybe_catch_panic does not take enough arguments."
305 let arg_dest = this.eval_place(&mir::Place::Base(mir::PlaceBase::Local(arg_local)))?;
306 this.write_scalar(data, arg_dest)?;
308 assert!(args.next().is_none(), "__rust_maybe_catch_panic argument has more arguments than expected");
310 // We ourselves will return `0`, eventually (because we will not return if we paniced).
311 this.write_null(dest)?;
313 // Don't fall through, we do *not* want to `goto_block`!
318 let left = this.read_scalar(args[0])?.not_undef()?;
319 let right = this.read_scalar(args[1])?.not_undef()?;
320 let n = Size::from_bytes(this.read_scalar(args[2])?.to_usize(this)?);
323 let left_bytes = this.memory().read_bytes(left, n)?;
324 let right_bytes = this.memory().read_bytes(right, n)?;
326 use std::cmp::Ordering::*;
327 match left_bytes.cmp(right_bytes) {
335 Scalar::from_int(result, Size::from_bits(32)),
341 let ptr = this.read_scalar(args[0])?.not_undef()?;
342 let val = this.read_scalar(args[1])?.to_i32()? as u8;
343 let num = this.read_scalar(args[2])?.to_usize(this)?;
344 if let Some(idx) = this.memory().read_bytes(ptr, Size::from_bytes(num))?
345 .iter().rev().position(|&c| c == val)
347 let new_ptr = ptr.ptr_offset(Size::from_bytes(num - idx as u64 - 1), this)?;
348 this.write_scalar(new_ptr, dest)?;
350 this.write_null(dest)?;
355 let ptr = this.read_scalar(args[0])?.not_undef()?;
356 let val = this.read_scalar(args[1])?.to_i32()? as u8;
357 let num = this.read_scalar(args[2])?.to_usize(this)?;
360 .read_bytes(ptr, Size::from_bytes(num))?
362 .position(|&c| c == val);
363 if let Some(idx) = idx {
364 let new_ptr = ptr.ptr_offset(Size::from_bytes(idx as u64), this)?;
365 this.write_scalar(new_ptr, dest)?;
367 this.write_null(dest)?;
373 let name_ptr = this.read_scalar(args[0])?.to_ptr()?;
374 let name = this.memory().get(name_ptr.alloc_id)?.read_c_str(tcx, name_ptr)?;
375 match this.machine.env_vars.get(name) {
376 Some(&var) => Scalar::Ptr(var),
377 None => Scalar::ptr_null(&*this.tcx),
380 this.write_scalar(result, dest)?;
384 let mut success = None;
386 let name_ptr = this.read_scalar(args[0])?.not_undef()?;
387 if !name_ptr.is_null_ptr(this) {
388 let name_ptr = name_ptr.to_ptr()?;
391 .get(name_ptr.alloc_id)?
392 .read_c_str(tcx, name_ptr)?
394 if !name.is_empty() && !name.contains(&b'=') {
395 success = Some(this.machine.env_vars.remove(&name));
399 if let Some(old) = success {
400 if let Some(var) = old {
401 this.memory_mut().deallocate(var, None, MiriMemoryKind::Env.into())?;
403 this.write_null(dest)?;
405 this.write_scalar(Scalar::from_int(-1, dest.layout.size), dest)?;
412 let name_ptr = this.read_scalar(args[0])?.not_undef()?;
413 let value_ptr = this.read_scalar(args[1])?.to_ptr()?;
414 let value = this.memory().get(value_ptr.alloc_id)?.read_c_str(tcx, value_ptr)?;
415 if !name_ptr.is_null_ptr(this) {
416 let name_ptr = name_ptr.to_ptr()?;
417 let name = this.memory().get(name_ptr.alloc_id)?.read_c_str(tcx, name_ptr)?;
418 if !name.is_empty() && !name.contains(&b'=') {
419 new = Some((name.to_owned(), value.to_owned()));
423 if let Some((name, value)) = new {
424 // `+1` for the null terminator.
425 let value_copy = this.memory_mut().allocate(
426 Size::from_bytes((value.len() + 1) as u64),
427 Align::from_bytes(1).unwrap(),
428 MiriMemoryKind::Env.into(),
429 ).with_default_tag();
431 let alloc = this.memory_mut().get_mut(value_copy.alloc_id)?;
432 alloc.write_bytes(tcx, value_copy, &value)?;
433 let trailing_zero_ptr = value_copy.offset(
434 Size::from_bytes(value.len() as u64),
437 alloc.write_bytes(tcx, trailing_zero_ptr, &[0])?;
439 if let Some(var) = this.machine.env_vars.insert(
444 this.memory_mut().deallocate(var, None, MiriMemoryKind::Env.into())?;
446 this.write_null(dest)?;
448 this.write_scalar(Scalar::from_int(-1, dest.layout.size), dest)?;
453 let fd = this.read_scalar(args[0])?.to_i32()?;
454 let buf = this.read_scalar(args[1])?.not_undef()?;
455 let n = this.read_scalar(args[2])?.to_usize(&*this.tcx)?;
456 trace!("Called write({:?}, {:?}, {:?})", fd, buf, n);
457 let result = if fd == 1 || fd == 2 {
459 use std::io::{self, Write};
461 let buf_cont = this.memory().read_bytes(buf, Size::from_bytes(n))?;
462 // We need to flush to make sure this actually appears on the screen
463 let res = if fd == 1 {
464 // Stdout is buffered, flush to make sure it appears on the screen.
465 // This is the write() syscall of the interpreted program, we want it
466 // to correspond to a write() syscall on the host -- there is no good
467 // in adding extra buffering here.
468 let res = io::stdout().write(buf_cont);
469 io::stdout().flush().unwrap();
472 // No need to flush, stderr is not buffered.
473 io::stderr().write(buf_cont)
480 eprintln!("Miri: Ignored output to FD {}", fd);
481 // Pretend it all went well.
484 // Now, `result` is the value we return back to the program.
486 Scalar::from_int(result, dest.layout.size),
492 let ptr = this.read_scalar(args[0])?.to_ptr()?;
493 let n = this.memory().get(ptr.alloc_id)?.read_c_str(tcx, ptr)?.len();
494 this.write_scalar(Scalar::from_uint(n as u64, dest.layout.size), dest)?;
497 // Some things needed for `sys::thread` initialization to go through.
498 "signal" | "sigaction" | "sigaltstack" => {
499 this.write_scalar(Scalar::from_int(0, dest.layout.size), dest)?;
503 let name = this.read_scalar(args[0])?.to_i32()?;
505 trace!("sysconf() called with name {}", name);
506 // Cache the sysconf integers via Miri's global cache.
508 (&["libc", "_SC_PAGESIZE"], Scalar::from_int(4096, dest.layout.size)),
509 (&["libc", "_SC_GETPW_R_SIZE_MAX"], Scalar::from_int(-1, dest.layout.size)),
510 (&["libc", "_SC_NPROCESSORS_ONLN"], Scalar::from_int(1, dest.layout.size)),
512 let mut result = None;
513 for &(path, path_value) in paths {
514 if let Some(val) = this.eval_path_scalar(path)? {
515 let val = val.to_i32()?;
517 result = Some(path_value);
523 if let Some(result) = result {
524 this.write_scalar(result, dest)?;
526 return err!(Unimplemented(
527 format!("Unimplemented sysconf name: {}", name),
533 this.write_null(dest)?;
536 // Hook pthread calls that go to the thread-local storage memory subsystem.
537 "pthread_key_create" => {
538 let key_ptr = this.read_scalar(args[0])?.to_ptr()?;
540 // Extract the function type out of the signature (that seems easier than constructing it ourselves).
541 let dtor = match this.read_scalar(args[1])?.not_undef()? {
542 Scalar::Ptr(dtor_ptr) => Some(this.memory().get_fn(dtor_ptr)?),
543 Scalar::Bits { bits: 0, size } => {
544 assert_eq!(size as u64, this.memory().pointer_size().bytes());
547 Scalar::Bits { .. } => return err!(ReadBytesAsPointer),
550 // Figure out how large a pthread TLS key actually is.
551 // This is `libc::pthread_key_t`.
552 let key_type = args[0].layout.ty
554 .ok_or_else(|| InterpError::AbiViolation("wrong signature used for `pthread_key_create`: first argument must be a raw pointer.".to_owned()))?
556 let key_layout = this.layout_of(key_type)?;
558 // Create key and write it into the memory where `key_ptr` wants it.
559 let key = this.machine.tls.create_tls_key(dtor, tcx) as u128;
560 if key_layout.size.bits() < 128 && key >= (1u128 << key_layout.size.bits() as u128) {
561 return err!(OutOfTls);
564 this.memory().check_align(key_ptr.into(), key_layout.align.abi)?;
565 this.memory_mut().get_mut(key_ptr.alloc_id)?.write_scalar(
568 Scalar::from_uint(key, key_layout.size).into(),
572 // Return success (`0`).
573 this.write_null(dest)?;
575 "pthread_key_delete" => {
576 let key = this.read_scalar(args[0])?.to_bits(args[0].layout.size)?;
577 this.machine.tls.delete_tls_key(key)?;
578 // Return success (0)
579 this.write_null(dest)?;
581 "pthread_getspecific" => {
582 let key = this.read_scalar(args[0])?.to_bits(args[0].layout.size)?;
583 let ptr = this.machine.tls.load_tls(key)?;
584 this.write_scalar(ptr, dest)?;
586 "pthread_setspecific" => {
587 let key = this.read_scalar(args[0])?.to_bits(args[0].layout.size)?;
588 let new_ptr = this.read_scalar(args[1])?.not_undef()?;
589 this.machine.tls.store_tls(key, new_ptr)?;
591 // Return success (`0`).
592 this.write_null(dest)?;
595 // Determine stack base address.
596 "pthread_attr_init" | "pthread_attr_destroy" | "pthread_attr_get_np" |
597 "pthread_getattr_np" | "pthread_self" | "pthread_get_stacksize_np" => {
598 this.write_null(dest)?;
600 "pthread_attr_getstack" => {
601 // Second argument is where we are supposed to write the stack size.
602 let ptr = this.deref_operand(args[1])?;
604 let stack_addr = Scalar::from_int(0x80000, args[1].layout.size);
605 this.write_scalar(stack_addr, ptr.into())?;
606 // Return success (`0`).
607 this.write_null(dest)?;
609 "pthread_get_stackaddr_np" => {
611 let stack_addr = Scalar::from_int(0x80000, dest.layout.size);
612 this.write_scalar(stack_addr, dest)?;
615 // Stub out calls for condvar, mutex and rwlock, to just return `0`.
616 "pthread_mutexattr_init" | "pthread_mutexattr_settype" | "pthread_mutex_init" |
617 "pthread_mutexattr_destroy" | "pthread_mutex_lock" | "pthread_mutex_unlock" |
618 "pthread_mutex_destroy" | "pthread_rwlock_rdlock" | "pthread_rwlock_unlock" |
619 "pthread_rwlock_wrlock" | "pthread_rwlock_destroy" | "pthread_condattr_init" |
620 "pthread_condattr_setclock" | "pthread_cond_init" | "pthread_condattr_destroy" |
621 "pthread_cond_destroy" => {
622 this.write_null(dest)?;
626 // 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.
627 let addr = this.read_scalar(args[0])?.not_undef()?;
628 this.write_scalar(addr, dest)?;
631 this.write_null(dest)?;
636 // FIXME: register the destructor.
639 this.write_scalar(Scalar::Ptr(this.machine.argc.unwrap()), dest)?;
642 this.write_scalar(Scalar::Ptr(this.machine.argv.unwrap()), dest)?;
645 // Windows API stubs.
647 let err = this.read_scalar(args[0])?.to_u32()?;
648 this.machine.last_error = err;
651 this.write_scalar(Scalar::from_uint(this.machine.last_error, Size::from_bits(32)), dest)?;
654 "AddVectoredExceptionHandler" => {
655 // Any non zero value works for the stdlib. This is just used for stack overflows anyway.
656 this.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?;
658 "InitializeCriticalSection" |
659 "EnterCriticalSection" |
660 "LeaveCriticalSection" |
661 "DeleteCriticalSection" => {
662 // Nothing to do, not even a return value.
666 "TryEnterCriticalSection" |
667 "GetConsoleScreenBufferInfo" |
668 "SetConsoleTextAttribute" => {
669 // Pretend these do not exist / nothing happened, by returning zero.
670 this.write_null(dest)?;
673 let system_info = this.deref_operand(args[0])?;
674 let system_info_ptr = system_info.ptr.to_ptr()?;
675 // Initialize with `0`.
676 this.memory_mut().get_mut(system_info_ptr.alloc_id)?
677 .write_repeat(tcx, system_info_ptr, 0, system_info.layout.size)?;
678 // Set number of processors to `1`.
679 let dword_size = Size::from_bytes(4);
680 let offset = 2*dword_size + 3*tcx.pointer_size();
681 this.memory_mut().get_mut(system_info_ptr.alloc_id)?
684 system_info_ptr.offset(offset, tcx)?,
685 Scalar::from_int(1, dword_size).into(),
691 // This just creates a key; Windows does not natively support TLS destructors.
693 // Create key and return it.
694 let key = this.machine.tls.create_tls_key(None, tcx) as u128;
696 // Figure out how large a TLS key actually is. This is `c::DWORD`.
697 if dest.layout.size.bits() < 128
698 && key >= (1u128 << dest.layout.size.bits() as u128) {
699 return err!(OutOfTls);
701 this.write_scalar(Scalar::from_uint(key, dest.layout.size), dest)?;
704 let key = this.read_scalar(args[0])?.to_u32()? as u128;
705 let ptr = this.machine.tls.load_tls(key)?;
706 this.write_scalar(ptr, dest)?;
709 let key = this.read_scalar(args[0])?.to_u32()? as u128;
710 let new_ptr = this.read_scalar(args[1])?.not_undef()?;
711 this.machine.tls.store_tls(key, new_ptr)?;
713 // Return success (`1`).
714 this.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?;
717 let which = this.read_scalar(args[0])?.to_i32()?;
718 // We just make this the identity function, so we know later in `WriteFile`
720 this.write_scalar(Scalar::from_int(which, this.pointer_size()), dest)?;
723 let handle = this.read_scalar(args[0])?.to_isize(this)?;
724 let buf = this.read_scalar(args[1])?.not_undef()?;
725 let n = this.read_scalar(args[2])?.to_u32()?;
726 let written_place = this.deref_operand(args[3])?;
727 // Spec says to always write `0` first.
728 this.write_null(written_place.into())?;
729 let written = if handle == -11 || handle == -12 {
731 use std::io::{self, Write};
733 let buf_cont = this.memory().read_bytes(buf, Size::from_bytes(u64::from(n)))?;
734 let res = if handle == -11 {
735 io::stdout().write(buf_cont)
737 io::stderr().write(buf_cont)
739 res.ok().map(|n| n as u32)
741 eprintln!("Miri: Ignored output to handle {}", handle);
742 // Pretend it all went well.
745 // If there was no error, write back how much was written.
746 if let Some(n) = written {
747 this.write_scalar(Scalar::from_uint(n, Size::from_bits(32)), written_place.into())?;
749 // Return whether this was a success.
751 Scalar::from_int(if written.is_some() { 1 } else { 0 }, dest.layout.size),
755 "GetConsoleMode" => {
756 // Everything is a pipe.
757 this.write_null(dest)?;
759 "GetEnvironmentVariableW" => {
760 // This is not the env var you are looking for.
761 this.machine.last_error = 203; // ERROR_ENVVAR_NOT_FOUND
762 this.write_null(dest)?;
764 "GetCommandLineW" => {
765 this.write_scalar(Scalar::Ptr(this.machine.cmd_line.unwrap()), dest)?;
767 // The actual name of 'RtlGenRandom'
768 "SystemFunction036" => {
769 let ptr = this.read_scalar(args[0])?.to_ptr()?;
770 let len = this.read_scalar(args[1])?.to_usize(this)?;
772 let data = gen_random(this, len as usize)?;
773 this.memory_mut().get_mut(ptr.alloc_id)?
774 .write_bytes(tcx, ptr, &data)?;
776 this.write_scalar(Scalar::from_bool(true), dest)?;
779 // We can't execute anything else.
781 return err!(Unimplemented(
782 format!("can't call foreign function: {}", link_name),
787 this.goto_block(Some(ret))?;
788 this.dump_place(*dest);
792 fn write_null(&mut self, dest: PlaceTy<'tcx, Borrow>) -> EvalResult<'tcx> {
793 self.eval_context_mut().write_scalar(Scalar::from_int(0, dest.layout.size), dest)
796 /// Evaluates the scalar at the specified path. Returns Some(val)
797 /// if the path could be resolved, and None otherwise
798 fn eval_path_scalar(&mut self, path: &[&str]) -> EvalResult<'tcx, Option<ScalarMaybeUndef<stacked_borrows::Borrow>>> {
799 let this = self.eval_context_mut();
800 if let Ok(instance) = this.resolve_path(path) {
805 let const_val = this.const_eval_raw(cid)?;
806 let const_val = this.read_scalar(const_val.into())?;
807 return Ok(Some(const_val));
813 fn gen_random<'a, 'mir, 'tcx>(
814 this: &mut MiriEvalContext<'a, 'mir, 'tcx>,
816 ) -> Result<Vec<u8>, EvalError<'tcx>> {
818 match &mut this.machine.rng {
820 let mut data = vec![0; len];
821 rng.fill_bytes(&mut data);
826 "miri does not support gathering system entropy in deterministic mode!
827 Use '-Zmiri-seed=<seed>' to enable random number generation.
828 WARNING: Miri does *not* generate cryptographically secure entropy -
829 do not use Miri to run any program that needs secure random number generation".to_owned(),