]> git.lizzy.rs Git - rust.git/blob - src/shims/foreign_items/windows.rs
a64ef0f1293522f201afcad964b891c9fba99c48
[rust.git] / src / shims / foreign_items / windows.rs
1 use crate::*;
2 use rustc::mir;
3 use rustc::ty::layout::Size;
4 use std::iter;
5
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(
9         &mut self,
10         link_name: &str,
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 };
17
18         match link_name {
19             // Windows API stubs.
20             // HANDLE = isize
21             // DWORD = ULONG = u32
22             // BOOL = i32
23
24             // Environment related shims
25             "GetEnvironmentVariableW" => {
26                 let result = this.GetEnvironmentVariableW(args[0], args[1], args[2])?;
27                 this.write_scalar(Scalar::from_uint(result, dest.layout.size), dest)?;
28             }
29
30             "SetEnvironmentVariableW" => {
31                 let result = this.SetEnvironmentVariableW(args[0], args[1])?;
32                 this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?;
33             }
34
35             "GetEnvironmentStringsW" => {
36                 let result = this.GetEnvironmentStringsW()?;
37                 this.write_scalar(result, dest)?;
38             }
39
40             "FreeEnvironmentStringsW" => {
41                 let result = this.FreeEnvironmentStringsW(args[0])?;
42                 this.write_scalar(Scalar::from_i32(result), dest)?;
43             }
44
45             // File related shims
46             "WriteFile" => {
47                 let handle = this.read_scalar(args[0])?.to_machine_isize(this)?;
48                 let buf = this.read_scalar(args[1])?.not_undef()?;
49                 let n = this.read_scalar(args[2])?.to_u32()?;
50                 let written_place = this.deref_operand(args[3])?;
51                 // Spec says to always write `0` first.
52                 this.write_null(written_place.into())?;
53                 let written = if handle == -11 || handle == -12 {
54                     // stdout/stderr
55                     use std::io::{self, Write};
56
57                     let buf_cont = this.memory.read_bytes(buf, Size::from_bytes(u64::from(n)))?;
58                     let res = if handle == -11 {
59                         io::stdout().write(buf_cont)
60                     } else {
61                         io::stderr().write(buf_cont)
62                     };
63                     res.ok().map(|n| n as u32)
64                 } else {
65                     eprintln!("Miri: Ignored output to handle {}", handle);
66                     // Pretend it all went well.
67                     Some(n)
68                 };
69                 // If there was no error, write back how much was written.
70                 if let Some(n) = written {
71                     this.write_scalar(Scalar::from_u32(n), written_place.into())?;
72                 }
73                 // Return whether this was a success.
74                 this.write_scalar(
75                     Scalar::from_int(if written.is_some() { 1 } else { 0 }, dest.layout.size),
76                     dest,
77                 )?;
78             }
79
80             // Other shims
81             "GetProcessHeap" => {
82                 // Just fake a HANDLE
83                 this.write_scalar(Scalar::from_int(1, this.pointer_size()), dest)?;
84             }
85             "HeapAlloc" => {
86                 let _handle = this.read_scalar(args[0])?.to_machine_isize(this)?;
87                 let flags = this.read_scalar(args[1])?.to_u32()?;
88                 let size = this.read_scalar(args[2])?.to_machine_usize(this)?;
89                 let zero_init = (flags & 0x00000008) != 0; // HEAP_ZERO_MEMORY
90                 let res = this.malloc(size, zero_init, MiriMemoryKind::WinHeap);
91                 this.write_scalar(res, dest)?;
92             }
93             "HeapFree" => {
94                 let _handle = this.read_scalar(args[0])?.to_machine_isize(this)?;
95                 let _flags = this.read_scalar(args[1])?.to_u32()?;
96                 let ptr = this.read_scalar(args[2])?.not_undef()?;
97                 this.free(ptr, MiriMemoryKind::WinHeap)?;
98                 this.write_scalar(Scalar::from_int(1, Size::from_bytes(4)), dest)?;
99             }
100             "HeapReAlloc" => {
101                 let _handle = this.read_scalar(args[0])?.to_machine_isize(this)?;
102                 let _flags = this.read_scalar(args[1])?.to_u32()?;
103                 let ptr = this.read_scalar(args[2])?.not_undef()?;
104                 let size = this.read_scalar(args[3])?.to_machine_usize(this)?;
105                 let res = this.realloc(ptr, size, MiriMemoryKind::WinHeap)?;
106                 this.write_scalar(res, dest)?;
107             }
108
109             "SetLastError" => {
110                 this.set_last_error(this.read_scalar(args[0])?.not_undef()?)?;
111             }
112             "GetLastError" => {
113                 let last_error = this.get_last_error()?;
114                 this.write_scalar(last_error, dest)?;
115             }
116
117             "AddVectoredExceptionHandler" => {
118                 // Any non zero value works for the stdlib. This is just used for stack overflows anyway.
119                 this.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?;
120             }
121
122             | "InitializeCriticalSection"
123             | "EnterCriticalSection"
124             | "LeaveCriticalSection"
125             | "DeleteCriticalSection"
126             => {
127                 // Nothing to do, not even a return value.
128                 // (Windows locks are reentrant, and we have only 1 thread,
129                 // so not doing any futher checks here is at least not incorrect.)
130             }
131
132             | "GetModuleHandleW"
133             | "GetProcAddress"
134             | "GetConsoleScreenBufferInfo"
135             | "SetConsoleTextAttribute"
136             => {
137                 // Pretend these do not exist / nothing happened, by returning zero.
138                 this.write_null(dest)?;
139             }
140
141             "GetSystemInfo" => {
142                 let system_info = this.deref_operand(args[0])?;
143                 // Initialize with `0`.
144                 this.memory.write_bytes(
145                     system_info.ptr,
146                     iter::repeat(0u8).take(system_info.layout.size.bytes() as usize),
147                 )?;
148                 // Set number of processors.
149                 let dword_size = Size::from_bytes(4);
150                 let num_cpus = this.mplace_field(system_info, 6)?;
151                 this.write_scalar(Scalar::from_int(NUM_CPUS, dword_size), num_cpus.into())?;
152             }
153
154             "TlsAlloc" => {
155                 // This just creates a key; Windows does not natively support TLS destructors.
156
157                 // Create key and return it.
158                 let key = this.machine.tls.create_tls_key(None, dest.layout.size)?;
159                 this.write_scalar(Scalar::from_uint(key, dest.layout.size), dest)?;
160             }
161             "TlsGetValue" => {
162                 let key = u128::from(this.read_scalar(args[0])?.to_u32()?);
163                 let ptr = this.machine.tls.load_tls(key, tcx)?;
164                 this.write_scalar(ptr, dest)?;
165             }
166             "TlsSetValue" => {
167                 let key = u128::from(this.read_scalar(args[0])?.to_u32()?);
168                 let new_ptr = this.read_scalar(args[1])?.not_undef()?;
169                 this.machine.tls.store_tls(key, this.test_null(new_ptr)?)?;
170
171                 // Return success (`1`).
172                 this.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?;
173             }
174             "GetStdHandle" => {
175                 let which = this.read_scalar(args[0])?.to_i32()?;
176                 // We just make this the identity function, so we know later in `WriteFile`
177                 // which one it is.
178                 this.write_scalar(Scalar::from_int(which, this.pointer_size()), dest)?;
179             }
180             "GetConsoleMode" => {
181                 // Everything is a pipe.
182                 this.write_null(dest)?;
183             }
184             "GetCommandLineW" => {
185                 this.write_scalar(
186                     this.machine.cmd_line.expect("machine must be initialized"),
187                     dest,
188                 )?;
189             }
190             // The actual name of 'RtlGenRandom'
191             "SystemFunction036" => {
192                 let ptr = this.read_scalar(args[0])?.not_undef()?;
193                 let len = this.read_scalar(args[1])?.to_u32()?;
194                 this.gen_random(ptr, len.into())?;
195                 this.write_scalar(Scalar::from_bool(true), dest)?;
196             }
197             // We don't support threading.
198             "CreateThread" => {
199                 throw_unsup_format!("Miri does not support threading");
200             }
201             _ => throw_unsup_format!("can't call foreign function: {}", link_name),
202         }
203
204         Ok(true)
205     }
206 }
207