Skip to content

Commit af4fb66

Browse files
committed
implement GetCommandLineW, GetEnvironmentVariableW, GetConsoleScreenBufferInfo, SetConsoleTextAttribute, GetSystemInfo
1 parent e7c523f commit af4fb66

File tree

2 files changed

+93
-23
lines changed

2 files changed

+93
-23
lines changed

src/fn_call.rs

+39-8
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

@@ -649,6 +672,14 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a,
649672
// Everything is a pipe
650673
this.write_null(dest)?;
651674
}
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+
}
652683

653684
// We can't execute anything else
654685
_ => {

src/lib.rs

+54-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,56 @@ 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";
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()
154+
.chain(Some(0)) // add 0-terminator
155+
.collect();
156+
let cmd_ptr = ecx.memory_mut().allocate(
157+
Size::from_bytes(cmd_utf16.len() as u64 * 2),
158+
Align::from_bytes(2).unwrap(),
159+
MiriMemoryKind::Env.into(),
160+
)?.with_default_tag();
161+
ecx.machine.cmd_line = Some(cmd_ptr);
162+
// store the UTF-16 string
163+
let char_size = Size::from_bytes(2);
164+
let cmd_alloc = ecx.memory_mut().get_mut(cmd_ptr.alloc_id)?;
165+
let mut cur_ptr = cmd_ptr;
166+
for &c in cmd_utf16.iter() {
167+
cmd_alloc.write_scalar(
168+
tcx,
169+
cur_ptr,
170+
Scalar::from_uint(c, char_size).into(),
171+
char_size,
172+
)?;
173+
cur_ptr = cur_ptr.offset(char_size, tcx)?;
174+
}
175+
}
144176

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

@@ -263,8 +295,13 @@ pub struct Evaluator<'tcx> {
263295

264296
/// Program arguments (`Option` because we can only initialize them after creating the ecx).
265297
/// These are *pointers* to argc/argv because macOS.
298+
/// We also need the full cmdline as one string because Window.
266299
pub(crate) argc: Option<Pointer<Borrow>>,
267300
pub(crate) argv: Option<Pointer<Borrow>>,
301+
pub(crate) cmd_line: Option<Pointer<Borrow>>,
302+
303+
/// Last OS error
304+
pub(crate) last_error: u32,
268305

269306
/// TLS state
270307
pub(crate) tls: TlsData<'tcx>,
@@ -282,6 +319,8 @@ impl<'tcx> Evaluator<'tcx> {
282319
env_vars: HashMap::default(),
283320
argc: None,
284321
argv: None,
322+
cmd_line: None,
323+
last_error: 0,
285324
tls: TlsData::default(),
286325
validate,
287326
stacked_borrows: stacked_borrows::State::default(),

0 commit comments

Comments
 (0)