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.
|
/// This prevents infinite loops and huge computations from freezing up const eval.
|
||||||
/// Remove once halting problem is solved.
|
/// Remove once halting problem is solved.
|
||||||
pub(crate) steps_remaining: u64,
|
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.
|
/// A stack frame.
|
||||||
|
@ -134,6 +138,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||||
stack: Vec::new(),
|
stack: Vec::new(),
|
||||||
stack_limit: limits.stack_limit,
|
stack_limit: limits.stack_limit,
|
||||||
steps_remaining: limits.step_limit,
|
steps_remaining: limits.step_limit,
|
||||||
|
env_vars: HashMap::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -670,12 +670,63 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
"getenv" => {
|
"getenv" => {
|
||||||
{
|
let result = {
|
||||||
let name_ptr = args[0].read_ptr(&self.memory)?.to_ptr()?;
|
let name_ptr = args[0].read_ptr(&self.memory)?.to_ptr()?;
|
||||||
let name = self.memory.read_c_str(name_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)?;
|
||||||
}
|
}
|
||||||
self.write_primval(dest, PrimVal::Bytes(0), dest_ty)?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
"write" => {
|
"write" => {
|
||||||
|
@ -696,6 +747,12 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||||
self.write_primval(dest, PrimVal::Bytes(result as u128), dest_ty)?;
|
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
|
// Some things needed for sys::thread initialization to go through
|
||||||
"signal" | "sigaction" | "sigaltstack" => {
|
"signal" | "sigaction" | "sigaltstack" => {
|
||||||
self.write_primval(dest, PrimVal::Bytes(0), dest_ty)?;
|
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()?;
|
let name = self.value_to_primval(args[0], usize)?.to_u64()?;
|
||||||
trace!("sysconf() called with name {}", name);
|
trace!("sysconf() called with name {}", name);
|
||||||
let result = match 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)))
|
_ => 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" => {
|
"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> {
|
pub fn signed_offset(self, i: i64, layout: &TargetDataLayout) -> EvalResult<'tcx, Self> {
|
||||||
match self {
|
match self {
|
||||||
PrimVal::Bytes(b) => {
|
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