2 use rustc::ty::layout::{Align, LayoutOf, Size};
3 use rustc::hir::def_id::DefId;
9 impl<'a, 'mir, 'tcx> EvalContextExt<'a, 'mir, 'tcx> for crate::MiriEvalContext<'a, 'mir, 'tcx> {}
10 pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<'a, 'mir, 'tcx> {
13 instance: ty::Instance<'tcx>,
14 args: &[OpTy<'tcx, Borrow>],
15 dest: Option<PlaceTy<'tcx, Borrow>>,
16 ret: Option<mir::BasicBlock>,
17 ) -> EvalResult<'tcx, Option<&'mir mir::Mir<'tcx>>> {
18 let this = self.eval_context_mut();
19 trace!("eval_fn_call: {:#?}, {:?}", instance, dest.map(|place| *place));
21 // First, run the common hooks also supported by CTFE.
22 if this.hook_fn(instance, args, dest)? {
23 this.goto_block(ret)?;
26 // There are some more lang items we want to hook that CTFE does not hook (yet).
27 if this.tcx.lang_items().align_offset_fn() == Some(instance.def.def_id()) {
28 // FIXME: return a real value in case the target allocation has an
29 // alignment bigger than the one requested.
30 let n = u128::max_value();
31 let dest = dest.unwrap();
32 let n = this.truncate(n, dest.layout);
33 this.write_scalar(Scalar::from_uint(n, dest.layout.size), dest)?;
34 this.goto_block(ret)?;
38 // Try to see if we can do something about foreign items.
39 if this.tcx.is_foreign_item(instance.def_id()) {
40 // An external function that we cannot find MIR for, but we can still run enough
41 // of them to make miri viable.
42 this.emulate_foreign_item(instance.def_id(), args, dest, ret)?;
43 // `goto_block` already handled.
47 // Otherwise, load the MIR.
48 Ok(Some(this.load_mir(instance.def)?))
51 /// Emulates calling a foreign item, failing if the item is not supported.
52 /// This function will handle `goto_block` if needed.
53 fn emulate_foreign_item(
56 args: &[OpTy<'tcx, Borrow>],
57 dest: Option<PlaceTy<'tcx, Borrow>>,
58 ret: Option<mir::BasicBlock>,
59 ) -> EvalResult<'tcx> {
60 let this = self.eval_context_mut();
61 let attrs = this.tcx.get_attrs(def_id);
62 let link_name = match attr::first_attr_value_str_by_name(&attrs, "link_name") {
63 Some(name) => name.as_str().get(),
64 None => this.tcx.item_name(def_id).as_str().get(),
66 // Strip linker suffixes (seen on 32-bit macOS).
67 let link_name = link_name.trim_end_matches("$UNIX2003");
68 let tcx = &{this.tcx.tcx};
70 // First: functions that could diverge.
72 "__rust_start_panic" | "panic_impl" => {
73 return err!(MachineError("the evaluated program panicked".to_string()));
75 _ => if dest.is_none() {
76 return err!(Unimplemented(
77 format!("can't call diverging foreign function: {}", link_name),
82 // Next: functions that assume a ret and dest.
83 let dest = dest.expect("we already checked for a dest");
84 let ret = ret.expect("dest is `Some` but ret is `None`");
87 let size = this.read_scalar(args[0])?.to_usize(this)?;
89 this.write_null(dest)?;
91 let align = this.tcx.data_layout.pointer_align.abi;
92 let ptr = this.memory_mut().allocate(Size::from_bytes(size), align, MiriMemoryKind::C.into());
93 this.write_scalar(Scalar::Ptr(ptr.with_default_tag()), dest)?;
97 let ret = this.deref_operand(args[0])?;
98 let align = this.read_scalar(args[1])?.to_usize(this)?;
99 let size = this.read_scalar(args[2])?.to_usize(this)?;
100 // Align must be power of 2, and also at least ptr-sized (POSIX rules).
101 if !align.is_power_of_two() {
102 return err!(HeapAllocNonPowerOfTwoAlignment(align));
104 if align < this.pointer_size().bytes() {
105 return err!(MachineError(format!(
106 "posix_memalign: alignment must be at least the size of a pointer, but is {}",
111 this.write_null(ret.into())?;
113 let ptr = this.memory_mut().allocate(
114 Size::from_bytes(size),
115 Align::from_bytes(align).unwrap(),
116 MiriMemoryKind::C.into()
118 this.write_scalar(Scalar::Ptr(ptr.with_default_tag()), ret.into())?;
120 this.write_null(dest)?;
124 let ptr = this.read_scalar(args[0])?.not_undef()?;
125 if !ptr.is_null_ptr(this) {
126 this.memory_mut().deallocate(
129 MiriMemoryKind::C.into(),
135 let size = this.read_scalar(args[0])?.to_usize(this)?;
136 let align = this.read_scalar(args[1])?.to_usize(this)?;
138 return err!(HeapAllocZeroBytes);
140 if !align.is_power_of_two() {
141 return err!(HeapAllocNonPowerOfTwoAlignment(align));
143 let ptr = this.memory_mut()
145 Size::from_bytes(size),
146 Align::from_bytes(align).unwrap(),
147 MiriMemoryKind::Rust.into()
150 this.write_scalar(Scalar::Ptr(ptr), dest)?;
152 "__rust_alloc_zeroed" => {
153 let size = this.read_scalar(args[0])?.to_usize(this)?;
154 let align = this.read_scalar(args[1])?.to_usize(this)?;
156 return err!(HeapAllocZeroBytes);
158 if !align.is_power_of_two() {
159 return err!(HeapAllocNonPowerOfTwoAlignment(align));
161 let ptr = this.memory_mut()
163 Size::from_bytes(size),
164 Align::from_bytes(align).unwrap(),
165 MiriMemoryKind::Rust.into()
169 .get_mut(ptr.alloc_id)?
170 .write_repeat(tcx, ptr, 0, Size::from_bytes(size))?;
171 this.write_scalar(Scalar::Ptr(ptr), dest)?;
173 "__rust_dealloc" => {
174 let ptr = this.read_scalar(args[0])?.to_ptr()?;
175 let old_size = this.read_scalar(args[1])?.to_usize(this)?;
176 let align = this.read_scalar(args[2])?.to_usize(this)?;
178 return err!(HeapAllocZeroBytes);
180 if !align.is_power_of_two() {
181 return err!(HeapAllocNonPowerOfTwoAlignment(align));
183 this.memory_mut().deallocate(
185 Some((Size::from_bytes(old_size), Align::from_bytes(align).unwrap())),
186 MiriMemoryKind::Rust.into(),
189 "__rust_realloc" => {
190 let ptr = this.read_scalar(args[0])?.to_ptr()?;
191 let old_size = this.read_scalar(args[1])?.to_usize(this)?;
192 let align = this.read_scalar(args[2])?.to_usize(this)?;
193 let new_size = this.read_scalar(args[3])?.to_usize(this)?;
194 if old_size == 0 || new_size == 0 {
195 return err!(HeapAllocZeroBytes);
197 if !align.is_power_of_two() {
198 return err!(HeapAllocNonPowerOfTwoAlignment(align));
200 let new_ptr = this.memory_mut().reallocate(
202 Size::from_bytes(old_size),
203 Align::from_bytes(align).unwrap(),
204 Size::from_bytes(new_size),
205 Align::from_bytes(align).unwrap(),
206 MiriMemoryKind::Rust.into(),
208 this.write_scalar(Scalar::Ptr(new_ptr.with_default_tag()), dest)?;
212 // TODO: read `syscall` IDs like `sysconf` IDs and
213 // figure out some way to actually process some of them.
215 // `libc::syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), GRND_NONBLOCK)`
216 // is called if a `HashMap` is created the regular way.
217 match this.read_scalar(args[0])?.to_usize(this)? {
219 return err!(Unimplemented(
220 "miri does not support random number generators".to_owned(),
224 return err!(Unimplemented(
225 format!("miri does not support syscall ID {}", id),
232 let _handle = this.read_scalar(args[0])?;
233 let symbol = this.read_scalar(args[1])?.to_ptr()?;
234 let symbol_name = this.memory().get(symbol.alloc_id)?.read_c_str(tcx, symbol)?;
235 let err = format!("bad c unicode symbol: {:?}", symbol_name);
236 let symbol_name = ::std::str::from_utf8(symbol_name).unwrap_or(&err);
237 return err!(Unimplemented(format!(
238 "miri does not support dynamically loading libraries (requested symbol: {})",
243 "__rust_maybe_catch_panic" => {
244 // fn __rust_maybe_catch_panic(
247 // data_ptr: *mut usize,
248 // vtable_ptr: *mut usize,
250 // We abort on panic, so not much is going on here, but we still have to call the closure.
251 let f = this.read_scalar(args[0])?.to_ptr()?;
252 let data = this.read_scalar(args[1])?.not_undef()?;
253 let f_instance = this.memory().get_fn(f)?;
254 this.write_null(dest)?;
255 trace!("__rust_maybe_catch_panic: {:?}", f_instance);
257 // Now we make a function call.
258 // TODO: consider making this reusable? `InterpretCx::step` does something similar
259 // for the TLS destructors, and of course `eval_main`.
260 let mir = this.load_mir(f_instance.def)?;
261 let ret_place = MPlaceTy::dangling(this.layout_of(this.tcx.mk_unit())?, this).into();
262 this.push_stack_frame(
267 // Directly return to caller.
268 StackPopCleanup::Goto(Some(ret)),
270 let mut args = this.frame().mir.args_iter();
272 let arg_local = args.next().ok_or_else(||
273 InterpError::AbiViolation(
274 "Argument to __rust_maybe_catch_panic does not take enough arguments."
278 let arg_dest = this.eval_place(&mir::Place::Base(mir::PlaceBase::Local(arg_local)))?;
279 this.write_scalar(data, arg_dest)?;
281 assert!(args.next().is_none(), "__rust_maybe_catch_panic argument has more arguments than expected");
283 // We ourselves will return `0`, eventually (because we will not return if we paniced).
284 this.write_null(dest)?;
286 // Don't fall through, we do *not* want to `goto_block`!
291 let left = this.read_scalar(args[0])?.not_undef()?;
292 let right = this.read_scalar(args[1])?.not_undef()?;
293 let n = Size::from_bytes(this.read_scalar(args[2])?.to_usize(this)?);
296 let left_bytes = this.memory().read_bytes(left, n)?;
297 let right_bytes = this.memory().read_bytes(right, n)?;
299 use std::cmp::Ordering::*;
300 match left_bytes.cmp(right_bytes) {
308 Scalar::from_int(result, Size::from_bits(32)),
314 let ptr = this.read_scalar(args[0])?.not_undef()?;
315 let val = this.read_scalar(args[1])?.to_i32()? as u8;
316 let num = this.read_scalar(args[2])?.to_usize(this)?;
317 if let Some(idx) = this.memory().read_bytes(ptr, Size::from_bytes(num))?
318 .iter().rev().position(|&c| c == val)
320 let new_ptr = ptr.ptr_offset(Size::from_bytes(num - idx as u64 - 1), this)?;
321 this.write_scalar(new_ptr, dest)?;
323 this.write_null(dest)?;
328 let ptr = this.read_scalar(args[0])?.not_undef()?;
329 let val = this.read_scalar(args[1])?.to_i32()? as u8;
330 let num = this.read_scalar(args[2])?.to_usize(this)?;
333 .read_bytes(ptr, Size::from_bytes(num))?
335 .position(|&c| c == val);
336 if let Some(idx) = idx {
337 let new_ptr = ptr.ptr_offset(Size::from_bytes(idx as u64), this)?;
338 this.write_scalar(new_ptr, dest)?;
340 this.write_null(dest)?;
346 let name_ptr = this.read_scalar(args[0])?.to_ptr()?;
347 let name = this.memory().get(name_ptr.alloc_id)?.read_c_str(tcx, name_ptr)?;
348 match this.machine.env_vars.get(name) {
349 Some(&var) => Scalar::Ptr(var),
350 None => Scalar::ptr_null(&*this.tcx),
353 this.write_scalar(result, dest)?;
357 let mut success = None;
359 let name_ptr = this.read_scalar(args[0])?.not_undef()?;
360 if !name_ptr.is_null_ptr(this) {
361 let name_ptr = name_ptr.to_ptr()?;
364 .get(name_ptr.alloc_id)?
365 .read_c_str(tcx, name_ptr)?
367 if !name.is_empty() && !name.contains(&b'=') {
368 success = Some(this.machine.env_vars.remove(&name));
372 if let Some(old) = success {
373 if let Some(var) = old {
374 this.memory_mut().deallocate(var, None, MiriMemoryKind::Env.into())?;
376 this.write_null(dest)?;
378 this.write_scalar(Scalar::from_int(-1, dest.layout.size), dest)?;
385 let name_ptr = this.read_scalar(args[0])?.not_undef()?;
386 let value_ptr = this.read_scalar(args[1])?.to_ptr()?;
387 let value = this.memory().get(value_ptr.alloc_id)?.read_c_str(tcx, value_ptr)?;
388 if !name_ptr.is_null_ptr(this) {
389 let name_ptr = name_ptr.to_ptr()?;
390 let name = this.memory().get(name_ptr.alloc_id)?.read_c_str(tcx, name_ptr)?;
391 if !name.is_empty() && !name.contains(&b'=') {
392 new = Some((name.to_owned(), value.to_owned()));
396 if let Some((name, value)) = new {
397 // `+1` for the null terminator.
398 let value_copy = this.memory_mut().allocate(
399 Size::from_bytes((value.len() + 1) as u64),
400 Align::from_bytes(1).unwrap(),
401 MiriMemoryKind::Env.into(),
402 ).with_default_tag();
404 let alloc = this.memory_mut().get_mut(value_copy.alloc_id)?;
405 alloc.write_bytes(tcx, value_copy, &value)?;
406 let trailing_zero_ptr = value_copy.offset(
407 Size::from_bytes(value.len() as u64),
410 alloc.write_bytes(tcx, trailing_zero_ptr, &[0])?;
412 if let Some(var) = this.machine.env_vars.insert(
417 this.memory_mut().deallocate(var, None, MiriMemoryKind::Env.into())?;
419 this.write_null(dest)?;
421 this.write_scalar(Scalar::from_int(-1, dest.layout.size), dest)?;
426 let fd = this.read_scalar(args[0])?.to_i32()?;
427 let buf = this.read_scalar(args[1])?.not_undef()?;
428 let n = this.read_scalar(args[2])?.to_usize(&*this.tcx)?;
429 trace!("Called write({:?}, {:?}, {:?})", fd, buf, n);
430 let result = if fd == 1 || fd == 2 {
432 use std::io::{self, Write};
434 let buf_cont = this.memory().read_bytes(buf, Size::from_bytes(n))?;
435 // We need to flush to make sure this actually appears on the screen
436 let res = if fd == 1 {
437 // Stdout is buffered, flush to make sure it appears on the screen.
438 // This is the write() syscall of the interpreted program, we want it
439 // to correspond to a write() syscall on the host -- there is no good
440 // in adding extra buffering here.
441 let res = io::stdout().write(buf_cont);
442 io::stdout().flush().unwrap();
445 // No need to flush, stderr is not buffered.
446 io::stderr().write(buf_cont)
453 eprintln!("Miri: Ignored output to FD {}", fd);
454 // Pretend it all went well.
457 // Now, `result` is the value we return back to the program.
459 Scalar::from_int(result, dest.layout.size),
465 let ptr = this.read_scalar(args[0])?.to_ptr()?;
466 let n = this.memory().get(ptr.alloc_id)?.read_c_str(tcx, ptr)?.len();
467 this.write_scalar(Scalar::from_uint(n as u64, dest.layout.size), dest)?;
470 // Some things needed for `sys::thread` initialization to go through.
471 "signal" | "sigaction" | "sigaltstack" => {
472 this.write_scalar(Scalar::from_int(0, dest.layout.size), dest)?;
476 let name = this.read_scalar(args[0])?.to_i32()?;
478 trace!("sysconf() called with name {}", name);
479 // Cache the sysconf integers via Miri's global cache.
481 (&["libc", "_SC_PAGESIZE"], Scalar::from_int(4096, dest.layout.size)),
482 (&["libc", "_SC_GETPW_R_SIZE_MAX"], Scalar::from_int(-1, dest.layout.size)),
483 (&["libc", "_SC_NPROCESSORS_ONLN"], Scalar::from_int(1, dest.layout.size)),
485 let mut result = None;
486 for &(path, path_value) in paths {
487 if let Ok(instance) = this.resolve_path(path) {
492 let const_val = this.const_eval_raw(cid)?;
493 let const_val = this.read_scalar(const_val.into())?;
494 let value = const_val.to_i32()?;
496 result = Some(path_value);
501 if let Some(result) = result {
502 this.write_scalar(result, dest)?;
504 return err!(Unimplemented(
505 format!("Unimplemented sysconf name: {}", name),
511 this.write_null(dest)?;
514 // Hook pthread calls that go to the thread-local storage memory subsystem.
515 "pthread_key_create" => {
516 let key_ptr = this.read_scalar(args[0])?.to_ptr()?;
518 // Extract the function type out of the signature (that seems easier than constructing it ourselves).
519 let dtor = match this.read_scalar(args[1])?.not_undef()? {
520 Scalar::Ptr(dtor_ptr) => Some(this.memory().get_fn(dtor_ptr)?),
521 Scalar::Bits { bits: 0, size } => {
522 assert_eq!(size as u64, this.memory().pointer_size().bytes());
525 Scalar::Bits { .. } => return err!(ReadBytesAsPointer),
528 // Figure out how large a pthread TLS key actually is.
529 // This is `libc::pthread_key_t`.
530 let key_type = args[0].layout.ty
532 .ok_or_else(|| InterpError::AbiViolation("wrong signature used for `pthread_key_create`: first argument must be a raw pointer.".to_owned()))?
534 let key_layout = this.layout_of(key_type)?;
536 // Create key and write it into the memory where `key_ptr` wants it.
537 let key = this.machine.tls.create_tls_key(dtor, tcx) as u128;
538 if key_layout.size.bits() < 128 && key >= (1u128 << key_layout.size.bits() as u128) {
539 return err!(OutOfTls);
542 this.memory().check_align(key_ptr.into(), key_layout.align.abi)?;
543 this.memory_mut().get_mut(key_ptr.alloc_id)?.write_scalar(
546 Scalar::from_uint(key, key_layout.size).into(),
550 // Return success (`0`).
551 this.write_null(dest)?;
553 "pthread_key_delete" => {
554 let key = this.read_scalar(args[0])?.to_bits(args[0].layout.size)?;
555 this.machine.tls.delete_tls_key(key)?;
556 // Return success (0)
557 this.write_null(dest)?;
559 "pthread_getspecific" => {
560 let key = this.read_scalar(args[0])?.to_bits(args[0].layout.size)?;
561 let ptr = this.machine.tls.load_tls(key)?;
562 this.write_scalar(ptr, dest)?;
564 "pthread_setspecific" => {
565 let key = this.read_scalar(args[0])?.to_bits(args[0].layout.size)?;
566 let new_ptr = this.read_scalar(args[1])?.not_undef()?;
567 this.machine.tls.store_tls(key, new_ptr)?;
569 // Return success (`0`).
570 this.write_null(dest)?;
573 // Determine stack base address.
574 "pthread_attr_init" | "pthread_attr_destroy" | "pthread_attr_get_np" |
575 "pthread_getattr_np" | "pthread_self" | "pthread_get_stacksize_np" => {
576 this.write_null(dest)?;
578 "pthread_attr_getstack" => {
579 // Second argument is where we are supposed to write the stack size.
580 let ptr = this.deref_operand(args[1])?;
582 let stack_addr = Scalar::from_int(0x80000, args[1].layout.size);
583 this.write_scalar(stack_addr, ptr.into())?;
584 // Return success (`0`).
585 this.write_null(dest)?;
587 "pthread_get_stackaddr_np" => {
589 let stack_addr = Scalar::from_int(0x80000, dest.layout.size);
590 this.write_scalar(stack_addr, dest)?;
593 // Stub out calls for condvar, mutex and rwlock, to just return `0`.
594 "pthread_mutexattr_init" | "pthread_mutexattr_settype" | "pthread_mutex_init" |
595 "pthread_mutexattr_destroy" | "pthread_mutex_lock" | "pthread_mutex_unlock" |
596 "pthread_mutex_destroy" | "pthread_rwlock_rdlock" | "pthread_rwlock_unlock" |
597 "pthread_rwlock_wrlock" | "pthread_rwlock_destroy" | "pthread_condattr_init" |
598 "pthread_condattr_setclock" | "pthread_cond_init" | "pthread_condattr_destroy" |
599 "pthread_cond_destroy" => {
600 this.write_null(dest)?;
604 // 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.
605 let addr = this.read_scalar(args[0])?.not_undef()?;
606 this.write_scalar(addr, dest)?;
609 this.write_null(dest)?;
614 // FIXME: register the destructor.
617 this.write_scalar(Scalar::Ptr(this.machine.argc.unwrap()), dest)?;
620 this.write_scalar(Scalar::Ptr(this.machine.argv.unwrap()), dest)?;
623 // Windows API stubs.
625 let err = this.read_scalar(args[0])?.to_u32()?;
626 this.machine.last_error = err;
629 this.write_scalar(Scalar::from_uint(this.machine.last_error, Size::from_bits(32)), dest)?;
632 "AddVectoredExceptionHandler" => {
633 // Any non zero value works for the stdlib. This is just used for stack overflows anyway.
634 this.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?;
636 "InitializeCriticalSection" |
637 "EnterCriticalSection" |
638 "LeaveCriticalSection" |
639 "DeleteCriticalSection" => {
640 // Nothing to do, not even a return value.
644 "TryEnterCriticalSection" |
645 "GetConsoleScreenBufferInfo" |
646 "SetConsoleTextAttribute" => {
647 // Pretend these do not exist / nothing happened, by returning zero.
648 this.write_null(dest)?;
651 let system_info = this.deref_operand(args[0])?;
652 let system_info_ptr = system_info.ptr.to_ptr()?;
653 // Initialize with `0`.
654 this.memory_mut().get_mut(system_info_ptr.alloc_id)?
655 .write_repeat(tcx, system_info_ptr, 0, system_info.layout.size)?;
656 // Set number of processors to `1`.
657 let dword_size = Size::from_bytes(4);
658 let offset = 2*dword_size + 3*tcx.pointer_size();
659 this.memory_mut().get_mut(system_info_ptr.alloc_id)?
662 system_info_ptr.offset(offset, tcx)?,
663 Scalar::from_int(1, dword_size).into(),
669 // This just creates a key; Windows does not natively support TLS destructors.
671 // Create key and return it.
672 let key = this.machine.tls.create_tls_key(None, tcx) as u128;
674 // Figure out how large a TLS key actually is. This is `c::DWORD`.
675 if dest.layout.size.bits() < 128
676 && key >= (1u128 << dest.layout.size.bits() as u128) {
677 return err!(OutOfTls);
679 this.write_scalar(Scalar::from_uint(key, dest.layout.size), dest)?;
682 let key = this.read_scalar(args[0])?.to_u32()? as u128;
683 let ptr = this.machine.tls.load_tls(key)?;
684 this.write_scalar(ptr, dest)?;
687 let key = this.read_scalar(args[0])?.to_u32()? as u128;
688 let new_ptr = this.read_scalar(args[1])?.not_undef()?;
689 this.machine.tls.store_tls(key, new_ptr)?;
691 // Return success (`1`).
692 this.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?;
695 let which = this.read_scalar(args[0])?.to_i32()?;
696 // We just make this the identity function, so we know later in `WriteFile`
698 this.write_scalar(Scalar::from_int(which, this.pointer_size()), dest)?;
701 let handle = this.read_scalar(args[0])?.to_isize(this)?;
702 let buf = this.read_scalar(args[1])?.not_undef()?;
703 let n = this.read_scalar(args[2])?.to_u32()?;
704 let written_place = this.deref_operand(args[3])?;
705 // Spec says to always write `0` first.
706 this.write_null(written_place.into())?;
707 let written = if handle == -11 || handle == -12 {
709 use std::io::{self, Write};
711 let buf_cont = this.memory().read_bytes(buf, Size::from_bytes(u64::from(n)))?;
712 let res = if handle == -11 {
713 io::stdout().write(buf_cont)
715 io::stderr().write(buf_cont)
717 res.ok().map(|n| n as u32)
719 eprintln!("Miri: Ignored output to handle {}", handle);
720 // Pretend it all went well.
723 // If there was no error, write back how much was written.
724 if let Some(n) = written {
725 this.write_scalar(Scalar::from_uint(n, Size::from_bits(32)), written_place.into())?;
727 // Return whether this was a success.
729 Scalar::from_int(if written.is_some() { 1 } else { 0 }, dest.layout.size),
733 "GetConsoleMode" => {
734 // Everything is a pipe.
735 this.write_null(dest)?;
737 "GetEnvironmentVariableW" => {
738 // This is not the env var you are looking for.
739 this.machine.last_error = 203; // ERROR_ENVVAR_NOT_FOUND
740 this.write_null(dest)?;
742 "GetCommandLineW" => {
743 this.write_scalar(Scalar::Ptr(this.machine.cmd_line.unwrap()), dest)?;
746 // We can't execute anything else.
748 return err!(Unimplemented(
749 format!("can't call foreign function: {}", link_name),
754 this.goto_block(Some(ret))?;
755 this.dump_place(*dest);
759 fn write_null(&mut self, dest: PlaceTy<'tcx, Borrow>) -> EvalResult<'tcx> {
760 self.eval_context_mut().write_scalar(Scalar::from_int(0, dest.layout.size), dest)