1 | use rustc_abi::ExternAbi; |
2 | use rustc_middle::ty::layout::LayoutOf; |
3 | |
4 | use self::shims::windows::handle::{EvalContextExt as _, Handle, PseudoHandle}; |
5 | use crate::*; |
6 | |
7 | impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} |
8 | |
9 | #[allow (non_snake_case)] |
10 | pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { |
11 | fn CreateThread( |
12 | &mut self, |
13 | security_op: &OpTy<'tcx>, |
14 | stacksize_op: &OpTy<'tcx>, |
15 | start_op: &OpTy<'tcx>, |
16 | arg_op: &OpTy<'tcx>, |
17 | flags_op: &OpTy<'tcx>, |
18 | thread_op: &OpTy<'tcx>, |
19 | ) -> InterpResult<'tcx, ThreadId> { |
20 | let this = self.eval_context_mut(); |
21 | |
22 | let security = this.read_pointer(security_op)?; |
23 | // stacksize is ignored, but still needs to be a valid usize |
24 | this.read_target_usize(stacksize_op)?; |
25 | let start_routine = this.read_pointer(start_op)?; |
26 | let func_arg = this.read_immediate(arg_op)?; |
27 | let flags = this.read_scalar(flags_op)?.to_u32()?; |
28 | |
29 | let thread = if this.ptr_is_null(this.read_pointer(thread_op)?)? { |
30 | None |
31 | } else { |
32 | let thread_info_place = this.deref_pointer_as(thread_op, this.machine.layouts.u32)?; |
33 | Some(thread_info_place) |
34 | }; |
35 | |
36 | let stack_size_param_is_a_reservation = |
37 | this.eval_windows_u32("c" , "STACK_SIZE_PARAM_IS_A_RESERVATION" ); |
38 | |
39 | // We ignore the stack size, so we also ignore the |
40 | // `STACK_SIZE_PARAM_IS_A_RESERVATION` flag. |
41 | if flags != 0 && flags != stack_size_param_is_a_reservation { |
42 | throw_unsup_format!("unsupported `dwCreationFlags` {} in `CreateThread`" , flags) |
43 | } |
44 | |
45 | if !this.ptr_is_null(security)? { |
46 | throw_unsup_format!("non-null `lpThreadAttributes` in `CreateThread`" ) |
47 | } |
48 | |
49 | this.start_regular_thread( |
50 | thread, |
51 | start_routine, |
52 | ExternAbi::System { unwind: false }, |
53 | func_arg, |
54 | this.layout_of(this.tcx.types.u32)?, |
55 | ) |
56 | } |
57 | |
58 | fn WaitForSingleObject( |
59 | &mut self, |
60 | handle_op: &OpTy<'tcx>, |
61 | timeout_op: &OpTy<'tcx>, |
62 | ) -> InterpResult<'tcx, Scalar> { |
63 | let this = self.eval_context_mut(); |
64 | |
65 | let handle = this.read_scalar(handle_op)?; |
66 | let timeout = this.read_scalar(timeout_op)?.to_u32()?; |
67 | |
68 | let thread = match Handle::try_from_scalar(handle, this)? { |
69 | Ok(Handle::Thread(thread)) => thread, |
70 | // Unlike on posix, the outcome of joining the current thread is not documented. |
71 | // On current Windows, it just deadlocks. |
72 | Ok(Handle::Pseudo(PseudoHandle::CurrentThread)) => this.active_thread(), |
73 | _ => this.invalid_handle("WaitForSingleObject" )?, |
74 | }; |
75 | |
76 | if timeout != this.eval_windows_u32("c" , "INFINITE" ) { |
77 | throw_unsup_format!("`WaitForSingleObject` with non-infinite timeout" ); |
78 | } |
79 | |
80 | this.join_thread(thread)?; |
81 | |
82 | interp_ok(this.eval_windows("c" , "WAIT_OBJECT_0" )) |
83 | } |
84 | } |
85 | |