From 2dc419d9c6bec5ed876fa710ea43c85c0f96f52f Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Mon, 31 Oct 2022 07:49:08 +0000 Subject: [PATCH] Add `NtWriteFile` to `foreign_items` Co-Authored-By: Ralf Jung --- src/tools/miri/src/shims/windows/dlsym.rs | 61 +------------------ .../miri/src/shims/windows/foreign_items.rs | 61 +++++++++++++++++++ 2 files changed, 63 insertions(+), 59 deletions(-) diff --git a/src/tools/miri/src/shims/windows/dlsym.rs b/src/tools/miri/src/shims/windows/dlsym.rs index 4b2a90723c79c..42bb694b77c82 100644 --- a/src/tools/miri/src/shims/windows/dlsym.rs +++ b/src/tools/miri/src/shims/windows/dlsym.rs @@ -1,5 +1,5 @@ +use super::foreign_items::nt_write_file; use rustc_middle::mir; -use rustc_target::abi::Size; use rustc_target::spec::abi::Abi; use log::trace; @@ -56,64 +56,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { ); } - let [ - handle, - _event, - _apc_routine, - _apc_context, - io_status_block, - buf, - n, - byte_offset, - _key, - ] = check_arg_count(args)?; - let handle = this.read_scalar(handle)?.to_machine_isize(this)?; - let buf = this.read_pointer(buf)?; - let n = this.read_scalar(n)?.to_u32()?; - let byte_offset = this.read_scalar(byte_offset)?.to_machine_usize(this)?; // is actually a pointer - let io_status_block = this.deref_operand(io_status_block)?; - - if byte_offset != 0 { - throw_unsup_format!( - "`NtWriteFile` `ByteOffset` paremeter is non-null, which is unsupported" - ); - } - - let written = if handle == -11 || handle == -12 { - // stdout/stderr - use std::io::{self, Write}; - - let buf_cont = - this.read_bytes_ptr_strip_provenance(buf, Size::from_bytes(u64::from(n)))?; - let res = if this.machine.mute_stdout_stderr { - Ok(buf_cont.len()) - } else if handle == -11 { - io::stdout().write(buf_cont) - } else { - io::stderr().write(buf_cont) - }; - // We write at most `n` bytes, which is a `u32`, so we cannot have written more than that. - res.ok().map(|n| u32::try_from(n).unwrap()) - } else { - throw_unsup_format!( - "on Windows, writing to anything except stdout/stderr is not supported" - ) - }; - // We have to put the result into io_status_block. - if let Some(n) = written { - let io_status_information = - this.mplace_field_named(&io_status_block, "Information")?; - this.write_scalar( - Scalar::from_machine_usize(n.into(), this), - &io_status_information.into(), - )?; - } - // Return whether this was a success. >= 0 is success. - // For the error code we arbitrarily pick 0xC0000185, STATUS_IO_DEVICE_ERROR. - this.write_scalar( - Scalar::from_u32(if written.is_some() { 0 } else { 0xC0000185u32 }), - dest, - )?; + nt_write_file(this, args, dest)?; } Dlsym::SetThreadDescription => { let [handle, name] = check_arg_count(args)?; diff --git a/src/tools/miri/src/shims/windows/foreign_items.rs b/src/tools/miri/src/shims/windows/foreign_items.rs index 2a34a3a47bbb5..530c8d7ab2680 100644 --- a/src/tools/miri/src/shims/windows/foreign_items.rs +++ b/src/tools/miri/src/shims/windows/foreign_items.rs @@ -4,6 +4,7 @@ use rustc_span::Symbol; use rustc_target::abi::Size; use rustc_target::spec::abi::Abi; +use crate::helpers::check_arg_count; use crate::*; use shims::foreign_items::EmulateByNameResult; use shims::windows::handle::{EvalContextExt as _, Handle, PseudoHandle}; @@ -453,6 +454,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { // FIXME: this should return a nonzero value if this call does result in switching to another thread. this.write_null(dest)?; } + "NtWriteFile" if this.frame_in_std() => { + this.check_abi_and_shim_symbol_clash( + abi, + Abi::System { unwind: false }, + link_name, + )?; + nt_write_file(this, args, dest)?; + } _ => return Ok(EmulateByNameResult::NotSupported), } @@ -460,3 +469,55 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { Ok(EmulateByNameResult::NeedsJumping) } } + +// Incomplete implementation of `NtWriteFile`. +pub(super) fn nt_write_file<'a, 'mir, 'tcx>( + this: &'a mut MiriInterpCx<'mir, 'tcx>, + args: &[OpTy<'tcx, Provenance>], + dest: &PlaceTy<'tcx, Provenance>, +) -> InterpResult<'tcx, ()> { + let [handle, _event, _apc_routine, _apc_context, io_status_block, buf, n, byte_offset, _key] = + check_arg_count(args)?; + + let handle = this.read_scalar(handle)?.to_machine_isize(this)?; + let buf = this.read_pointer(buf)?; + let n = this.read_scalar(n)?.to_u32()?; + let byte_offset = this.read_scalar(byte_offset)?.to_machine_usize(this)?; // is actually a pointer + let io_status_block = this.deref_operand(io_status_block)?; + + if byte_offset != 0 { + throw_unsup_format!( + "`NtWriteFile` `ByteOffset` paremeter is non-null, which is unsupported" + ); + } + + let written = if handle == -11 || handle == -12 { + // stdout/stderr + use std::io::{self, Write}; + + let buf_cont = this.read_bytes_ptr_strip_provenance(buf, Size::from_bytes(u64::from(n)))?; + let res = if this.machine.mute_stdout_stderr { + Ok(buf_cont.len()) + } else if handle == -11 { + io::stdout().write(buf_cont) + } else { + io::stderr().write(buf_cont) + }; + // We write at most `n` bytes, which is a `u32`, so we cannot have written more than that. + res.ok().map(|n| u32::try_from(n).unwrap()) + } else { + throw_unsup_format!("on Windows, writing to anything except stdout/stderr is not supported") + }; + // We have to put the result into io_status_block. + if let Some(n) = written { + let io_status_information = this.mplace_field_named(&io_status_block, "Information")?; + this.write_scalar( + Scalar::from_machine_usize(n.into(), this), + &io_status_information.into(), + )?; + } + // Return whether this was a success. >= 0 is success. + // For the error code we arbitrarily pick 0xC0000185, STATUS_IO_DEVICE_ERROR. + this.write_scalar(Scalar::from_u32(if written.is_some() { 0 } else { 0xC0000185u32 }), dest)?; + Ok(()) +}