3 use rustc::ty::layout::Size;
6 impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
7 pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
8 fn emulate_foreign_item_by_name(
11 args: &[OpTy<'tcx, Tag>],
12 dest: PlaceTy<'tcx, Tag>,
13 _ret: mir::BasicBlock,
14 ) -> InterpResult<'tcx, bool> {
15 let this = self.eval_context_mut();
16 let tcx = &{ this.tcx.tcx };
19 // Environment related shims
20 "GetEnvironmentVariableW" => {
21 // args[0] : LPCWSTR lpName (32-bit ptr to a const string of 16-bit Unicode chars)
22 // args[1] : LPWSTR lpBuffer (32-bit pointer to a string of 16-bit Unicode chars)
23 // lpBuffer : ptr to buffer that receives contents of the env_var as a null-terminated string.
24 // Return `# of chars` stored in the buffer pointed to by lpBuffer, excluding null-terminator.
25 // Return 0 upon failure.
27 // This is not the env var you are looking for.
28 this.set_last_error(Scalar::from_u32(203))?; // ERROR_ENVVAR_NOT_FOUND
29 this.write_null(dest)?;
32 "SetEnvironmentVariableW" => {
33 // args[0] : LPCWSTR lpName (32-bit ptr to a const string of 16-bit Unicode chars)
34 // args[1] : LPCWSTR lpValue (32-bit ptr to a const string of 16-bit Unicode chars)
35 // Return nonzero if success, else return 0.
36 throw_unsup_format!("can't set environment variable on Windows");
41 let handle = this.read_scalar(args[0])?.to_machine_isize(this)?;
42 let buf = this.read_scalar(args[1])?.not_undef()?;
43 let n = this.read_scalar(args[2])?.to_u32()?;
44 let written_place = this.deref_operand(args[3])?;
45 // Spec says to always write `0` first.
46 this.write_null(written_place.into())?;
47 let written = if handle == -11 || handle == -12 {
49 use std::io::{self, Write};
51 let buf_cont = this.memory.read_bytes(buf, Size::from_bytes(u64::from(n)))?;
52 let res = if handle == -11 {
53 io::stdout().write(buf_cont)
55 io::stderr().write(buf_cont)
57 res.ok().map(|n| n as u32)
59 eprintln!("Miri: Ignored output to handle {}", handle);
60 // Pretend it all went well.
63 // If there was no error, write back how much was written.
64 if let Some(n) = written {
65 this.write_scalar(Scalar::from_u32(n), written_place.into())?;
67 // Return whether this was a success.
69 Scalar::from_int(if written.is_some() { 1 } else { 0 }, dest.layout.size),
75 // DWORD = ULONG = u32
79 this.write_scalar(Scalar::from_int(1, this.pointer_size()), dest)?;
82 let _handle = this.read_scalar(args[0])?.to_machine_isize(this)?;
83 let flags = this.read_scalar(args[1])?.to_u32()?;
84 let size = this.read_scalar(args[2])?.to_machine_usize(this)?;
85 let zero_init = (flags & 0x00000008) != 0; // HEAP_ZERO_MEMORY
86 let res = this.malloc(size, zero_init, MiriMemoryKind::WinHeap);
87 this.write_scalar(res, dest)?;
90 let _handle = this.read_scalar(args[0])?.to_machine_isize(this)?;
91 let _flags = this.read_scalar(args[1])?.to_u32()?;
92 let ptr = this.read_scalar(args[2])?.not_undef()?;
93 this.free(ptr, MiriMemoryKind::WinHeap)?;
94 this.write_scalar(Scalar::from_int(1, Size::from_bytes(4)), dest)?;
97 let _handle = this.read_scalar(args[0])?.to_machine_isize(this)?;
98 let _flags = this.read_scalar(args[1])?.to_u32()?;
99 let ptr = this.read_scalar(args[2])?.not_undef()?;
100 let size = this.read_scalar(args[3])?.to_machine_usize(this)?;
101 let res = this.realloc(ptr, size, MiriMemoryKind::WinHeap)?;
102 this.write_scalar(res, dest)?;
106 this.set_last_error(this.read_scalar(args[0])?.not_undef()?)?;
109 let last_error = this.get_last_error()?;
110 this.write_scalar(last_error, dest)?;
113 "AddVectoredExceptionHandler" => {
114 // Any non zero value works for the stdlib. This is just used for stack overflows anyway.
115 this.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?;
118 | "InitializeCriticalSection"
119 | "EnterCriticalSection"
120 | "LeaveCriticalSection"
121 | "DeleteCriticalSection"
123 // Nothing to do, not even a return value.
128 | "TryEnterCriticalSection"
129 | "GetConsoleScreenBufferInfo"
130 | "SetConsoleTextAttribute"
132 // Pretend these do not exist / nothing happened, by returning zero.
133 this.write_null(dest)?;
137 let system_info = this.deref_operand(args[0])?;
138 // Initialize with `0`.
139 this.memory.write_bytes(
141 iter::repeat(0u8).take(system_info.layout.size.bytes() as usize),
143 // Set number of processors.
144 let dword_size = Size::from_bytes(4);
145 let num_cpus = this.mplace_field(system_info, 6)?;
146 this.write_scalar(Scalar::from_int(NUM_CPUS, dword_size), num_cpus.into())?;
150 // This just creates a key; Windows does not natively support TLS destructors.
152 // Create key and return it.
153 let key = this.machine.tls.create_tls_key(None) as u128;
155 // Figure out how large a TLS key actually is. This is `c::DWORD`.
156 if dest.layout.size.bits() < 128
157 && key >= (1u128 << dest.layout.size.bits() as u128)
159 throw_unsup!(OutOfTls);
161 this.write_scalar(Scalar::from_uint(key, dest.layout.size), dest)?;
164 let key = this.read_scalar(args[0])?.to_u32()? as u128;
165 let ptr = this.machine.tls.load_tls(key, tcx)?;
166 this.write_scalar(ptr, dest)?;
169 let key = this.read_scalar(args[0])?.to_u32()? as u128;
170 let new_ptr = this.read_scalar(args[1])?.not_undef()?;
171 this.machine.tls.store_tls(key, this.test_null(new_ptr)?)?;
173 // Return success (`1`).
174 this.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?;
177 let which = this.read_scalar(args[0])?.to_i32()?;
178 // We just make this the identity function, so we know later in `WriteFile`
180 this.write_scalar(Scalar::from_int(which, this.pointer_size()), dest)?;
182 "GetConsoleMode" => {
183 // Everything is a pipe.
184 this.write_null(dest)?;
186 "GetCommandLineW" => {
188 this.machine.cmd_line.expect("machine must be initialized"),
192 // The actual name of 'RtlGenRandom'
193 "SystemFunction036" => {
194 let ptr = this.read_scalar(args[0])?.not_undef()?;
195 let len = this.read_scalar(args[1])?.to_u32()?;
196 this.gen_random(ptr, len as usize)?;
197 this.write_scalar(Scalar::from_bool(true), dest)?;
199 _ => throw_unsup_format!("can't call foreign function: {}", link_name),