Skip to content
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

Test cargo-miri on Windows #578

Merged
merged 4 commits into from
Dec 19, 2018
Merged
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
8 changes: 6 additions & 2 deletions appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,17 @@ build: false
test_script:
- set RUST_TEST_NOCAPTURE=1
- set RUST_BACKTRACE=1
# Build miri
# Build and install miri
- cargo build --release --all-features --all-targets
- cargo install --all-features --force --path .
# Get ourselves a MIR-full libstd, and use it henceforth
- cargo run --release --all-features --bin cargo-miri -- miri setup
- cargo miri setup
- set MIRI_SYSROOT=%USERPROFILE%\AppData\Local\miri\miri\cache\HOST
# Test miri
- cargo test --release --all-features
# Test cargo integration
- cd test-cargo-miri
- python3 run-test.py

notifications:
- provider: Email
Expand Down
92 changes: 82 additions & 10 deletions src/fn_call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -562,27 +562,50 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a,
},

// Windows API stubs
"SetLastError" => {
let err = this.read_scalar(args[0])?.to_u32()?;
this.machine.last_error = err;
}
"GetLastError" => {
this.write_scalar(Scalar::from_uint(this.machine.last_error, Size::from_bits(32)), dest)?;
}

"AddVectoredExceptionHandler" => {
// any non zero value works for the stdlib. This is just used for stackoverflows anyway
this.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?;
},
"InitializeCriticalSection" |
"EnterCriticalSection" |
"LeaveCriticalSection" |
"DeleteCriticalSection" |
"SetLastError" => {
// Function does not return anything, nothing to do
"DeleteCriticalSection" => {
// Nothing to do, not even a return value
},
"GetModuleHandleW" |
"GetProcAddress" |
"TryEnterCriticalSection" => {
"TryEnterCriticalSection" |
"GetConsoleScreenBufferInfo" |
"SetConsoleTextAttribute" => {
// pretend these do not exist/nothing happened, by returning zero
this.write_null(dest)?;
},
"GetLastError" => {
// this is c::ERROR_CALL_NOT_IMPLEMENTED
this.write_scalar(Scalar::from_int(120, dest.layout.size), dest)?;
},
"GetSystemInfo" => {
let system_info = this.deref_operand(args[0])?;
let system_info_ptr = system_info.ptr.to_ptr()?;
// initialize with 0
this.memory_mut().get_mut(system_info_ptr.alloc_id)?
.write_repeat(tcx, system_info_ptr, 0, system_info.layout.size)?;
// set number of processors to 1
let dword_size = Size::from_bytes(4);
let offset = 2*dword_size + 3*tcx.pointer_size();
this.memory_mut().get_mut(system_info_ptr.alloc_id)?
.write_scalar(
tcx,
system_info_ptr.offset(offset, tcx)?,
Scalar::from_int(1, dword_size).into(),
dword_size,
)?;
}

"TlsAlloc" => {
// This just creates a key; Windows does not natively support TLS dtors.

Expand All @@ -596,18 +619,67 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a,
this.write_scalar(Scalar::from_uint(key, dest.layout.size), dest)?;
}
"TlsGetValue" => {
let key = this.read_scalar(args[0])?.to_bits(args[0].layout.size)?;
let key = this.read_scalar(args[0])?.to_u32()? as u128;
let ptr = this.machine.tls.load_tls(key)?;
this.write_scalar(ptr, dest)?;
}
"TlsSetValue" => {
let key = this.read_scalar(args[0])?.to_bits(args[0].layout.size)?;
let key = this.read_scalar(args[0])?.to_u32()? as u128;
let new_ptr = this.read_scalar(args[1])?.not_undef()?;
this.machine.tls.store_tls(key, new_ptr)?;

// Return success (1)
this.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?;
}
"GetStdHandle" => {
let which = this.read_scalar(args[0])?.to_i32()?;
// We just make this the identity function, so we know later in "WriteFile"
// which one it is.
this.write_scalar(Scalar::from_int(which, this.pointer_size()), dest)?;
}
"WriteFile" => {
let handle = this.read_scalar(args[0])?.to_isize(this)?;
let buf = this.read_scalar(args[1])?.not_undef()?;
let n = this.read_scalar(args[2])?.to_u32()?;
let written_place = this.deref_operand(args[3])?;
this.write_null(written_place.into())?; // spec says we always write 0 first
let written = if handle == -11 || handle == -12 {
// stdout/stderr
use std::io::{self, Write};

let buf_cont = this.memory().read_bytes(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 {
eprintln!("Miri: Ignored output to handle {}", handle);
Some(n) // pretend it all went well
};
// If there was no error, write back how much was written
if let Some(n) = written {
this.write_scalar(Scalar::from_uint(n, Size::from_bits(32)), written_place.into())?;
}
// Return whether this was a success
this.write_scalar(
Scalar::from_int(if written.is_some() { 1 } else { 0 }, dest.layout.size),
dest,
)?;
}
"GetConsoleMode" => {
// Everything is a pipe
this.write_null(dest)?;
}
"GetEnvironmentVariableW" => {
// This is not the env var you are looking for
this.machine.last_error = 203; // ERROR_ENVVAR_NOT_FOUND
this.write_null(dest)?;
}
"GetCommandLineW" => {
this.write_scalar(Scalar::Ptr(this.machine.cmd_line.unwrap()), dest)?;
}

// We can't execute anything else
_ => {
Expand Down
67 changes: 52 additions & 15 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use std::borrow::Cow;
use std::env;

use rustc::ty::{self, TyCtxt, query::TyCtxtAt};
use rustc::ty::layout::{TyLayout, LayoutOf, Size};
use rustc::ty::layout::{TyLayout, LayoutOf, Size, Align};
use rustc::hir::{self, def_id::DefId};
use rustc::mir;

Expand Down Expand Up @@ -123,24 +123,54 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>(
let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?;
let argc = Scalar::from_int(1, dest.layout.size);
ecx.write_scalar(argc, dest)?;
let argc_place = ecx.allocate(dest.layout, MiriMemoryKind::Env.into())?;
ecx.write_scalar(argc, argc_place.into())?;
ecx.machine.argc = Some(argc_place.ptr.to_ptr()?);
// Store argc for macOS _NSGetArgc
{
let argc_place = ecx.allocate(dest.layout, MiriMemoryKind::Env.into())?;
ecx.write_scalar(argc, argc_place.into())?;
ecx.machine.argc = Some(argc_place.ptr.to_ptr()?);
}

// FIXME: extract main source file path
// Third argument (argv): &[b"foo"]
const CMD: &str = "running-in-miri\0";
let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?;
let foo = ecx.memory_mut().allocate_static_bytes(b"foo\0").with_default_tag();
let foo_ty = ecx.tcx.mk_imm_ptr(ecx.tcx.types.u8);
let foo_layout = ecx.layout_of(foo_ty)?;
let foo_place = ecx.allocate(foo_layout, MiriMemoryKind::Env.into())?;
ecx.write_scalar(Scalar::Ptr(foo), foo_place.into())?;
ecx.memory_mut().mark_immutable(foo_place.to_ptr()?.alloc_id)?;
let argv = foo_place.ptr;
ecx.write_scalar(argv, dest)?;
let argv_place = ecx.allocate(dest.layout, MiriMemoryKind::Env.into())?;
ecx.write_scalar(argv, argv_place.into())?;
ecx.machine.argv = Some(argv_place.ptr.to_ptr()?);
let cmd = ecx.memory_mut().allocate_static_bytes(CMD.as_bytes()).with_default_tag();
let raw_str_layout = ecx.layout_of(ecx.tcx.mk_imm_ptr(ecx.tcx.types.u8))?;
let cmd_place = ecx.allocate(raw_str_layout, MiriMemoryKind::Env.into())?;
ecx.write_scalar(Scalar::Ptr(cmd), cmd_place.into())?;
ecx.memory_mut().mark_immutable(cmd_place.to_ptr()?.alloc_id)?;
// Store argv for macOS _NSGetArgv
{
let argv = cmd_place.ptr;
ecx.write_scalar(argv, dest)?;
let argv_place = ecx.allocate(dest.layout, MiriMemoryKind::Env.into())?;
ecx.write_scalar(argv, argv_place.into())?;
ecx.machine.argv = Some(argv_place.ptr.to_ptr()?);
}
// Store cmdline as UTF-16 for Windows GetCommandLineW
{
let tcx = &{ecx.tcx.tcx};
let cmd_utf16: Vec<u16> = CMD.encode_utf16().collect();
let cmd_ptr = ecx.memory_mut().allocate(
Size::from_bytes(cmd_utf16.len() as u64 * 2),
Align::from_bytes(2).unwrap(),
MiriMemoryKind::Env.into(),
)?.with_default_tag();
ecx.machine.cmd_line = Some(cmd_ptr);
// store the UTF-16 string
let char_size = Size::from_bytes(2);
let cmd_alloc = ecx.memory_mut().get_mut(cmd_ptr.alloc_id)?;
let mut cur_ptr = cmd_ptr;
for &c in cmd_utf16.iter() {
cmd_alloc.write_scalar(
tcx,
cur_ptr,
Scalar::from_uint(c, char_size).into(),
char_size,
)?;
cur_ptr = cur_ptr.offset(char_size, tcx)?;
}
}

assert!(args.next().is_none(), "start lang item has more arguments than expected");

Expand Down Expand Up @@ -263,8 +293,13 @@ pub struct Evaluator<'tcx> {

/// Program arguments (`Option` because we can only initialize them after creating the ecx).
/// These are *pointers* to argc/argv because macOS.
/// We also need the full cmdline as one string because Window.
pub(crate) argc: Option<Pointer<Borrow>>,
pub(crate) argv: Option<Pointer<Borrow>>,
pub(crate) cmd_line: Option<Pointer<Borrow>>,

/// Last OS error
pub(crate) last_error: u32,

/// TLS state
pub(crate) tls: TlsData<'tcx>,
Expand All @@ -282,6 +317,8 @@ impl<'tcx> Evaluator<'tcx> {
env_vars: HashMap::default(),
argc: None,
argv: None,
cmd_line: None,
last_error: 0,
tls: TlsData::default(),
validate,
stacked_borrows: stacked_borrows::State::default(),
Expand Down
2 changes: 0 additions & 2 deletions tests/run-pass/box-pair-to-vec.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
//ignore-msvc: Stdout not implemented on Windows

#[repr(C)]
#[derive(Debug)]
struct PairFoo {
Expand Down
1 change: 0 additions & 1 deletion tests/run-pass/catch.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
//ignore-msvc: Stdout not implemented on Windows
use std::panic::{catch_unwind, AssertUnwindSafe};

fn main() {
Expand Down
1 change: 0 additions & 1 deletion tests/run-pass/format.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
//ignore-msvc: Stdout not implemented on Windows
fn main() {
println!("Hello {}", 13);
}
1 change: 0 additions & 1 deletion tests/run-pass/hello.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
//ignore-msvc: Stdout not implemented on Windows
fn main() {
println!("Hello, world!");
}
2 changes: 1 addition & 1 deletion tests/run-pass/issue-17877.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
// except according to those terms.

//ignore-windows: Causes a stack overflow?!? Likely a rustc bug: https://github.com/rust-lang/rust/issues/53820
//Once that bug is fixed, increase the size to 16*1024 and enable on all platforms.
//FIXME: Once that bug is fixed, increase the size to 16*1024 and enable on all platforms.

#![feature(slice_patterns)]

Expand Down
1 change: 0 additions & 1 deletion tests/run-pass/issue-3794.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//ignore-msvc: Stdout not implemented on Windows
#![feature(box_syntax)]

trait T {
Expand Down