Skip to content

Commit 0f6f9d6

Browse files
authored
Merge pull request #4344 from CraftSpider/windows-file-clone
Implement file cloning on Windows
2 parents 4f4e7ca + 960710f commit 0f6f9d6

File tree

3 files changed

+97
-1
lines changed

3 files changed

+97
-1
lines changed

src/shims/windows/foreign_items.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -572,6 +572,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
572572
let ret = this.WaitForSingleObject(handle, timeout)?;
573573
this.write_scalar(ret, dest)?;
574574
}
575+
"GetCurrentProcess" => {
576+
let [] = this.check_shim(abi, sys_conv, link_name, args)?;
577+
578+
this.write_scalar(
579+
Handle::Pseudo(PseudoHandle::CurrentProcess).to_scalar(this),
580+
dest,
581+
)?;
582+
}
575583
"GetCurrentThread" => {
576584
let [] = this.check_shim(abi, sys_conv, link_name, args)?;
577585

@@ -693,6 +701,20 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
693701
let res = this.GetStdHandle(which)?;
694702
this.write_scalar(res, dest)?;
695703
}
704+
"DuplicateHandle" => {
705+
let [src_proc, src_handle, target_proc, target_handle, access, inherit, options] =
706+
this.check_shim(abi, sys_conv, link_name, args)?;
707+
let res = this.DuplicateHandle(
708+
src_proc,
709+
src_handle,
710+
target_proc,
711+
target_handle,
712+
access,
713+
inherit,
714+
options,
715+
)?;
716+
this.write_scalar(res, dest)?;
717+
}
696718
"CloseHandle" => {
697719
let [handle] = this.check_shim(abi, sys_conv, link_name, args)?;
698720

src/shims/windows/handle.rs

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use crate::*;
99
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1010
pub enum PseudoHandle {
1111
CurrentThread,
12+
CurrentProcess,
1213
}
1314

1415
/// Miri representation of a Windows `HANDLE`
@@ -23,16 +24,19 @@ pub enum Handle {
2324

2425
impl 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

tests/pass/shims/fs.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,9 @@ fn main() {
2323
test_seek();
2424
test_errors();
2525
test_from_raw_os_error();
26+
test_file_clone();
2627
// Windows file handling is very incomplete.
2728
if cfg!(not(windows)) {
28-
test_file_clone();
2929
test_file_set_len();
3030
test_file_sync();
3131
test_rename();

0 commit comments

Comments
 (0)