@@ -9,6 +9,7 @@ use crate::*;
99#[ derive( Clone , Copy , Debug , PartialEq , Eq , Hash ) ]
1010pub enum PseudoHandle {
1111 CurrentThread ,
12+ CurrentProcess ,
1213}
1314
1415/// Miri representation of a Windows `HANDLE`
@@ -23,16 +24,19 @@ pub enum Handle {
2324
2425impl PseudoHandle {
2526 const CURRENT_THREAD_VALUE : u32 = 0 ;
27+ const CURRENT_PROCESS_VALUE : u32 = 1 ;
2628
2729 fn value ( self ) -> u32 {
2830 match self {
2931 Self :: CurrentThread => Self :: CURRENT_THREAD_VALUE ,
32+ Self :: CurrentProcess => Self :: CURRENT_PROCESS_VALUE ,
3033 }
3134 }
3235
3336 fn from_value ( value : u32 ) -> Option < Self > {
3437 match value {
3538 Self :: CURRENT_THREAD_VALUE => Some ( Self :: CurrentThread ) ,
39+ Self :: CURRENT_PROCESS_VALUE => Some ( Self :: CurrentProcess ) ,
3640 _ => None ,
3741 }
3842 }
@@ -244,6 +248,76 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
244248 interp_ok ( handle. to_scalar ( this) )
245249 }
246250
251+ fn DuplicateHandle (
252+ & mut self ,
253+ src_proc : & OpTy < ' tcx > , // HANDLE
254+ src_handle : & OpTy < ' tcx > , // HANDLE
255+ target_proc : & OpTy < ' tcx > , // HANDLE
256+ target_handle : & OpTy < ' tcx > , // LPHANDLE
257+ desired_access : & OpTy < ' tcx > , // DWORD
258+ inherit : & OpTy < ' tcx > , // BOOL
259+ options : & OpTy < ' tcx > , // DWORD
260+ ) -> InterpResult < ' tcx , Scalar > {
261+ // ^ Returns BOOL (i32 on Windows)
262+ let this = self . eval_context_mut ( ) ;
263+
264+ let src_proc = this. read_handle ( src_proc, "DuplicateHandle" ) ?;
265+ let src_handle = this. read_handle ( src_handle, "DuplicateHandle" ) ?;
266+ let target_proc = this. read_handle ( target_proc, "DuplicateHandle" ) ?;
267+ let target_handle_ptr = this. read_pointer ( target_handle) ?;
268+ // Since we only support DUPLICATE_SAME_ACCESS, this value is ignored, but should be valid
269+ let _ = this. read_scalar ( desired_access) ?. to_u32 ( ) ?;
270+ // We don't support the CreateProcess API, so inheritable or not means nothing.
271+ // If we ever add CreateProcess support, this will need to be implemented.
272+ let _ = this. read_scalar ( inherit) ?;
273+ let options = this. read_scalar ( options) ?;
274+
275+ if src_proc != Handle :: Pseudo ( PseudoHandle :: CurrentProcess ) {
276+ throw_unsup_format ! (
277+ "`DuplicateHandle` `hSourceProcessHandle` parameter is not the current process, which is unsupported"
278+ ) ;
279+ }
280+
281+ if target_proc != Handle :: Pseudo ( PseudoHandle :: CurrentProcess ) {
282+ throw_unsup_format ! (
283+ "`DuplicateHandle` `hSourceProcessHandle` parameter is not the current process, which is unsupported"
284+ ) ;
285+ }
286+
287+ if this. ptr_is_null ( target_handle_ptr) ? {
288+ throw_unsup_format ! (
289+ "`DuplicateHandle` `lpTargetHandle` parameter is null, which is unsupported"
290+ ) ;
291+ }
292+
293+ if options != this. eval_windows ( "c" , "DUPLICATE_SAME_ACCESS" ) {
294+ throw_unsup_format ! (
295+ "`DuplicateHandle` `dwOptions` parameter is not `DUPLICATE_SAME_ACCESS`, which is unsupported"
296+ ) ;
297+ }
298+
299+ let new_handle = match src_handle {
300+ Handle :: File ( old_fd_num) => {
301+ let Some ( fd) = this. machine . fds . get ( old_fd_num) else {
302+ this. invalid_handle ( "DuplicateHandle" ) ?
303+ } ;
304+ Handle :: File ( this. machine . fds . insert ( fd) )
305+ }
306+ Handle :: Thread ( _) => {
307+ throw_unsup_format ! (
308+ "`DuplicateHandle` called on a thread handle, which is unsupported"
309+ ) ;
310+ }
311+ Handle :: Pseudo ( pseudo) => Handle :: Pseudo ( pseudo) ,
312+ Handle :: Null | Handle :: Invalid => this. invalid_handle ( "DuplicateHandle" ) ?,
313+ } ;
314+
315+ let target_place = this. deref_pointer_as ( target_handle, this. machine . layouts . usize ) ?;
316+ this. write_scalar ( new_handle. to_scalar ( this) , & target_place) ?;
317+
318+ interp_ok ( this. eval_windows ( "c" , "TRUE" ) )
319+ }
320+
247321 fn CloseHandle ( & mut self , handle_op : & OpTy < ' tcx > ) -> InterpResult < ' tcx , Scalar > {
248322 let this = self . eval_context_mut ( ) ;
249323
0 commit comments