Store env vars where necessary
This commit is contained in:
parent
5414825f09
commit
f22c7e43df
4 changed files with 114 additions and 5 deletions
|
@ -41,6 +41,10 @@ pub struct EvalContext<'a, 'tcx: 'a> {
|
|||
/// This prevents infinite loops and huge computations from freezing up const eval.
|
||||
/// Remove once halting problem is solved.
|
||||
pub(crate) steps_remaining: u64,
|
||||
|
||||
/// Environment variables set by `setenv`
|
||||
/// Miri does not expose env vars from the host to the emulated program
|
||||
pub(crate) env_vars: HashMap<Vec<u8>, Pointer>,
|
||||
}
|
||||
|
||||
/// A stack frame.
|
||||
|
@ -134,6 +138,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
|||
stack: Vec::new(),
|
||||
stack_limit: limits.stack_limit,
|
||||
steps_remaining: limits.step_limit,
|
||||
env_vars: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -670,12 +670,63 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
|||
}
|
||||
|
||||
"getenv" => {
|
||||
{
|
||||
let result = {
|
||||
let name_ptr = args[0].read_ptr(&self.memory)?.to_ptr()?;
|
||||
let name = self.memory.read_c_str(name_ptr)?;
|
||||
info!("ignored env var request for `{:?}`", ::std::str::from_utf8(name));
|
||||
match self.env_vars.get(name) {
|
||||
Some(&var) => PrimVal::Ptr(var),
|
||||
None => PrimVal::Bytes(0),
|
||||
}
|
||||
};
|
||||
self.write_primval(dest, result, dest_ty)?;
|
||||
}
|
||||
|
||||
"unsetenv" => {
|
||||
let mut success = None;
|
||||
{
|
||||
let name_ptr = args[0].read_ptr(&self.memory)?;
|
||||
if !name_ptr.is_null()? {
|
||||
let name = self.memory.read_c_str(name_ptr.to_ptr()?)?;
|
||||
if !name.is_empty() && !name.contains(&b'=') {
|
||||
success = Some(self.env_vars.remove(name));
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some(old) = success {
|
||||
if let Some(var) = old {
|
||||
self.memory.deallocate(var)?;
|
||||
}
|
||||
self.write_primval(dest, PrimVal::Bytes(0), dest_ty)?;
|
||||
} else {
|
||||
self.write_primval(dest, PrimVal::from_i128(-1), dest_ty)?;
|
||||
}
|
||||
}
|
||||
|
||||
"setenv" => {
|
||||
let mut new = None;
|
||||
{
|
||||
let name_ptr = args[0].read_ptr(&self.memory)?;
|
||||
let value_ptr = args[1].read_ptr(&self.memory)?.to_ptr()?;
|
||||
let value = self.memory.read_c_str(value_ptr)?;
|
||||
if !name_ptr.is_null()? {
|
||||
let name = self.memory.read_c_str(name_ptr.to_ptr()?)?;
|
||||
if !name.is_empty() && !name.contains(&b'=') {
|
||||
new = Some((name.to_owned(), value.to_owned()));
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some((name, value)) = new {
|
||||
// +1 for the null terminator
|
||||
let value_copy = self.memory.allocate((value.len() + 1) as u64, 1)?;
|
||||
self.memory.write_bytes(value_copy, &value)?;
|
||||
self.memory.write_bytes(value_copy.offset(value.len() as u64, self.memory.layout)?, &[0])?;
|
||||
if let Some(var) = self.env_vars.insert(name.to_owned(), value_copy) {
|
||||
self.memory.deallocate(var)?;
|
||||
}
|
||||
self.write_primval(dest, PrimVal::Bytes(0), dest_ty)?;
|
||||
} else {
|
||||
self.write_primval(dest, PrimVal::from_i128(-1), dest_ty)?;
|
||||
}
|
||||
}
|
||||
|
||||
"write" => {
|
||||
|
@ -696,6 +747,12 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
|||
self.write_primval(dest, PrimVal::Bytes(result as u128), dest_ty)?;
|
||||
}
|
||||
|
||||
"strlen" => {
|
||||
let ptr = args[0].read_ptr(&self.memory)?.to_ptr()?;
|
||||
let n = self.memory.read_c_str(ptr)?.len();
|
||||
self.write_primval(dest, PrimVal::Bytes(n as u128), dest_ty)?;
|
||||
}
|
||||
|
||||
// Some things needed for sys::thread initialization to go through
|
||||
"signal" | "sigaction" | "sigaltstack" => {
|
||||
self.write_primval(dest, PrimVal::Bytes(0), dest_ty)?;
|
||||
|
@ -705,10 +762,11 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
|||
let name = self.value_to_primval(args[0], usize)?.to_u64()?;
|
||||
trace!("sysconf() called with name {}", name);
|
||||
let result = match name {
|
||||
30 => 4096, // _SC_PAGESIZE
|
||||
30 => PrimVal::Bytes(4096), // _SC_PAGESIZE
|
||||
70 => PrimVal::from_i128(-1), // _SC_GETPW_R_SIZE_MAX
|
||||
_ => return Err(EvalError::Unimplemented(format!("Unimplemented sysconf name: {}", name)))
|
||||
};
|
||||
self.write_primval(dest, PrimVal::Bytes(result), dest_ty)?;
|
||||
self.write_primval(dest, result, dest_ty)?;
|
||||
}
|
||||
|
||||
"mmap" => {
|
||||
|
|
|
@ -205,6 +205,14 @@ impl<'tcx> PrimVal {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn is_null(self) -> EvalResult<'tcx, bool> {
|
||||
match self {
|
||||
PrimVal::Bytes(b) => Ok(b == 0),
|
||||
PrimVal::Ptr(_) => Ok(false),
|
||||
PrimVal::Undef => Err(EvalError::ReadUndefBytes),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn signed_offset(self, i: i64, layout: &TargetDataLayout) -> EvalResult<'tcx, Self> {
|
||||
match self {
|
||||
PrimVal::Bytes(b) => {
|
||||
|
|
38
tests/run-pass-fullmir/foreign-fn-linkname.rs
Normal file
38
tests/run-pass-fullmir/foreign-fn-linkname.rs
Normal file
|
@ -0,0 +1,38 @@
|
|||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
|
||||
#![feature(std_misc, libc)]
|
||||
|
||||
extern crate libc;
|
||||
use std::ffi::CString;
|
||||
|
||||
mod mlibc {
|
||||
use libc::{c_char, size_t};
|
||||
|
||||
extern {
|
||||
#[link_name = "strlen"]
|
||||
pub fn my_strlen(str: *const c_char) -> size_t;
|
||||
}
|
||||
}
|
||||
|
||||
fn strlen(str: String) -> usize {
|
||||
// C string is terminated with a zero
|
||||
let s = CString::new(str).unwrap();
|
||||
unsafe {
|
||||
mlibc::my_strlen(s.as_ptr()) as usize
|
||||
}
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
let len = strlen("Rust".to_string());
|
||||
assert_eq!(len, 4);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue