# See the `src/tools/rustc-workspace-hack/README.md` file in `rust-lang/rust`
# for more information.
rustc-workspace-hack = "1.0.0"
+hex = "0.3.2"
+rand = "0.6.5"
[build-dependencies]
vergen = "3"
fn visit_item(&mut self, i: &'hir hir::Item) {
if let hir::ItemKind::Fn(.., body_id) = i.node {
if i.attrs.iter().any(|attr| attr.check_name("test")) {
- let config = MiriConfig { validate: true, args: vec![] };
+ let config = MiriConfig { validate: true, args: vec![], seed: None };
let did = self.0.hir().body_owner_def_id(body_id);
println!("running test: {}", self.0.def_path_debug_str(did));
miri::eval_main(self.0, did, config);
}
tcx.hir().krate().visit_all_item_likes(&mut Visitor(tcx));
} else if let Some((entry_def_id, _)) = tcx.entry_fn(LOCAL_CRATE) {
- let config = MiriConfig { validate: true, args: vec![] };
+ let config = MiriConfig { validate: true, args: vec![], seed: None };
miri::eval_main(tcx, entry_def_id, config);
compiler.session().abort_if_errors();
// Parse our arguments and split them across `rustc` and `miri`.
let mut validate = true;
+ let mut seed: Option<u64> = None;
let mut rustc_args = vec![];
let mut miri_args = vec![];
let mut after_dashdash = false;
after_dashdash = true;
}
_ => {
- rustc_args.push(arg);
+ let split: Vec<String> = arg.split("-Zmiri-seed=").map(|s| s.to_owned()).collect();
+ if split.len() == 2 {
+ if seed.is_some() {
+ panic!("Cannot specify -Zmiri-seed multiple times!");
+ }
+ let seed_raw = hex::decode(&split[1]).unwrap();
+ if seed_raw.len() > 8 {
+ panic!(format!("-Zmiri-seed must be at most 8 bytes, was {}", seed_raw.len()));
+ }
+
+ let mut bytes = [0; 8];
+ bytes[..seed_raw.len()].copy_from_slice(&hex::decode(&split[1]).unwrap());
+ seed = Some(u64::from_be_bytes(bytes));
+ } else {
+ rustc_args.push(arg);
+ }
}
}
}
debug!("rustc arguments: {:?}", rustc_args);
debug!("miri arguments: {:?}", miri_args);
- let miri_config = miri::MiriConfig { validate, args: miri_args };
+ let miri_config = miri::MiriConfig { validate, args: miri_args, seed };
let result = rustc_driver::report_ices_to_stderr_if_any(move || {
rustc_driver::run_compiler(&rustc_args, &mut MiriCompilerCalls { miri_config }, None, None)
}).and_then(|result| result);
use rustc::mir;
use syntax::attr;
+use rand::RngCore;
+
use crate::*;
impl<'a, 'mir, 'tcx> EvalContextExt<'a, 'mir, 'tcx> for crate::MiriEvalContext<'a, 'mir, 'tcx> {}
// is called if a `HashMap` is created the regular way.
match this.read_scalar(args[0])?.to_usize(this)? {
318 | 511 => {
- return err!(Unimplemented(
- "miri does not support random number generators".to_owned(),
- ))
+ match this.machine.rng.as_ref() {
+ Some(rng) => {
+ let ptr = this.read_scalar(args[1])?.to_ptr()?;
+ let len = this.read_scalar(args[2])?.to_usize(this)?;
+
+ // The only supported flags are GRND_RANDOM and GRND_NONBLOCK,
+ // neither of which have any effect on our current PRNG
+ let _flags = this.read_scalar(args[3])?.to_i32()?;
+
+ let mut data = vec![0; len as usize];
+ rng.borrow_mut().fill_bytes(&mut data);
+
+ this.memory_mut().get_mut(ptr.alloc_id)?
+ .write_bytes(tcx, ptr, &data)?;
+
+ this.write_scalar(Scalar::from_uint(len, dest.layout.size), dest)?;
+
+ },
+ None => {
+ return err!(Unimplemented(
+ "miri does not support random number generators in deterministic mode!
+ Use '-Zmiri-seed=<seed>' to enable random number generation".to_owned(),
+ ))
+ }
+ }
+
}
id => {
return err!(Unimplemented(
use std::collections::HashMap;
use std::borrow::Cow;
+use std::cell::RefCell;
+
+use rand::rngs::StdRng;
+use rand::SeedableRng;
use rustc::ty::{self, TyCtxt, query::TyCtxtAt};
use rustc::ty::layout::{LayoutOf, Size, Align};
pub struct MiriConfig {
pub validate: bool,
pub args: Vec<String>,
+
+ // The seed to use when non-determinism is required (e.g. getrandom())
+ pub seed: Option<u64>
}
// Used by priroda.
let mut ecx = InterpretCx::new(
tcx.at(syntax::source_map::DUMMY_SP),
ty::ParamEnv::reveal_all(),
- Evaluator::new(config.validate),
+ Evaluator::new(config.validate, config.seed),
);
let main_instance = ty::Instance::mono(ecx.tcx.tcx, main_id);
/// Stacked Borrows state.
pub(crate) stacked_borrows: stacked_borrows::State,
+
+ /// The random number generator to use if Miri
+ /// is running in non-deterministic mode
+ pub(crate) rng: Option<RefCell<StdRng>>
}
impl<'tcx> Evaluator<'tcx> {
- fn new(validate: bool) -> Self {
+ fn new(validate: bool, seed: Option<u64>) -> Self {
Evaluator {
env_vars: HashMap::default(),
argc: None,
tls: TlsData::default(),
validate,
stacked_borrows: stacked_borrows::State::default(),
+ rng: seed.map(|s| RefCell::new(StdRng::seed_from_u64(s)))
}
}
}
--- /dev/null
+#![feature(rustc_private)]
+extern crate libc;
+
+fn main() {
+ let mut buf = [0u8; 5];
+ unsafe {
+ libc::syscall(libc::SYS_getrandom, &mut buf as &mut [u8] as *mut [u8] as *mut u8 as *mut libc::c_void, 5, 0);
+ //~^ ERROR constant evaluation error: miri does not support random number generators in deterministic mode!
+ }
+}
+// compile-flags: -Zmiri-seed=0000000000000000
+
use std::collections::{self, HashMap};
-use std::hash::BuildHasherDefault;
+use std::hash::{BuildHasherDefault, BuildHasher};
-fn main() {
- let mut map : HashMap<i32, i32, BuildHasherDefault<collections::hash_map::DefaultHasher>> = Default::default();
+fn test_map<S: BuildHasher>(mut map: HashMap<i32, i32, S>) {
map.insert(0, 0);
assert_eq!(map.values().fold(0, |x, y| x+y), 0);
assert_eq!(map.values().fold(0, |x, y| x+y), num*(num-1)/2);
// TODO: Test Entry API, Iterators, ...
+
+}
+
+fn main() {
+ let map : HashMap<i32, i32, BuildHasherDefault<collections::hash_map::DefaultHasher>> = Default::default();
+ let map_normal: HashMap<i32, i32> = HashMap::new();
+
+ test_map(map);
+ test_map(map_normal);
}