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