Skip to content

Commit

Permalink
implement GetCommandLineW, GetEnvironmentVariableW, GetConsoleScreenB…
Browse files Browse the repository at this point in the history
…ufferInfo, SetConsoleTextAttribute, GetSystemInfo
  • Loading branch information
RalfJung committed Dec 19, 2018
1 parent e7c523f commit af4fb66
Show file tree
Hide file tree
Showing 2 changed files with 93 additions and 23 deletions.
47 changes: 39 additions & 8 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 Down Expand Up @@ -649,6 +672,14 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a,
// 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
69 changes: 54 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,56 @@ 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";
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()
.chain(Some(0)) // add 0-terminator
.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 +295,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 +319,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

0 comments on commit af4fb66

Please sign in to comment.