diff --git a/src/shims/windows/dlsym.rs b/src/shims/windows/dlsym.rs index 325100bdb3..c431a10173 100644 --- a/src/shims/windows/dlsym.rs +++ b/src/shims/windows/dlsym.rs @@ -1,10 +1,16 @@ use rustc_middle::mir; +use rustc_target::abi::Size; use rustc_target::spec::abi::Abi; +use log::trace; + +use crate::helpers::check_arg_count; use crate::*; #[derive(Debug, Copy, Clone)] -pub enum Dlsym {} +pub enum Dlsym { + NtWriteFile, +} impl Dlsym { // Returns an error for unsupported symbols, and None if this symbol @@ -12,6 +18,7 @@ impl Dlsym { pub fn from_str(name: &str) -> InterpResult<'static, Option> { Ok(match name { "GetSystemTimePreciseAsFileTime" => None, + "NtWriteFile" => Some(Dlsym::NtWriteFile), _ => throw_unsup_format!("unsupported Windows dlsym: {}", name), }) } @@ -23,15 +30,85 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, dlsym: Dlsym, abi: Abi, - _args: &[OpTy<'tcx, Tag>], + args: &[OpTy<'tcx, Tag>], ret: Option<(&PlaceTy<'tcx, Tag>, mir::BasicBlock)>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let (_dest, _ret) = ret.expect("we don't support any diverging dlsym"); + let (dest, ret) = ret.expect("we don't support any diverging dlsym"); assert!(this.tcx.sess.target.os == "windows"); this.check_abi(abi, Abi::System { unwind: false })?; - match dlsym {} + match dlsym { + Dlsym::NtWriteFile => { + if !this.frame_in_std() { + throw_unsup_format!( + "NtWriteFile support is crude and just enough for stdout to work" + ); + } + + let &[ + ref handle, + ref _event, + ref _apc_routine, + ref _apc_context, + ref io_status_block, + ref buf, + ref n, + ref byte_offset, + ref _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)?; + 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(buf, Size::from_bytes(u64::from(n)))?; + let res = if handle == -11 { + io::stdout().write(buf_cont) + } else { + io::stderr().write(buf_cont) + }; + res.ok().map(|n| n as u32) + } 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_machine_isize( + if written.is_some() { 0 } else { (0xC0000185u32 as i32).into() }, + this, + ), + dest, + )?; + } + } + + trace!("{:?}", this.dump_place(**dest)); + this.go_to_block(ret); + Ok(()) } } diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index 82ac5c5d75..30a02e606c 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -69,43 +69,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let &[ref which] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let which = this.read_scalar(which)?.to_i32()?; - // We just make this the identity function, so we know later in `WriteFile` + // We just make this the identity function, so we know later in `NtWriteFile` // which one it is. this.write_scalar(Scalar::from_machine_isize(which.into(), this), dest)?; } - "WriteFile" => { - let &[ref handle, ref buf, ref n, ref written_ptr, ref overlapped] = - this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; - this.read_scalar(overlapped)?.to_machine_usize(this)?; // this is a poiner, that we ignore - 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 written_place = this.deref_operand(written_ptr)?; - // Spec says to always write `0` first. - this.write_null(&written_place.into())?; - let written = if handle == -11 || handle == -12 { - // stdout/stderr - use std::io::{self, Write}; - - let buf_cont = this.read_bytes_ptr(buf, Size::from_bytes(u64::from(n)))?; - let res = if handle == -11 { - io::stdout().write(buf_cont) - } else { - io::stderr().write(buf_cont) - }; - res.ok().map(|n| n as u32) - } else { - throw_unsup_format!( - "on Windows, writing to anything except stdout/stderr is not supported" - ) - }; - // If there was no error, write back how much was written. - if let Some(n) = written { - this.write_scalar(Scalar::from_u32(n), &written_place.into())?; - } - // Return whether this was a success. - this.write_scalar(Scalar::from_i32(if written.is_some() { 1 } else { 0 }), dest)?; - } // Allocation "HeapAlloc" => { @@ -350,6 +317,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Just fake a HANDLE this.write_scalar(Scalar::from_machine_isize(1, this), dest)?; } + "GetModuleHandleA" if this.frame_in_std() => { + #[allow(non_snake_case)] + let &[_lpModuleName] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; + // We need to return something non-null here to make `compat_fn!` work. + this.write_scalar(Scalar::from_machine_isize(1, this), dest)?; + } "SetConsoleTextAttribute" if this.frame_in_std() => { #[allow(non_snake_case)] let &[ref _hConsoleOutput, ref _wAttribute] = diff --git a/tests/run-pass/vecdeque.rs b/tests/run-pass/vecdeque.rs index 0cba0165ca..fa6707632d 100644 --- a/tests/run-pass/vecdeque.rs +++ b/tests/run-pass/vecdeque.rs @@ -26,7 +26,7 @@ fn main() { assert_eq!(**a, 2); } - // Regression test for Debug and Diaplay impl's + // Regression test for Debug impl's println!("{:?} {:?}", dst, dst.iter()); println!("{:?}", VecDeque::::new().iter());