Merge pull request #4344 from CraftSpider/windows-file-clone

Implement file cloning on Windows
This commit is contained in:
Oli Scherer 2025-05-28 10:38:42 +00:00 committed by GitHub
commit 0fdc38eefe
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 97 additions and 1 deletions

View file

@ -572,6 +572,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
let ret = this.WaitForSingleObject(handle, timeout)?;
this.write_scalar(ret, dest)?;
}
"GetCurrentProcess" => {
let [] = this.check_shim(abi, sys_conv, link_name, args)?;
this.write_scalar(
Handle::Pseudo(PseudoHandle::CurrentProcess).to_scalar(this),
dest,
)?;
}
"GetCurrentThread" => {
let [] = this.check_shim(abi, sys_conv, link_name, args)?;
@ -693,6 +701,20 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
let res = this.GetStdHandle(which)?;
this.write_scalar(res, dest)?;
}
"DuplicateHandle" => {
let [src_proc, src_handle, target_proc, target_handle, access, inherit, options] =
this.check_shim(abi, sys_conv, link_name, args)?;
let res = this.DuplicateHandle(
src_proc,
src_handle,
target_proc,
target_handle,
access,
inherit,
options,
)?;
this.write_scalar(res, dest)?;
}
"CloseHandle" => {
let [handle] = this.check_shim(abi, sys_conv, link_name, args)?;

View file

@ -9,6 +9,7 @@ use crate::*;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum PseudoHandle {
CurrentThread,
CurrentProcess,
}
/// Miri representation of a Windows `HANDLE`
@ -23,16 +24,19 @@ pub enum Handle {
impl PseudoHandle {
const CURRENT_THREAD_VALUE: u32 = 0;
const CURRENT_PROCESS_VALUE: u32 = 1;
fn value(self) -> u32 {
match self {
Self::CurrentThread => Self::CURRENT_THREAD_VALUE,
Self::CurrentProcess => Self::CURRENT_PROCESS_VALUE,
}
}
fn from_value(value: u32) -> Option<Self> {
match value {
Self::CURRENT_THREAD_VALUE => Some(Self::CurrentThread),
Self::CURRENT_PROCESS_VALUE => Some(Self::CurrentProcess),
_ => None,
}
}
@ -244,6 +248,76 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
interp_ok(handle.to_scalar(this))
}
fn DuplicateHandle(
&mut self,
src_proc: &OpTy<'tcx>, // HANDLE
src_handle: &OpTy<'tcx>, // HANDLE
target_proc: &OpTy<'tcx>, // HANDLE
target_handle: &OpTy<'tcx>, // LPHANDLE
desired_access: &OpTy<'tcx>, // DWORD
inherit: &OpTy<'tcx>, // BOOL
options: &OpTy<'tcx>, // DWORD
) -> InterpResult<'tcx, Scalar> {
// ^ Returns BOOL (i32 on Windows)
let this = self.eval_context_mut();
let src_proc = this.read_handle(src_proc, "DuplicateHandle")?;
let src_handle = this.read_handle(src_handle, "DuplicateHandle")?;
let target_proc = this.read_handle(target_proc, "DuplicateHandle")?;
let target_handle_ptr = this.read_pointer(target_handle)?;
// Since we only support DUPLICATE_SAME_ACCESS, this value is ignored, but should be valid
let _ = this.read_scalar(desired_access)?.to_u32()?;
// We don't support the CreateProcess API, so inheritable or not means nothing.
// If we ever add CreateProcess support, this will need to be implemented.
let _ = this.read_scalar(inherit)?;
let options = this.read_scalar(options)?;
if src_proc != Handle::Pseudo(PseudoHandle::CurrentProcess) {
throw_unsup_format!(
"`DuplicateHandle` `hSourceProcessHandle` parameter is not the current process, which is unsupported"
);
}
if target_proc != Handle::Pseudo(PseudoHandle::CurrentProcess) {
throw_unsup_format!(
"`DuplicateHandle` `hSourceProcessHandle` parameter is not the current process, which is unsupported"
);
}
if this.ptr_is_null(target_handle_ptr)? {
throw_unsup_format!(
"`DuplicateHandle` `lpTargetHandle` parameter is null, which is unsupported"
);
}
if options != this.eval_windows("c", "DUPLICATE_SAME_ACCESS") {
throw_unsup_format!(
"`DuplicateHandle` `dwOptions` parameter is not `DUPLICATE_SAME_ACCESS`, which is unsupported"
);
}
let new_handle = match src_handle {
Handle::File(old_fd_num) => {
let Some(fd) = this.machine.fds.get(old_fd_num) else {
this.invalid_handle("DuplicateHandle")?
};
Handle::File(this.machine.fds.insert(fd))
}
Handle::Thread(_) => {
throw_unsup_format!(
"`DuplicateHandle` called on a thread handle, which is unsupported"
);
}
Handle::Pseudo(pseudo) => Handle::Pseudo(pseudo),
Handle::Null | Handle::Invalid => this.invalid_handle("DuplicateHandle")?,
};
let target_place = this.deref_pointer_as(target_handle, this.machine.layouts.usize)?;
this.write_scalar(new_handle.to_scalar(this), &target_place)?;
interp_ok(this.eval_windows("c", "TRUE"))
}
fn CloseHandle(&mut self, handle_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> {
let this = self.eval_context_mut();

View file

@ -23,9 +23,9 @@ fn main() {
test_seek();
test_errors();
test_from_raw_os_error();
test_file_clone();
// Windows file handling is very incomplete.
if cfg!(not(windows)) {
test_file_clone();
test_file_set_len();
test_file_sync();
test_rename();