]> git.lizzy.rs Git - rust.git/blob - src/shims/foreign_items/windows.rs
remove hack for panics
[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             // 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.
26
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)?;
30             }
31
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");
37             }
38
39             // File related shims
40             "WriteFile" => {
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 {
48                     // stdout/stderr
49                     use std::io::{self, Write};
50
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)
54                     } else {
55                         io::stderr().write(buf_cont)
56                     };
57                     res.ok().map(|n| n as u32)
58                 } else {
59                     eprintln!("Miri: Ignored output to handle {}", handle);
60                     // Pretend it all went well.
61                     Some(n)
62                 };
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())?;
66                 }
67                 // Return whether this was a success.
68                 this.write_scalar(
69                     Scalar::from_int(if written.is_some() { 1 } else { 0 }, dest.layout.size),
70                     dest,
71                 )?;
72             }
73             // Windows API stubs.
74             // HANDLE = isize
75             // DWORD = ULONG = u32
76             // BOOL = i32
77             "GetProcessHeap" => {
78                 // Just fake a HANDLE
79                 this.write_scalar(Scalar::from_int(1, this.pointer_size()), dest)?;
80             }
81             "HeapAlloc" => {
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)?;
88             }
89             "HeapFree" => {
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)?;
95             }
96             "HeapReAlloc" => {
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)?;
103             }
104
105             "SetLastError" => {
106                 this.set_last_error(this.read_scalar(args[0])?.not_undef()?)?;
107             }
108             "GetLastError" => {
109                 let last_error = this.get_last_error()?;
110                 this.write_scalar(last_error, dest)?;
111             }
112
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)?;
116             }
117
118             | "InitializeCriticalSection"
119             | "EnterCriticalSection"
120             | "LeaveCriticalSection"
121             | "DeleteCriticalSection"
122             => {
123                 // Nothing to do, not even a return value.
124             }
125
126             | "GetModuleHandleW"
127             | "GetProcAddress"
128             | "TryEnterCriticalSection"
129             | "GetConsoleScreenBufferInfo"
130             | "SetConsoleTextAttribute"
131             => {
132                 // Pretend these do not exist / nothing happened, by returning zero.
133                 this.write_null(dest)?;
134             }
135
136             "GetSystemInfo" => {
137                 let system_info = this.deref_operand(args[0])?;
138                 // Initialize with `0`.
139                 this.memory.write_bytes(
140                     system_info.ptr,
141                     iter::repeat(0u8).take(system_info.layout.size.bytes() as usize),
142                 )?;
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())?;
147             }
148
149             "TlsAlloc" => {
150                 // This just creates a key; Windows does not natively support TLS destructors.
151
152                 // Create key and return it.
153                 let key = this.machine.tls.create_tls_key(None) as u128;
154
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)
158                 {
159                     throw_unsup!(OutOfTls);
160                 }
161                 this.write_scalar(Scalar::from_uint(key, dest.layout.size), dest)?;
162             }
163             "TlsGetValue" => {
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)?;
167             }
168             "TlsSetValue" => {
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)?)?;
172
173                 // Return success (`1`).
174                 this.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?;
175             }
176             "GetStdHandle" => {
177                 let which = this.read_scalar(args[0])?.to_i32()?;
178                 // We just make this the identity function, so we know later in `WriteFile`
179                 // which one it is.
180                 this.write_scalar(Scalar::from_int(which, this.pointer_size()), dest)?;
181             }
182             "GetConsoleMode" => {
183                 // Everything is a pipe.
184                 this.write_null(dest)?;
185             }
186             "GetCommandLineW" => {
187                 this.write_scalar(
188                     this.machine.cmd_line.expect("machine must be initialized"),
189                     dest,
190                 )?;
191             }
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)?;
198             }
199             _ => throw_unsup_format!("can't call foreign function: {}", link_name),
200         }
201
202         Ok(true)
203     }
204 }
205