From af4fb6655e9a09d4154250bcff99fc80eb2c402f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 19 Dec 2018 15:25:25 +0100 Subject: [PATCH] implement GetCommandLineW, GetEnvironmentVariableW, GetConsoleScreenBufferInfo, SetConsoleTextAttribute, GetSystemInfo --- src/fn_call.rs | 47 ++++++++++++++++++++++++++++------ src/lib.rs | 69 +++++++++++++++++++++++++++++++++++++++----------- 2 files changed, 93 insertions(+), 23 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index 7815c1ce40e1..16d18dbfe6dc 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -562,6 +562,14 @@ 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)?; @@ -569,20 +577,35 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, "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. @@ -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 _ => { diff --git a/src/lib.rs b/src/lib.rs index e41a92e55f72..bc5e8363e89e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -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; @@ -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 = 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"); @@ -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>, pub(crate) argv: Option>, + pub(crate) cmd_line: Option>, + + /// Last OS error + pub(crate) last_error: u32, /// TLS state pub(crate) tls: TlsData<'tcx>, @@ -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(),