Skip to content

Commit 8359898

Browse files
authored
Merge pull request #578 from RalfJung/misc
Test cargo-miri on Windows
2 parents d8956f0 + 750cd44 commit 8359898

File tree

9 files changed

+141
-34
lines changed

9 files changed

+141
-34
lines changed

appveyor.yml

+6-2
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,17 @@ build: false
2727
test_script:
2828
- set RUST_TEST_NOCAPTURE=1
2929
- set RUST_BACKTRACE=1
30-
# Build miri
30+
# Build and install miri
3131
- cargo build --release --all-features --all-targets
32+
- cargo install --all-features --force --path .
3233
# Get ourselves a MIR-full libstd, and use it henceforth
33-
- cargo run --release --all-features --bin cargo-miri -- miri setup
34+
- cargo miri setup
3435
- set MIRI_SYSROOT=%USERPROFILE%\AppData\Local\miri\miri\cache\HOST
3536
# Test miri
3637
- cargo test --release --all-features
38+
# Test cargo integration
39+
- cd test-cargo-miri
40+
- python3 run-test.py
3741

3842
notifications:
3943
- provider: Email

src/fn_call.rs

+82-10
Original file line numberDiff line numberDiff line change
@@ -562,27 +562,50 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a,
562562
},
563563

564564
// Windows API stubs
565+
"SetLastError" => {
566+
let err = this.read_scalar(args[0])?.to_u32()?;
567+
this.machine.last_error = err;
568+
}
569+
"GetLastError" => {
570+
this.write_scalar(Scalar::from_uint(this.machine.last_error, Size::from_bits(32)), dest)?;
571+
}
572+
565573
"AddVectoredExceptionHandler" => {
566574
// any non zero value works for the stdlib. This is just used for stackoverflows anyway
567575
this.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?;
568576
},
569577
"InitializeCriticalSection" |
570578
"EnterCriticalSection" |
571579
"LeaveCriticalSection" |
572-
"DeleteCriticalSection" |
573-
"SetLastError" => {
574-
// Function does not return anything, nothing to do
580+
"DeleteCriticalSection" => {
581+
// Nothing to do, not even a return value
575582
},
576583
"GetModuleHandleW" |
577584
"GetProcAddress" |
578-
"TryEnterCriticalSection" => {
585+
"TryEnterCriticalSection" |
586+
"GetConsoleScreenBufferInfo" |
587+
"SetConsoleTextAttribute" => {
579588
// pretend these do not exist/nothing happened, by returning zero
580589
this.write_null(dest)?;
581590
},
582-
"GetLastError" => {
583-
// this is c::ERROR_CALL_NOT_IMPLEMENTED
584-
this.write_scalar(Scalar::from_int(120, dest.layout.size), dest)?;
585-
},
591+
"GetSystemInfo" => {
592+
let system_info = this.deref_operand(args[0])?;
593+
let system_info_ptr = system_info.ptr.to_ptr()?;
594+
// initialize with 0
595+
this.memory_mut().get_mut(system_info_ptr.alloc_id)?
596+
.write_repeat(tcx, system_info_ptr, 0, system_info.layout.size)?;
597+
// set number of processors to 1
598+
let dword_size = Size::from_bytes(4);
599+
let offset = 2*dword_size + 3*tcx.pointer_size();
600+
this.memory_mut().get_mut(system_info_ptr.alloc_id)?
601+
.write_scalar(
602+
tcx,
603+
system_info_ptr.offset(offset, tcx)?,
604+
Scalar::from_int(1, dword_size).into(),
605+
dword_size,
606+
)?;
607+
}
608+
586609
"TlsAlloc" => {
587610
// This just creates a key; Windows does not natively support TLS dtors.
588611

@@ -596,18 +619,67 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a,
596619
this.write_scalar(Scalar::from_uint(key, dest.layout.size), dest)?;
597620
}
598621
"TlsGetValue" => {
599-
let key = this.read_scalar(args[0])?.to_bits(args[0].layout.size)?;
622+
let key = this.read_scalar(args[0])?.to_u32()? as u128;
600623
let ptr = this.machine.tls.load_tls(key)?;
601624
this.write_scalar(ptr, dest)?;
602625
}
603626
"TlsSetValue" => {
604-
let key = this.read_scalar(args[0])?.to_bits(args[0].layout.size)?;
627+
let key = this.read_scalar(args[0])?.to_u32()? as u128;
605628
let new_ptr = this.read_scalar(args[1])?.not_undef()?;
606629
this.machine.tls.store_tls(key, new_ptr)?;
607630

608631
// Return success (1)
609632
this.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?;
610633
}
634+
"GetStdHandle" => {
635+
let which = this.read_scalar(args[0])?.to_i32()?;
636+
// We just make this the identity function, so we know later in "WriteFile"
637+
// which one it is.
638+
this.write_scalar(Scalar::from_int(which, this.pointer_size()), dest)?;
639+
}
640+
"WriteFile" => {
641+
let handle = this.read_scalar(args[0])?.to_isize(this)?;
642+
let buf = this.read_scalar(args[1])?.not_undef()?;
643+
let n = this.read_scalar(args[2])?.to_u32()?;
644+
let written_place = this.deref_operand(args[3])?;
645+
this.write_null(written_place.into())?; // spec says we always write 0 first
646+
let written = if handle == -11 || handle == -12 {
647+
// stdout/stderr
648+
use std::io::{self, Write};
649+
650+
let buf_cont = this.memory().read_bytes(buf, Size::from_bytes(u64::from(n)))?;
651+
let res = if handle == -11 {
652+
io::stdout().write(buf_cont)
653+
} else {
654+
io::stderr().write(buf_cont)
655+
};
656+
res.ok().map(|n| n as u32)
657+
} else {
658+
eprintln!("Miri: Ignored output to handle {}", handle);
659+
Some(n) // pretend it all went well
660+
};
661+
// If there was no error, write back how much was written
662+
if let Some(n) = written {
663+
this.write_scalar(Scalar::from_uint(n, Size::from_bits(32)), written_place.into())?;
664+
}
665+
// Return whether this was a success
666+
this.write_scalar(
667+
Scalar::from_int(if written.is_some() { 1 } else { 0 }, dest.layout.size),
668+
dest,
669+
)?;
670+
}
671+
"GetConsoleMode" => {
672+
// Everything is a pipe
673+
this.write_null(dest)?;
674+
}
675+
"GetEnvironmentVariableW" => {
676+
// This is not the env var you are looking for
677+
this.machine.last_error = 203; // ERROR_ENVVAR_NOT_FOUND
678+
this.write_null(dest)?;
679+
}
680+
"GetCommandLineW" => {
681+
this.write_scalar(Scalar::Ptr(this.machine.cmd_line.unwrap()), dest)?;
682+
}
611683

612684
// We can't execute anything else
613685
_ => {

src/lib.rs

+52-15
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use std::borrow::Cow;
1818
use std::env;
1919

2020
use rustc::ty::{self, TyCtxt, query::TyCtxtAt};
21-
use rustc::ty::layout::{TyLayout, LayoutOf, Size};
21+
use rustc::ty::layout::{TyLayout, LayoutOf, Size, Align};
2222
use rustc::hir::{self, def_id::DefId};
2323
use rustc::mir;
2424

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

130133
// FIXME: extract main source file path
131134
// Third argument (argv): &[b"foo"]
135+
const CMD: &str = "running-in-miri\0";
132136
let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?;
133-
let foo = ecx.memory_mut().allocate_static_bytes(b"foo\0").with_default_tag();
134-
let foo_ty = ecx.tcx.mk_imm_ptr(ecx.tcx.types.u8);
135-
let foo_layout = ecx.layout_of(foo_ty)?;
136-
let foo_place = ecx.allocate(foo_layout, MiriMemoryKind::Env.into())?;
137-
ecx.write_scalar(Scalar::Ptr(foo), foo_place.into())?;
138-
ecx.memory_mut().mark_immutable(foo_place.to_ptr()?.alloc_id)?;
139-
let argv = foo_place.ptr;
140-
ecx.write_scalar(argv, dest)?;
141-
let argv_place = ecx.allocate(dest.layout, MiriMemoryKind::Env.into())?;
142-
ecx.write_scalar(argv, argv_place.into())?;
143-
ecx.machine.argv = Some(argv_place.ptr.to_ptr()?);
137+
let cmd = ecx.memory_mut().allocate_static_bytes(CMD.as_bytes()).with_default_tag();
138+
let raw_str_layout = ecx.layout_of(ecx.tcx.mk_imm_ptr(ecx.tcx.types.u8))?;
139+
let cmd_place = ecx.allocate(raw_str_layout, MiriMemoryKind::Env.into())?;
140+
ecx.write_scalar(Scalar::Ptr(cmd), cmd_place.into())?;
141+
ecx.memory_mut().mark_immutable(cmd_place.to_ptr()?.alloc_id)?;
142+
// Store argv for macOS _NSGetArgv
143+
{
144+
let argv = cmd_place.ptr;
145+
ecx.write_scalar(argv, dest)?;
146+
let argv_place = ecx.allocate(dest.layout, MiriMemoryKind::Env.into())?;
147+
ecx.write_scalar(argv, argv_place.into())?;
148+
ecx.machine.argv = Some(argv_place.ptr.to_ptr()?);
149+
}
150+
// Store cmdline as UTF-16 for Windows GetCommandLineW
151+
{
152+
let tcx = &{ecx.tcx.tcx};
153+
let cmd_utf16: Vec<u16> = CMD.encode_utf16().collect();
154+
let cmd_ptr = ecx.memory_mut().allocate(
155+
Size::from_bytes(cmd_utf16.len() as u64 * 2),
156+
Align::from_bytes(2).unwrap(),
157+
MiriMemoryKind::Env.into(),
158+
)?.with_default_tag();
159+
ecx.machine.cmd_line = Some(cmd_ptr);
160+
// store the UTF-16 string
161+
let char_size = Size::from_bytes(2);
162+
let cmd_alloc = ecx.memory_mut().get_mut(cmd_ptr.alloc_id)?;
163+
let mut cur_ptr = cmd_ptr;
164+
for &c in cmd_utf16.iter() {
165+
cmd_alloc.write_scalar(
166+
tcx,
167+
cur_ptr,
168+
Scalar::from_uint(c, char_size).into(),
169+
char_size,
170+
)?;
171+
cur_ptr = cur_ptr.offset(char_size, tcx)?;
172+
}
173+
}
144174

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

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

264294
/// Program arguments (`Option` because we can only initialize them after creating the ecx).
265295
/// These are *pointers* to argc/argv because macOS.
296+
/// We also need the full cmdline as one string because Window.
266297
pub(crate) argc: Option<Pointer<Borrow>>,
267298
pub(crate) argv: Option<Pointer<Borrow>>,
299+
pub(crate) cmd_line: Option<Pointer<Borrow>>,
300+
301+
/// Last OS error
302+
pub(crate) last_error: u32,
268303

269304
/// TLS state
270305
pub(crate) tls: TlsData<'tcx>,
@@ -282,6 +317,8 @@ impl<'tcx> Evaluator<'tcx> {
282317
env_vars: HashMap::default(),
283318
argc: None,
284319
argv: None,
320+
cmd_line: None,
321+
last_error: 0,
285322
tls: TlsData::default(),
286323
validate,
287324
stacked_borrows: stacked_borrows::State::default(),

tests/run-pass/box-pair-to-vec.rs

-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
//ignore-msvc: Stdout not implemented on Windows
2-
31
#[repr(C)]
42
#[derive(Debug)]
53
struct PairFoo {

tests/run-pass/catch.rs

-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
//ignore-msvc: Stdout not implemented on Windows
21
use std::panic::{catch_unwind, AssertUnwindSafe};
32

43
fn main() {

tests/run-pass/format.rs

-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
//ignore-msvc: Stdout not implemented on Windows
21
fn main() {
32
println!("Hello {}", 13);
43
}

tests/run-pass/hello.rs

-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
//ignore-msvc: Stdout not implemented on Windows
21
fn main() {
32
println!("Hello, world!");
43
}

tests/run-pass/issue-17877.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
// except according to those terms.
1010

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

1414
#![feature(slice_patterns)]
1515

tests/run-pass/issue-3794.rs

-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

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

1413
trait T {

0 commit comments

Comments
 (0)