Skip to content

Commit 8de1110

Browse files
authored
Merge pull request rust-lang#201 from oli-obk/test_suite_fails
"Support" more libc functions
2 parents 522ac49 + 2b9cfb6 commit 8de1110

File tree

6 files changed

+220
-13
lines changed

6 files changed

+220
-13
lines changed

src/eval_context.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,10 @@ pub struct EvalContext<'a, 'tcx: 'a> {
4141
/// This prevents infinite loops and huge computations from freezing up const eval.
4242
/// Remove once halting problem is solved.
4343
pub(crate) steps_remaining: u64,
44+
45+
/// Environment variables set by `setenv`
46+
/// Miri does not expose env vars from the host to the emulated program
47+
pub(crate) env_vars: HashMap<Vec<u8>, Pointer>,
4448
}
4549

4650
/// A stack frame.
@@ -134,6 +138,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
134138
stack: Vec::new(),
135139
stack_limit: limits.stack_limit,
136140
steps_remaining: limits.step_limit,
141+
env_vars: HashMap::new(),
137142
}
138143
}
139144

src/terminator/intrinsic.rs

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -542,12 +542,11 @@ fn numeric_intrinsic<'tcx>(
542542
kind: PrimValKind
543543
) -> EvalResult<'tcx, PrimVal> {
544544
macro_rules! integer_intrinsic {
545-
($name:expr, $val:expr, $kind:expr, $method:ident) => ({
546-
let val = $val;
545+
($method:ident) => ({
547546
let bytes = val.to_bytes()?;
548547

549548
use value::PrimValKind::*;
550-
let result_bytes = match $kind {
549+
let result_bytes = match kind {
551550
I8 => (bytes as i8).$method() as u128,
552551
U8 => (bytes as u8).$method() as u128,
553552
I16 => (bytes as i16).$method() as u128,
@@ -558,18 +557,18 @@ fn numeric_intrinsic<'tcx>(
558557
U64 => (bytes as u64).$method() as u128,
559558
I128 => (bytes as i128).$method() as u128,
560559
U128 => bytes.$method() as u128,
561-
_ => bug!("invalid `{}` argument: {:?}", $name, val),
560+
_ => bug!("invalid `{}` argument: {:?}", name, val),
562561
};
563562

564563
PrimVal::Bytes(result_bytes)
565564
});
566565
}
567566

568567
let result_val = match name {
569-
"bswap" => integer_intrinsic!("bswap", val, kind, swap_bytes),
570-
"ctlz" => integer_intrinsic!("ctlz", val, kind, leading_zeros),
571-
"ctpop" => integer_intrinsic!("ctpop", val, kind, count_ones),
572-
"cttz" => integer_intrinsic!("cttz", val, kind, trailing_zeros),
568+
"bswap" => integer_intrinsic!(swap_bytes),
569+
"ctlz" => integer_intrinsic!(leading_zeros),
570+
"ctpop" => integer_intrinsic!(count_ones),
571+
"cttz" => integer_intrinsic!(trailing_zeros),
573572
_ => bug!("not a numeric intrinsic: {}", name),
574573
};
575574

src/terminator/mod.rs

Lines changed: 99 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -559,6 +559,42 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
559559
let usize = self.tcx.types.usize;
560560

561561
match &link_name[..] {
562+
"malloc" => {
563+
let size = self.value_to_primval(args[0], usize)?.to_u64()?;
564+
if size == 0 {
565+
self.write_primval(dest, PrimVal::Bytes(0), dest_ty)?;
566+
} else {
567+
let align = self.memory.pointer_size();
568+
let ptr = self.memory.allocate(size, align)?;
569+
self.write_primval(dest, PrimVal::Ptr(ptr), dest_ty)?;
570+
}
571+
}
572+
573+
"free" => {
574+
let ptr = args[0].read_ptr(&self.memory)?;
575+
if !ptr.is_null()? {
576+
self.memory.deallocate(ptr.to_ptr()?)?;
577+
}
578+
}
579+
580+
"syscall" => {
581+
match self.value_to_primval(args[0], usize)?.to_u64()? {
582+
511 => return Err(EvalError::Unimplemented("miri does not support random number generators".to_owned())),
583+
id => return Err(EvalError::Unimplemented(format!("miri does not support syscall id {}", id))),
584+
}
585+
}
586+
587+
"dlsym" => {
588+
let handle = args[0].read_ptr(&self.memory)?;
589+
{
590+
let symbol = args[1].read_ptr(&self.memory)?.to_ptr()?;
591+
let symbol_name = self.memory.read_c_str(symbol)?;
592+
let err = format!("bad c unicode symbol: {:?}", symbol_name);
593+
let symbol_name = ::std::str::from_utf8(symbol_name).unwrap_or(&err);
594+
return Err(EvalError::Unimplemented(format!("miri does not support dynamically loading libraries (requested symbol: {})", symbol_name)));
595+
}
596+
}
597+
562598
"__rust_allocate" => {
563599
let size = self.value_to_primval(args[0], usize)?.to_u64()?;
564600
let align = self.value_to_primval(args[1], usize)?.to_u64()?;
@@ -670,12 +706,63 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
670706
}
671707

672708
"getenv" => {
673-
{
709+
let result = {
674710
let name_ptr = args[0].read_ptr(&self.memory)?.to_ptr()?;
675711
let name = self.memory.read_c_str(name_ptr)?;
676-
info!("ignored env var request for `{:?}`", ::std::str::from_utf8(name));
712+
match self.env_vars.get(name) {
713+
Some(&var) => PrimVal::Ptr(var),
714+
None => PrimVal::Bytes(0),
715+
}
716+
};
717+
self.write_primval(dest, result, dest_ty)?;
718+
}
719+
720+
"unsetenv" => {
721+
let mut success = None;
722+
{
723+
let name_ptr = args[0].read_ptr(&self.memory)?;
724+
if !name_ptr.is_null()? {
725+
let name = self.memory.read_c_str(name_ptr.to_ptr()?)?;
726+
if !name.is_empty() && !name.contains(&b'=') {
727+
success = Some(self.env_vars.remove(name));
728+
}
729+
}
730+
}
731+
if let Some(old) = success {
732+
if let Some(var) = old {
733+
self.memory.deallocate(var)?;
734+
}
735+
self.write_primval(dest, PrimVal::Bytes(0), dest_ty)?;
736+
} else {
737+
self.write_primval(dest, PrimVal::from_i128(-1), dest_ty)?;
738+
}
739+
}
740+
741+
"setenv" => {
742+
let mut new = None;
743+
{
744+
let name_ptr = args[0].read_ptr(&self.memory)?;
745+
let value_ptr = args[1].read_ptr(&self.memory)?.to_ptr()?;
746+
let value = self.memory.read_c_str(value_ptr)?;
747+
if !name_ptr.is_null()? {
748+
let name = self.memory.read_c_str(name_ptr.to_ptr()?)?;
749+
if !name.is_empty() && !name.contains(&b'=') {
750+
new = Some((name.to_owned(), value.to_owned()));
751+
}
752+
}
753+
}
754+
if let Some((name, value)) = new {
755+
// +1 for the null terminator
756+
let value_copy = self.memory.allocate((value.len() + 1) as u64, 1)?;
757+
self.memory.write_bytes(value_copy, &value)?;
758+
self.memory.write_bytes(value_copy.offset(value.len() as u64, self.memory.layout)?, &[0])?;
759+
if let Some(var) = self.env_vars.insert(name.to_owned(), value_copy) {
760+
self.memory.deallocate(var)?;
761+
}
762+
self.write_primval(dest, PrimVal::Bytes(0), dest_ty)?;
763+
} else {
764+
self.write_primval(dest, PrimVal::from_i128(-1), dest_ty)?;
677765
}
678-
self.write_primval(dest, PrimVal::Bytes(0), dest_ty)?;
679766
}
680767

681768
"write" => {
@@ -696,6 +783,12 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
696783
self.write_primval(dest, PrimVal::Bytes(result as u128), dest_ty)?;
697784
}
698785

786+
"strlen" => {
787+
let ptr = args[0].read_ptr(&self.memory)?.to_ptr()?;
788+
let n = self.memory.read_c_str(ptr)?.len();
789+
self.write_primval(dest, PrimVal::Bytes(n as u128), dest_ty)?;
790+
}
791+
699792
// Some things needed for sys::thread initialization to go through
700793
"signal" | "sigaction" | "sigaltstack" => {
701794
self.write_primval(dest, PrimVal::Bytes(0), dest_ty)?;
@@ -705,10 +798,11 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
705798
let name = self.value_to_primval(args[0], usize)?.to_u64()?;
706799
trace!("sysconf() called with name {}", name);
707800
let result = match name {
708-
30 => 4096, // _SC_PAGESIZE
801+
30 => PrimVal::Bytes(4096), // _SC_PAGESIZE
802+
70 => PrimVal::from_i128(-1), // _SC_GETPW_R_SIZE_MAX
709803
_ => return Err(EvalError::Unimplemented(format!("Unimplemented sysconf name: {}", name)))
710804
};
711-
self.write_primval(dest, PrimVal::Bytes(result), dest_ty)?;
805+
self.write_primval(dest, result, dest_ty)?;
712806
}
713807

714808
"mmap" => {

src/value.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,14 @@ impl<'tcx> PrimVal {
226226
}
227227
}
228228

229+
pub fn is_null(self) -> EvalResult<'tcx, bool> {
230+
match self {
231+
PrimVal::Bytes(b) => Ok(b == 0),
232+
PrimVal::Ptr(_) => Ok(false),
233+
PrimVal::Undef => Err(EvalError::ReadUndefBytes),
234+
}
235+
}
236+
229237
pub fn signed_offset(self, i: i64, layout: &TargetDataLayout) -> EvalResult<'tcx, Self> {
230238
match self {
231239
PrimVal::Bytes(b) => {
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
12+
13+
#![feature(libc)]
14+
15+
extern crate libc;
16+
use std::ffi::CString;
17+
18+
mod mlibc {
19+
use libc::{c_char, size_t};
20+
21+
extern {
22+
#[link_name = "strlen"]
23+
pub fn my_strlen(str: *const c_char) -> size_t;
24+
}
25+
}
26+
27+
fn strlen(str: String) -> usize {
28+
// C string is terminated with a zero
29+
let s = CString::new(str).unwrap();
30+
unsafe {
31+
mlibc::my_strlen(s.as_ptr()) as usize
32+
}
33+
}
34+
35+
pub fn main() {
36+
let len = strlen("Rust".to_string());
37+
assert_eq!(len, 4);
38+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// pretty-expanded FIXME #23616
12+
13+
#![feature(libc)]
14+
15+
#![allow(dead_code)]
16+
17+
extern crate libc;
18+
use std::mem;
19+
20+
struct Arena(());
21+
22+
struct Bcx<'a> {
23+
fcx: &'a Fcx<'a>
24+
}
25+
26+
struct Fcx<'a> {
27+
arena: &'a Arena,
28+
ccx: &'a Ccx
29+
}
30+
31+
struct Ccx {
32+
x: isize
33+
}
34+
35+
fn alloc<'a>(_bcx : &'a Arena) -> &'a Bcx<'a> {
36+
unsafe {
37+
mem::transmute(libc::malloc(mem::size_of::<Bcx<'a>>()
38+
as libc::size_t))
39+
}
40+
}
41+
42+
fn h<'a>(bcx : &'a Bcx<'a>) -> &'a Bcx<'a> {
43+
return alloc(bcx.fcx.arena);
44+
}
45+
46+
fn g(fcx : &Fcx) {
47+
let bcx = Bcx { fcx: fcx };
48+
let bcx2 = h(&bcx);
49+
unsafe {
50+
libc::free(mem::transmute(bcx2));
51+
}
52+
}
53+
54+
fn f(ccx : &Ccx) {
55+
let a = Arena(());
56+
let fcx = Fcx { arena: &a, ccx: ccx };
57+
return g(&fcx);
58+
}
59+
60+
pub fn main() {
61+
let ccx = Ccx { x: 0 };
62+
f(&ccx);
63+
}

0 commit comments

Comments
 (0)