Skip to content

Rustup #2055

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Apr 8, 2022
Merged

Rustup #2055

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion rust-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
bbe9d27b8ff36da56638aa43d6d0cdfdf89a4e57
1a4b9a85634c17a60e8802307510c300a35a4b9b
3 changes: 3 additions & 0 deletions src/machine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -605,6 +605,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> {

#[inline(always)]
fn memory_read(
_tcx: TyCtxt<'tcx>,
machine: &Self,
alloc_extra: &AllocExtra,
tag: Tag,
Expand All @@ -627,6 +628,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> {

#[inline(always)]
fn memory_written(
_tcx: TyCtxt<'tcx>,
machine: &mut Self,
alloc_extra: &mut AllocExtra,
tag: Tag,
Expand All @@ -649,6 +651,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> {

#[inline(always)]
fn memory_deallocated(
_tcx: TyCtxt<'tcx>,
machine: &mut Self,
alloc_extra: &mut AllocExtra,
tag: Tag,
Expand Down
82 changes: 78 additions & 4 deletions src/shims/windows/dlsym.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,24 @@
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
// should become a NULL pointer (pretend it does not exist).
pub fn from_str(name: &str) -> InterpResult<'static, Option<Dlsym>> {
Ok(match name {
"GetSystemTimePreciseAsFileTime" => None,
"NtWriteFile" => Some(Dlsym::NtWriteFile),
_ => throw_unsup_format!("unsupported Windows dlsym: {}", name),
})
}
Expand All @@ -23,15 +30,82 @@ 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)?; // 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(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_i32(if written.is_some() { 0 } else { 0xC0000185u32 as i32 }),
dest,
)?;
}
}

trace!("{:?}", this.dump_place(**dest));
this.go_to_block(ret);
Ok(())
}
}
60 changes: 17 additions & 43 deletions src/shims/windows/foreign_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx

// Windows API stubs.
// HANDLE = isize
// NTSTATUS = LONH = i32
// DWORD = ULONG = u32
// BOOL = i32
// BOOLEAN = u8
Expand Down Expand Up @@ -64,49 +65,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
this.write_scalar(Scalar::from_i32(result), dest)?;
}

// File related shims
"GetStdHandle" => {
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`
// 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" => {
let &[ref handle, ref flags, ref size] =
Expand Down Expand Up @@ -333,6 +291,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
// value if this call does result in switching to another thread.
this.write_null(dest)?;
}
"GetStdHandle" => {
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 `NtWriteFile` which
// one it is. This is very fake, but libtest needs it so we cannot make it a
// std-only shim.
this.write_scalar(Scalar::from_machine_isize(which.into(), this), dest)?;
}

// Better error for attempts to create a thread
"CreateThread" => {
Expand All @@ -350,6 +317,13 @@ 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] =
Expand Down
2 changes: 1 addition & 1 deletion tests/run-pass/concurrency/simple.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// ignore-windows: Concurrency on Windows is not supported yet.
// compile-flags: -Zmiri-check-number-validity
// compile-flags: -Zmiri-strict-provenance

use std::thread;

Expand Down
2 changes: 1 addition & 1 deletion tests/run-pass/vecdeque.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::<u32>::new().iter());

Expand Down