[dependencies]
byteorder = { version = "1.1", features = ["i128"]}
-cargo_metadata = { version = "0.5", optional = true }
-regex = "0.2.2"
+cargo_metadata = { version = "0.6", optional = true }
+regex = "1.0"
lazy_static = "1.0"
env_logger = "0.5.0-rc.1"
log = "0.4"
[dev-dependencies]
compiletest_rs = { version = "0.3.4", features = ["tmp"] }
+colored = "1.6"
## Debugging
-You can get detailed, statement-by-statement traces by setting the `MIRI_LOG`
-environment variable to `trace`. These traces are indented based on call stack
-depth. You can get a much less verbose set of information with other logging
-levels such as `warn`.
+Since the heart of miri (the main interpreter engine) lives in rustc, tracing
+the interpreter requires a version of rustc compiled with tracing. To this
+end, you will have to compile your own rustc:
+```
+git clone https://github.com/rust-lang/rust/ rustc
+cd rustc
+cp config.toml.example config.toml
+# Now edit `config.toml` and set `debug-assertions = true`
+./x.py build
+rustup toolchain link custom build/x86_64-unknown-linux-gnu/stage2
+```
+The `build` step can take 30 to 60 minutes.
+
+Now, in the miri directory, you can `rustup override set custom` and re-build
+everything. Finally, if you now set `RUST_LOG=rustc_mir::interpret=trace` as
+environment variable, you will get detailed step-by-step tracing information.
## Running miri on your own project('s test suite)
Now you can run miri against the libstd compiled by xargo:
```sh
-MIRI_SYSROOT=~/.xargo/HOST cargo run --bin miri tests/run-pass-fullmir/vecs.rs
+MIRI_SYSROOT=~/.xargo/HOST cargo run --bin miri tests/run-pass-fullmir/hashmap.rs
```
Notice that you will have to re-run the last step of the preparations above when
your toolchain changes (e.g., when you update the nightly).
+You can also set `-Zmiri-start-fn` to make miri start evaluation with the
+`start_fn` lang item, instead of starting at the `main` function.
+
## Contributing and getting help
Check out the issues on this GitHub repository for some ideas. There's lots that
control.after_hir_lowering.callback = Box::new(after_hir_lowering);
let start_fn = this.start_fn;
control.after_analysis.callback = Box::new(move |state| after_analysis(state, start_fn));
- if sess.target.target != sess.host {
- // only fully compile targets on the host. linking will fail for cross-compilation.
- control.after_analysis.stop = Compilation::Stop;
- }
+ control.after_analysis.stop = Compilation::Stop;
control
}
}
);
} else if let Some((entry_node_id, _, _)) = *state.session.entry_fn.borrow() {
let entry_def_id = tcx.hir.local_def_id(entry_node_id);
- let start_wrapper = tcx.lang_items().start_fn().and_then(|start_fn| {
- if use_start_fn {
- Some(start_fn)
- } else {
- None
- }
- });
+ // Use start_fn lang item if we have -Zmiri-start-fn set
+ let start_wrapper = if use_start_fn {
+ Some(tcx.lang_items().start_fn().unwrap())
+ } else {
+ None
+ };
miri::eval_main(tcx, entry_def_id, start_wrapper);
state.session.abort_if_errors();
}
});
- // Make sure we always have all the MIR (e.g. for auxilary builds in unit tests).
- args.push("-Zalways-encode-mir".to_owned());
-
rustc_driver::run_compiler(&args, Box::new(MiriCompilerCalls {
default: Box::new(RustcDefaultCalls),
start_fn,
self.write_null(dest, dest_ty)?;
} else {
let align = self.tcx.data_layout.pointer_align;
- let ptr = self.memory.allocate(Size::from_bytes(size), align, Some(MemoryKind::C.into()))?;
+ let ptr = self.memory.allocate(Size::from_bytes(size), align, MemoryKind::C.into())?;
self.write_scalar(dest, Scalar::Ptr(ptr), dest_ty)?;
}
}
)?;
let mut args = self.frame().mir.args_iter();
- let arg_local = args.next().ok_or(
+ let arg_local = args.next().ok_or_else(||
EvalErrorKind::AbiViolation(
"Argument to __rust_maybe_catch_panic does not take enough arguments."
.to_owned(),
let value_copy = self.memory.allocate(
Size::from_bytes((value.len() + 1) as u64),
Align::from_bytes(1, 1).unwrap(),
- Some(MemoryKind::Env.into()),
+ MemoryKind::Env.into(),
)?;
self.memory.write_bytes(value_copy.into(), &value)?;
let trailing_zero_ptr = value_copy.offset(Size::from_bytes(value.len() as u64), &self)?.into();
// Figure out how large a pthread TLS key actually is. This is libc::pthread_key_t.
let key_type = args[0].ty.builtin_deref(true)
- .ok_or(EvalErrorKind::AbiViolation("Wrong signature used for pthread_key_create: First argument must be a raw pointer.".to_owned()))?.ty;
+ .ok_or_else(|| EvalErrorKind::AbiViolation("Wrong signature used for pthread_key_create: First argument must be a raw pointer.".to_owned()))?.ty;
let key_size = self.layout_of(key_type)?.size;
// Create key and write it into the memory where key_ptr wants it
}
let ptr = self.memory.allocate(Size::from_bytes(size),
Align::from_bytes(align, align).unwrap(),
- Some(MemoryKind::Rust.into()))?;
+ MemoryKind::Rust.into())?;
self.write_scalar(dest, Scalar::Ptr(ptr), dest_ty)?;
}
"alloc::alloc::::__rust_alloc_zeroed" => {
}
let ptr = self.memory.allocate(Size::from_bytes(size),
Align::from_bytes(align, align).unwrap(),
- Some(MemoryKind::Rust.into()))?;
+ MemoryKind::Rust.into())?;
self.memory.write_repeat(ptr.into(), 0, Size::from_bytes(size))?;
self.write_scalar(dest, Scalar::Ptr(ptr), dest_ty)?;
}
// current frame.
self.dump_local(dest);
self.goto_block(dest_block);
- return Ok(());
+ Ok(())
}
fn write_null(&mut self, dest: Place, dest_ty: Ty<'tcx>) -> EvalResult<'tcx> {
}
// FIXME: assuming here that type size is < i64::max_value()
let pointee_size = self.layout_of(pointee_ty)?.size.bytes() as i64;
- return if let Some(offset) = offset.checked_mul(pointee_size) {
+ if let Some(offset) = offset.checked_mul(pointee_size) {
let ptr = ptr.ptr_signed_offset(offset, self)?;
// Do not do bounds-checking for integers; they can never alias a normal pointer anyway.
if let Scalar::Ptr(ptr) = ptr {
Ok(ptr)
} else {
err!(Overflow(mir::BinOp::Mul))
- };
+ }
}
fn value_to_isize(
inclusive_range_methods,
)]
+#![cfg_attr(feature = "cargo-clippy", allow(cast_lossless))]
+
#[macro_use]
extern crate log;
use rustc::ty::subst::Subst;
use rustc::hir::def_id::DefId;
use rustc::mir;
-use rustc::middle::const_val;
use rustc_data_structures::fx::FxHasher;
// Return value
let size = ecx.tcx.data_layout.pointer_size;
let align = ecx.tcx.data_layout.pointer_align;
- let ret_ptr = ecx.memory_mut().allocate(size, align, Some(MemoryKind::Stack))?;
+ let ret_ptr = ecx.memory_mut().allocate(size, align, MemoryKind::Stack)?;
cleanup_ptr = Some(ret_ptr);
// Push our stack frame
let foo = ecx.memory.allocate_bytes(b"foo\0");
let ptr_size = ecx.memory.pointer_size();
let ptr_align = ecx.tcx.data_layout.pointer_align;
- let foo_ptr = ecx.memory.allocate(ptr_size, ptr_align, None)?;
+ let foo_ptr = ecx.memory.allocate(ptr_size, ptr_align, MemoryKind::Stack)?;
ecx.memory.write_scalar(foo_ptr.into(), ptr_align, Scalar::Ptr(foo), ptr_size, false)?;
ecx.memory.mark_static_initialized(foo_ptr.alloc_id, Mutability::Immutable)?;
ecx.write_ptr(dest, foo_ptr.into(), ty)?;
block.terminator().source_info.span
};
- let mut err = const_val::struct_error(ecx.tcx.tcx.at(span), "constant evaluation error");
+ let mut err = struct_error(ecx.tcx.tcx.at(span), "constant evaluation error");
let (frames, span) = ecx.generate_stacktrace(None);
err.span_label(span, e.to_string());
- for const_val::FrameInfo { span, location, .. } in frames {
+ for FrameInfo { span, location, .. } in frames {
err.span_note(span, &format!("inside call to `{}`", location));
}
err.emit();
let ptr = ecx.memory.allocate(
layout.size,
layout.align,
- None,
+ MemoryKind::Stack,
)?;
// Step 4: Cache allocation id for recursive statics
let frame = ecx.frame_mut();
let bb = &frame.mir.basic_blocks()[frame.block];
if bb.statements.len() == frame.stmt && !bb.is_cleanup {
- match bb.terminator().kind {
- ::rustc::mir::TerminatorKind::Return => {
- for (local, _local_decl) in mir.local_decls.iter_enumerated().skip(1) {
- // Don't deallocate locals, because the return value might reference them
- frame.storage_dead(local);
- }
+ if let ::rustc::mir::TerminatorKind::Return = bb.terminator().kind {
+ for (local, _local_decl) in mir.local_decls.iter_enumerated().skip(1) {
+ // Don't deallocate locals, because the return value might reference them
+ frame.storage_dead(local);
}
- _ => {}
}
}
}
value: Value::Scalar(Scalar::from_u128(match layout.size.bytes() {
0 => 1 as u128,
size => size as u128,
- }.into())),
+ })),
ty: usize,
},
dest,
// All is well
continue 'locks;
}
- } else {
- if !is_our_lock {
- // All is well.
- continue 'locks;
- }
+ } else if !is_our_lock {
+ // All is well.
+ continue 'locks;
}
// If we get here, releasing this is an error except for NoLock.
if lock.active != NoLock {
}
// Clean up the map
alloc_locks.retain(|lock| match lock.active {
- NoLock => lock.suspended.len() > 0,
+ NoLock => !lock.suspended.is_empty(),
_ => true,
});
}
.expect("Offset called on non-ptr type")
.ty;
let ptr = self.pointer_offset(
- left.into(),
+ left,
pointee_ty,
right.to_bits(self.memory.pointer_size())? as i64,
)?;
// At the same time the `end` is irrelevant for the sorting and range searching, but used for the check.
// This kind of search breaks, if `end < start`, so don't do that!
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug)]
-struct Range {
+pub struct Range {
start: u64,
end: u64, // Invariant: end > start
}
F: FnMut(&T) -> bool,
{
let mut remove = Vec::new();
- for (range, data) in self.map.iter() {
+ for (range, data) in &self.map {
if !f(data) {
remove.push(*range);
}
},
);
trace!("New TLS key allocated: {} with dtor {:?}", new_key, dtor);
- return new_key;
+ new_key
}
fn delete_tls_key(&mut self, key: TlsKey) -> EvalResult<'tcx> {
- return match self.data.thread_local.remove(&key) {
+ match self.data.thread_local.remove(&key) {
Some(_) => {
trace!("TLS key {} removed", key);
Ok(())
}
None => err!(TlsOutOfBounds),
- };
+ }
}
fn load_tls(&mut self, key: TlsKey) -> EvalResult<'tcx, Scalar> {
- return match self.data.thread_local.get(&key) {
+ match self.data.thread_local.get(&key) {
Some(&TlsEntry { data, .. }) => {
trace!("TLS key {} loaded: {:?}", key, data);
Ok(data)
}
None => err!(TlsOutOfBounds),
- };
+ }
}
fn store_tls(&mut self, key: TlsKey, new_data: Scalar) -> EvalResult<'tcx> {
- return match self.data.thread_local.get_mut(&key) {
+ match self.data.thread_local.get_mut(&key) {
Some(&mut TlsEntry { ref mut data, .. }) => {
trace!("TLS key {} stored: {:?}", key, new_data);
*data = new_data;
Ok(())
}
None => err!(TlsOutOfBounds),
- };
+ }
}
/// Returns a dtor, its argument and its index, if one is supposed to run
}
}
}
- return Ok(None);
+ Ok(None)
}
}
Place::undef(),
StackPopCleanup::None,
)?;
- let arg_local = self.frame().mir.args_iter().next().ok_or(
- EvalErrorKind::AbiViolation("TLS dtor does not take enough arguments.".to_owned()),
+ let arg_local = self.frame().mir.args_iter().next().ok_or_else(
+ || EvalErrorKind::AbiViolation("TLS dtor does not take enough arguments.".to_owned()),
)?;
let dest = self.eval_place(&mir::Place::Local(arg_local))?;
let ty = self.tcx.mk_mut_ptr(self.tcx.types.u8);
use rustc::traits::{self, TraitEngine};
use rustc::infer::InferCtxt;
use rustc::middle::region;
-use rustc::middle::const_val::ConstVal;
+use rustc::mir::interpret::{ConstValue};
use rustc_data_structures::indexed_vec::Idx;
use rustc_mir::interpret::HasMemory;
}
fn abstract_place(&self, place: &mir::Place<'tcx>) -> EvalResult<'tcx, AbsPlace<'tcx>> {
- Ok(match place {
- &mir::Place::Local(l) => AbsPlace::Local(l),
- &mir::Place::Static(ref s) => AbsPlace::Static(s.def_id),
- &mir::Place::Projection(ref p) =>
+ Ok(match *place {
+ mir::Place::Local(l) => AbsPlace::Local(l),
+ mir::Place::Static(ref s) => AbsPlace::Static(s.def_id),
+ mir::Place::Projection(ref p) =>
AbsPlace::Projection(Box::new(self.abstract_place_projection(&*p)?)),
})
}
mut layout: ty::layout::TyLayout<'tcx>,
i: usize,
) -> EvalResult<'tcx, Ty<'tcx>> {
- match base {
- Place::Ptr { extra: PlaceExtra::DowncastVariant(variant_index), .. } => {
- layout = layout.for_variant(&self, variant_index);
- }
- _ => {}
+ if let Place::Ptr { extra: PlaceExtra::DowncastVariant(variant_index), .. } = base {
+ layout = layout.for_variant(&self, variant_index);
}
let tcx = self.tcx.tcx;
Ok(match layout.ty.sty {
// Inner lifetimes *outlive* outer ones, so only if we have no lifetime restriction yet,
// we record the region of this borrow to the context.
if query.re == None {
- match *region {
- ReScope(scope) => query.re = Some(scope),
- // It is possible for us to encounter erased lifetimes here because the lifetimes in
- // this functions' Subst will be erased.
- _ => {}
+ if let ReScope(scope) = *region {
+ query.re = Some(scope);
}
+ // It is possible for us to encounter erased lifetimes here because the lifetimes in
+ // this functions' Subst will be erased.
}
self.validate_ptr(val, query.place.0, pointee_ty, query.re, query.mutbl, mode)?;
}
}
TyArray(elem_ty, len) => {
let len = match len.val {
- ConstVal::Unevaluated(def_id, substs) => {
+ ConstValue::Unevaluated(def_id, substs) => {
self.tcx.const_eval(self.tcx.param_env(def_id).and(GlobalId {
instance: Instance::new(def_id, substs),
promoted: None,
}))
.map_err(|_err|EvalErrorKind::MachineError("<already reported>".to_string()))?
}
- ConstVal::Value(_) => len,
+ _ => len,
};
let len = len.unwrap_usize(self.tcx.tcx);
for i in 0..len {
let variant_idx = self.read_discriminant_as_variant_index(query.place.1, query.ty)?;
let variant = &adt.variants[variant_idx];
- if variant.fields.len() > 0 {
+ if !variant.fields.is_empty() {
// Downcast to this variant, if needed
let place = if adt.is_enum() {
(
--- /dev/null
+#![feature(alloc, allocator_api)]
+
+extern crate alloc;
+
+use alloc::alloc::Global;
+use std::alloc::*;
+
+// error-pattern: incorrect alloc info: expected size 1 and align 2, got size 1 and align 1
+
+fn main() {
+ unsafe {
+ let x = Global.alloc(Layout::from_size_align_unchecked(1, 1)).unwrap();
+ Global.dealloc(x, Layout::from_size_align_unchecked(1, 2));
+ }
+}
--- /dev/null
+#![feature(alloc, allocator_api)]
+
+extern crate alloc;
+
+use alloc::alloc::Global;
+use std::alloc::*;
+
+// error-pattern: incorrect alloc info: expected size 2 and align 1, got size 1 and align 1
+
+fn main() {
+ unsafe {
+ let x = Global.alloc(Layout::from_size_align_unchecked(1, 1)).unwrap();
+ Global.dealloc(x, Layout::from_size_align_unchecked(2, 1));
+ }
+}
--- /dev/null
+#![feature(alloc, allocator_api)]
+
+extern crate alloc;
+
+use alloc::alloc::Global;
+use std::alloc::*;
+
+// error-pattern: tried to deallocate dangling pointer
+
+fn main() {
+ unsafe {
+ let x = Global.alloc(Layout::from_size_align_unchecked(1, 1)).unwrap();
+ Global.dealloc(x, Layout::from_size_align_unchecked(1, 1));
+ Global.dealloc(x, Layout::from_size_align_unchecked(1, 1));
+ }
+}
--- /dev/null
+// error-pattern: pointer computed at offset 5, outside bounds of allocation
+fn main() {
+ let v = [0i8; 4];
+ let x = &v as *const i8;
+ // The error is inside another function, so we cannot match it by line
+ let x = unsafe { x.offset(5) };
+ panic!("this should never print: {:?}", x);
+}
--- /dev/null
+// error-pattern: attempt to add with overflow
+fn main() {
+ let v = [0i8; 4];
+ let x = &v as *const i8;
+ let x = unsafe { x.offset(-1) };
+ panic!("this should never print: {:?}", x);
+}
--- /dev/null
+//error-pattern: attempt to add with overflow
+fn main() {
+ let v = [1i8, 2];
+ let x = &v[1] as *const i8;
+ let _ = unsafe { x.offset(isize::min_value()) };
+}
--- /dev/null
+#![feature(alloc, allocator_api)]
+
+extern crate alloc;
+
+use alloc::alloc::Global;
+use std::alloc::*;
+
+// error-pattern: incorrect alloc info: expected size 2 and align 1, got size 1 and align 1
+
+fn main() {
+ unsafe {
+ let x = Global.alloc(Layout::from_size_align_unchecked(1, 1)).unwrap();
+ let _y = Global.realloc(x, Layout::from_size_align_unchecked(2, 1), 1).unwrap();
+ }
+}
--- /dev/null
+#![feature(alloc, allocator_api)]
+
+extern crate alloc;
+
+use alloc::alloc::Global;
+use std::alloc::*;
+
+fn main() {
+ unsafe {
+ let x = Global.alloc(Layout::from_size_align_unchecked(1, 1)).unwrap();
+ let _y = Global.realloc(x, Layout::from_size_align_unchecked(1, 1), 1).unwrap();
+ let _z = *(x.as_ptr() as *mut u8); //~ ERROR constant evaluation error [E0080]
+ //~^ NOTE dangling pointer was dereferenced
+ }
+}
--- /dev/null
+#![feature(alloc, allocator_api)]
+
+extern crate alloc;
+
+use alloc::alloc::Global;
+use std::alloc::*;
+
+// error-pattern: dangling pointer was dereferenced
+
+fn main() {
+ unsafe {
+ let x = Global.alloc(Layout::from_size_align_unchecked(1, 1)).unwrap();
+ Global.dealloc(x, Layout::from_size_align_unchecked(1, 1));
+ Global.realloc(x, Layout::from_size_align_unchecked(1, 1), 1).unwrap();
+ }
+}
--- /dev/null
+// error-pattern: tried to deallocate Stack memory but gave Machine(Rust) as the kind
+
+fn main() {
+ let x = 42;
+ let bad_box = unsafe { std::mem::transmute::<&i32, Box<i32>>(&x) };
+ drop(bad_box);
+}
+++ /dev/null
-// This should fail even without validation
-// compile-flags: -Zmir-emit-validate=0
-
-fn main() {
- let v: Vec<u8> = Vec::with_capacity(10);
- let undef = unsafe { *v.get_unchecked(5) };
- let x = undef + 1; //~ ERROR: attempted to read undefined bytes
- panic!("this should never print: {}", x);
-}
+++ /dev/null
-#![feature(alloc, allocator_api)]
-
-extern crate alloc;
-
-use alloc::alloc::Global;
-use std::alloc::*;
-
-// error-pattern: incorrect alloc info: expected size 1 and align 2, got size 1 and align 1
-
-fn main() {
- unsafe {
- let x = Global.alloc(Layout::from_size_align_unchecked(1, 1));
- Global.dealloc(x, Layout::from_size_align_unchecked(1, 2));
- }
-}
+++ /dev/null
-#![feature(alloc, allocator_api)]
-
-extern crate alloc;
-
-use alloc::alloc::Global;
-use std::alloc::*;
-
-// error-pattern: incorrect alloc info: expected size 2 and align 1, got size 1 and align 1
-
-fn main() {
- unsafe {
- let x = Global.alloc(Layout::from_size_align_unchecked(1, 1));
- Global.dealloc(x, Layout::from_size_align_unchecked(2, 1));
- }
-}
+++ /dev/null
-#![feature(alloc, allocator_api)]
-
-extern crate alloc;
-
-use alloc::alloc::Global;
-use std::alloc::*;
-
-// error-pattern: tried to deallocate dangling pointer
-
-fn main() {
- unsafe {
- let x = Global.alloc(Layout::from_size_align_unchecked(1, 1));
- Global.dealloc(x, Layout::from_size_align_unchecked(1, 1));
- Global.dealloc(x, Layout::from_size_align_unchecked(1, 1));
- }
-}
+// ignore-test FIXME: we are not checking these things on match any more?
+
fn main() {
assert!(std::char::from_u32(-1_i32 as u32).is_none());
match unsafe { std::mem::transmute::<i32, char>(-1) } { //~ ERROR constant evaluation error [E0080]
+// ignore-test FIXME: leak detection is disabled
//error-pattern: the evaluated program leaked memory
fn main() {
+// ignore-test FIXME: leak detection is disabled
//error-pattern: the evaluated program leaked memory
use std::rc::Rc;
+++ /dev/null
-// error-pattern: pointer computed at offset 5, outside bounds of allocation
-fn main() {
- let v = [0i8; 4];
- let x = &v as *const i8;
- // The error is inside another function, so we cannot match it by line
- let x = unsafe { x.offset(5) };
- panic!("this should never print: {:?}", x);
-}
+++ /dev/null
-// error-pattern: attempt to add with overflow
-fn main() {
- let v = [0i8; 4];
- let x = &v as *const i8;
- let x = unsafe { x.offset(-1) };
- panic!("this should never print: {:?}", x);
-}
fn main() {
// Make sure we catch overflows that would be hidden by first casting the RHS to u32
let _n = 1i64 >> (u32::max_value() as i64 + 1); //~ ERROR constant evaluation error [E0080]
- //~^ NOTE suiriuruihrihue
+ //~^ NOTE attempt to shift right with overflow
}
+//ignore-windows
// FIXME: Something in panic handling fails validation with full-MIR
// compile-flags: -Zmir-emit-validate=0
//error-pattern: the evaluated program panicked
+++ /dev/null
-//error-pattern: attempt to add with overflow
-fn main() {
- let v = [1i8, 2];
- let x = &v[1] as *const i8;
- let _ = unsafe { x.offset(isize::min_value()) };
-}
+++ /dev/null
-#![feature(alloc, allocator_api)]
-
-extern crate alloc;
-
-use alloc::alloc::Global;
-use std::alloc::*;
-
-// error-pattern: incorrect alloc info: expected size 2 and align 1, got size 1 and align 1
-
-fn main() {
- unsafe {
- let x = Global.alloc(Layout::from_size_align_unchecked(1, 1));
- let _y = Global.realloc(x, Layout::from_size_align_unchecked(2, 1), 1);
- }
-}
+++ /dev/null
-#![feature(alloc, allocator_api)]
-
-extern crate alloc;
-
-use alloc::alloc::Global;
-use std::alloc::*;
-
-fn main() {
- unsafe {
- let x = Global.alloc(Layout::from_size_align_unchecked(1, 1));
- let _y = Global.realloc(x, Layout::from_size_align_unchecked(1, 1), 1);
- let _z = *(x as *mut u8); //~ ERROR constant evaluation error [E0080]
- //~^ NOTE dangling pointer was dereferenced
- }
-}
+++ /dev/null
-#![feature(alloc, allocator_api)]
-
-extern crate alloc;
-
-use alloc::alloc::Global;
-use std::alloc::*;
-
-// error-pattern: dangling pointer was dereferenced
-
-fn main() {
- unsafe {
- let x = Global.alloc(Layout::from_size_align_unchecked(1, 1));
- Global.dealloc(x, Layout::from_size_align_unchecked(1, 1));
- Global.realloc(x, Layout::from_size_align_unchecked(1, 1), 1);
- }
-}
+++ /dev/null
-// error-pattern: tried to deallocate Stack memory but gave Machine(Rust) as the kind
-
-fn main() {
- let x = 42;
- let bad_box = unsafe { std::mem::transmute::<&i32, Box<i32>>(&x) };
- drop(bad_box);
-}
+// ignore-test FIXME: we are not making these statics read-only any more?
static X: usize = 5;
#[allow(mutable_transmutes)]
--- /dev/null
+// This should fail even without validation
+// compile-flags: -Zmir-emit-validate=0
+
+fn main() {
+ let v: Vec<u8> = Vec::with_capacity(10);
+ let undef = unsafe { *v.get_unchecked(5) };
+ let x = undef + 1; //~ ERROR: error
+ //~^ NOTE attempted to read undefined bytes
+ panic!("this should never print: {}", x);
+}
#![feature(slice_concat_ext)]
extern crate compiletest_rs as compiletest;
+extern crate colored;
+
+use colored::*;
use std::slice::SliceConcatExt;
use std::path::{PathBuf, Path};
option_env!("RUSTC_LIB_PATH").unwrap().into()
}
-fn compile_fail(sysroot: &Path, path: &str, target: &str, host: &str, fullmir: bool) {
- eprintln!(
+fn have_fullmir() -> bool {
+ // We assume we have full MIR when MIRI_SYSROOT is set or when we are in rustc
+ std::env::var("MIRI_SYSROOT").is_ok() || rustc_test_suite().is_some()
+}
+
+fn compile_fail(sysroot: &Path, path: &str, target: &str, host: &str, need_fullmir: bool) {
+ if need_fullmir && !have_fullmir() {
+ eprintln!("{}", format!(
+ "## Skipping compile-fail tests in {} against miri for target {} due to missing mir",
+ path,
+ target
+ ).yellow().bold());
+ return;
+ }
+
+ eprintln!("{}", format!(
"## Running compile-fail tests in {} against miri for target {}",
path,
target
- );
+ ).green().bold());
let mut config = compiletest::Config::default().tempdir();
config.mode = "compile-fail".parse().expect("Invalid mode");
config.rustc_path = miri_path();
config.run_lib_path = rustc_lib_path();
config.compile_lib_path = rustc_lib_path();
}
- // if we are building as part of the rustc test suite, we already have fullmir for everything
- if fullmir && rustc_test_suite().is_none() {
- if host != target {
- // skip fullmir on nonhost
- return;
- }
- let sysroot = std::env::home_dir().unwrap()
- .join(".xargo")
- .join("HOST");
- flags.push(format!("--sysroot {}", sysroot.to_str().unwrap()));
- config.src_base = PathBuf::from(path.to_string());
- } else {
- flags.push(format!("--sysroot {}", sysroot.to_str().unwrap()));
- config.src_base = PathBuf::from(path.to_string());
- }
+ flags.push(format!("--sysroot {}", sysroot.display()));
+ config.src_base = PathBuf::from(path.to_string());
flags.push("-Zmir-emit-validate=1".to_owned());
config.target_rustcflags = Some(flags.join(" "));
config.target = target.to_owned();
+ config.host = host.to_owned();
compiletest::run_tests(&config);
}
-fn run_pass(path: &str) {
- eprintln!("## Running run-pass tests in {} against rustc", path);
+fn rustc_pass(sysroot: &Path, path: &str) {
+ eprintln!("{}", format!("## Running run-pass tests in {} against rustc", path).green().bold());
let mut config = compiletest::Config::default().tempdir();
config.mode = "run-pass".parse().expect("Invalid mode");
config.src_base = PathBuf::from(path);
config.rustc_path = rustc_path;
config.run_lib_path = rustc_lib_path();
config.compile_lib_path = rustc_lib_path();
- config.target_rustcflags = Some(format!("-Dwarnings --sysroot {}", get_sysroot().display()));
+ config.target_rustcflags = Some(format!("-Dwarnings --sysroot {}", sysroot.display()));
} else {
config.target_rustcflags = Some("-Dwarnings".to_owned());
}
compiletest::run_tests(&config);
}
-fn miri_pass(path: &str, target: &str, host: &str, fullmir: bool, opt: bool) {
+fn miri_pass(sysroot: &Path, path: &str, target: &str, host: &str, need_fullmir: bool, opt: bool) {
+ if need_fullmir && !have_fullmir() {
+ eprintln!("{}", format!(
+ "## Skipping run-pass tests in {} against miri for target {} due to missing mir",
+ path,
+ target
+ ).yellow().bold());
+ return;
+ }
+
let opt_str = if opt { " with optimizations" } else { "" };
- eprintln!(
+ eprintln!("{}", format!(
"## Running run-pass tests in {} against miri for target {}{}",
path,
target,
opt_str
- );
+ ).green().bold());
let mut config = compiletest::Config::default().tempdir();
config.mode = "ui".parse().expect("Invalid mode");
config.src_base = PathBuf::from(path);
config.compile_lib_path = rustc_lib_path();
}
let mut flags = Vec::new();
- // Control miri logging. This is okay despite concurrent test execution as all tests
- // will set this env var to the same value.
- env::set_var("MIRI_LOG", "warn");
- // if we are building as part of the rustc test suite, we already have fullmir for everything
- if fullmir && rustc_test_suite().is_none() {
- if host != target {
- // skip fullmir on nonhost
- return;
- }
- let sysroot = std::env::home_dir().unwrap()
- .join(".xargo")
- .join("HOST");
-
+ flags.push(format!("--sysroot {}", sysroot.display()));
+ if have_fullmir() {
flags.push("-Zmiri-start-fn".to_owned());
- flags.push(format!("--sysroot {}", sysroot.to_str().unwrap()));
}
if opt {
flags.push("-Zmir-opt-level=3".to_owned());
// For now, only validate without optimizations. Inlining breaks validation.
flags.push("-Zmir-emit-validate=1".to_owned());
}
+ // Control miri logging. This is okay despite concurrent test execution as all tests
+ // will set this env var to the same value.
+ env::set_var("MIRI_LOG", "warn");
config.target_rustcflags = Some(flags.join(" "));
compiletest::run_tests(&config);
}
let host = get_host();
for_all_targets(&sysroot, |target| {
- miri_pass("tests/run-pass", &target, &host, false, opt);
+ miri_pass(&sysroot, "tests/run-pass", &target, &host, false, opt);
});
- miri_pass("tests/run-pass-fullmir", &host, &host, true, opt);
-}
-
-#[test]
-fn run_pass_miri_noopt() {
- run_pass_miri(false);
+ miri_pass(&sysroot, "tests/run-pass-fullmir", &host, &host, true, opt);
}
-#[test]
-#[ignore] // FIXME: Disabled for now, as the optimizer is pretty broken and crashes...
-fn run_pass_miri_opt() {
- run_pass_miri(true);
-}
-
-#[test]
fn run_pass_rustc() {
- run_pass("tests/run-pass");
- run_pass("tests/run-pass-fullmir");
+ let sysroot = get_sysroot();
+ rustc_pass(&sysroot, "tests/run-pass");
+ rustc_pass(&sysroot, "tests/run-pass-fullmir");
}
-#[test]
-#[should_panic] // TODO: update test errors
fn compile_fail_miri() {
let sysroot = get_sysroot();
let host = get_host();
// FIXME: run tests for other targets, too
- compile_fail(&sysroot, "tests/compile-fail", &host, &host, true);
-
+ compile_fail(&sysroot, "tests/compile-fail", &host, &host, false);
compile_fail(&sysroot, "tests/compile-fail-fullmir", &host, &host, true);
}
+
+#[test]
+fn test() {
+ // We put everything into a single test to avoid the parallelism `cargo test`
+ // introduces. We still get parallelism within our tests because `compiletest`
+ // uses `libtest` which runs jobs in parallel.
+
+ run_pass_rustc();
+
+ run_pass_miri(false);
+
+ // FIXME: Disabled for now, as the optimizer is pretty broken and crashes...
+ // See https://github.com/rust-lang/rust/issues/50411
+ //run_pass_miri(true);
+
+ compile_fail_miri();
+}
+++ /dev/null
-//ignore-msvc
-#![feature(box_syntax)]
-
-fn make_box() -> Box<(i16, i16)> {
- Box::new((1, 2))
-}
-
-fn make_box_syntax() -> Box<(i16, i16)> {
- box (1, 2)
-}
-
-fn allocate_reallocate() {
- let mut s = String::new();
-
- // 6 byte heap alloc (__rust_allocate)
- s.push_str("foobar");
- assert_eq!(s.len(), 6);
- assert_eq!(s.capacity(), 6);
-
- // heap size doubled to 12 (__rust_reallocate)
- s.push_str("baz");
- assert_eq!(s.len(), 9);
- assert_eq!(s.capacity(), 12);
-
- // heap size reduced to 9 (__rust_reallocate)
- s.shrink_to_fit();
- assert_eq!(s.len(), 9);
- assert_eq!(s.capacity(), 9);
-}
-
-fn main() {
- assert_eq!(*make_box(), (1, 2));
- assert_eq!(*make_box_syntax(), (1, 2));
- allocate_reallocate();
-}
+++ /dev/null
-// Copyright 2014 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.
-
-//ignore-msvc
-
-#![feature(slice_patterns)]
-
-fn main() {
- let mut x: &[_] = &[1, 2, 3, 4];
-
- let mut result = vec!();
- loop {
- x = match *x {
- [1, n, 3, ref rest..] => {
- result.push(n);
- rest
- }
- [n, ref rest..] => {
- result.push(n);
- rest
- }
- [] =>
- break
- }
- }
- assert_eq!(result, [2, 4]);
-}
+++ /dev/null
-// 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.
-
-//ignore-msvc
-
-#![allow(unused_features, unused_variables)]
-#![feature(box_syntax)]
-
-fn test(foo: Box<Vec<isize>> ) { assert_eq!((*foo)[0], 10); }
-
-pub fn main() {
- let x = box vec![10];
- // Test forgetting a local by move-in
- test(x);
-}
+++ /dev/null
-// 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.
-
-// FIXME: We handle uninitialzied storage here, which currently makes validation fail.
-// compile-flags: -Zmir-emit-validate=0
-
-//ignore-msvc
-
-#![feature(libc)]
-
-#![allow(dead_code)]
-
-extern crate libc;
-use std::mem;
-
-struct Arena(());
-
-struct Bcx<'a> {
- fcx: &'a Fcx<'a>
-}
-
-struct Fcx<'a> {
- arena: &'a Arena,
- ccx: &'a Ccx
-}
-
-struct Ccx {
- x: isize
-}
-
-fn alloc<'a>(_bcx : &'a Arena) -> &'a Bcx<'a> {
- unsafe {
- mem::transmute(libc::malloc(mem::size_of::<Bcx<'a>>()
- as libc::size_t))
- }
-}
-
-fn h<'a>(bcx : &'a Bcx<'a>) -> &'a Bcx<'a> {
- return alloc(bcx.fcx.arena);
-}
-
-fn g(fcx : &Fcx) {
- let bcx = Bcx { fcx: fcx };
- let bcx2 = h(&bcx);
- unsafe {
- libc::free(mem::transmute(bcx2));
- }
-}
-
-fn f(ccx : &Ccx) {
- let a = Arena(());
- let fcx = Fcx { arena: &a, ccx: ccx };
- return g(&fcx);
-}
-
-pub fn main() {
- let ccx = Ccx { x: 0 };
- f(&ccx);
-}
+++ /dev/null
-//ignore-msvc
-
-fn make_vec() -> Vec<u8> {
- let mut v = Vec::with_capacity(4);
- v.push(1);
- v.push(2);
- v
-}
-
-fn make_vec_macro() -> Vec<u8> {
- vec![1, 2]
-}
-
-fn make_vec_macro_repeat() -> Vec<u8> {
- vec![42; 5]
-}
-
-fn make_vec_macro_repeat_zeroed() -> Vec<u8> {
- vec![0; 7]
-}
-
-fn vec_into_iter() -> u8 {
- vec![1, 2, 3, 4]
- .into_iter()
- .map(|x| x * x)
- .fold(0, |x, y| x + y)
-}
-
-fn vec_into_iter_zst() -> usize {
- vec![[0u64; 0], [0u64; 0]]
- .into_iter()
- .map(|x| x.len())
- .sum()
-}
-
-fn vec_reallocate() -> Vec<u8> {
- let mut v = vec![1, 2];
- v.push(3);
- v.push(4);
- v.push(5);
- v
-}
-
-fn main() {
- assert_eq!(vec_reallocate().len(), 5);
- assert_eq!(vec_into_iter(), 30);
- assert_eq!(vec_into_iter_zst(), 0);
- assert_eq!(make_vec().capacity(), 4);
- assert_eq!(make_vec_macro(), [1, 2]);
- assert_eq!(make_vec_macro_repeat(), [42; 5]);
- assert_eq!(make_vec_macro_repeat_zeroed(), [0; 7]);
-}
+++ /dev/null
-// aux-build:dep.rs
-
-// ignore-cross-compile
-
-extern crate dep;
-
-fn main() {
- dep::foo();
-}
+++ /dev/null
-pub fn foo() {}
--- /dev/null
+//ignore-msvc
+#![feature(box_syntax)]
+
+fn make_box() -> Box<(i16, i16)> {
+ Box::new((1, 2))
+}
+
+fn make_box_syntax() -> Box<(i16, i16)> {
+ box (1, 2)
+}
+
+fn allocate_reallocate() {
+ let mut s = String::new();
+
+ // 6 byte heap alloc (__rust_allocate)
+ s.push_str("foobar");
+ assert_eq!(s.len(), 6);
+ assert_eq!(s.capacity(), 6);
+
+ // heap size doubled to 12 (__rust_reallocate)
+ s.push_str("baz");
+ assert_eq!(s.len(), 9);
+ assert_eq!(s.capacity(), 12);
+
+ // heap size reduced to 9 (__rust_reallocate)
+ s.shrink_to_fit();
+ assert_eq!(s.len(), 9);
+ assert_eq!(s.capacity(), 9);
+}
+
+fn main() {
+ assert_eq!(*make_box(), (1, 2));
+ assert_eq!(*make_box_syntax(), (1, 2));
+ allocate_reallocate();
+}
--- /dev/null
+// Copyright 2014 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.
+
+//ignore-msvc
+
+#![feature(slice_patterns)]
+
+fn main() {
+ let mut x: &[_] = &[1, 2, 3, 4];
+
+ let mut result = vec!();
+ loop {
+ x = match *x {
+ [1, n, 3, ref rest..] => {
+ result.push(n);
+ rest
+ }
+ [n, ref rest..] => {
+ result.push(n);
+ rest
+ }
+ [] =>
+ break
+ }
+ }
+ assert_eq!(result, [2, 4]);
+}
--- /dev/null
+// 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.
+
+//ignore-msvc
+
+#![allow(unused_features, unused_variables)]
+#![feature(box_syntax)]
+
+fn test(foo: Box<Vec<isize>> ) { assert_eq!((*foo)[0], 10); }
+
+pub fn main() {
+ let x = box vec![10];
+ // Test forgetting a local by move-in
+ test(x);
+}
--- /dev/null
+// 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.
+
+// FIXME: We handle uninitialized storage here, which currently makes validation fail.
+// compile-flags: -Zmir-emit-validate=0
+
+//ignore-msvc
+
+#![feature(libc)]
+
+#![allow(dead_code)]
+
+extern crate libc;
+use std::mem;
+
+struct Arena(());
+
+struct Bcx<'a> {
+ fcx: &'a Fcx<'a>
+}
+
+struct Fcx<'a> {
+ arena: &'a Arena,
+ ccx: &'a Ccx
+}
+
+struct Ccx {
+ x: isize
+}
+
+fn alloc<'a>(_bcx : &'a Arena) -> &'a Bcx<'a> {
+ unsafe {
+ mem::transmute(libc::malloc(mem::size_of::<Bcx<'a>>()
+ as libc::size_t))
+ }
+}
+
+fn h<'a>(bcx : &'a Bcx<'a>) -> &'a Bcx<'a> {
+ return alloc(bcx.fcx.arena);
+}
+
+fn g(fcx : &Fcx) {
+ let bcx = Bcx { fcx: fcx };
+ let bcx2 = h(&bcx);
+ unsafe {
+ libc::free(mem::transmute(bcx2));
+ }
+}
+
+fn f(ccx : &Ccx) {
+ let a = Arena(());
+ let fcx = Fcx { arena: &a, ccx: ccx };
+ return g(&fcx);
+}
+
+pub fn main() {
+ let ccx = Ccx { x: 0 };
+ f(&ccx);
+}
--- /dev/null
+//ignore-msvc
+
+fn make_vec() -> Vec<u8> {
+ let mut v = Vec::with_capacity(4);
+ v.push(1);
+ v.push(2);
+ v
+}
+
+fn make_vec_macro() -> Vec<u8> {
+ vec![1, 2]
+}
+
+fn make_vec_macro_repeat() -> Vec<u8> {
+ vec![42; 5]
+}
+
+fn make_vec_macro_repeat_zeroed() -> Vec<u8> {
+ vec![0; 7]
+}
+
+fn vec_into_iter() -> u8 {
+ vec![1, 2, 3, 4]
+ .into_iter()
+ .map(|x| x * x)
+ .fold(0, |x, y| x + y)
+}
+
+fn vec_into_iter_zst() -> usize {
+ vec![[0u64; 0], [0u64; 0]]
+ .into_iter()
+ .map(|x| x.len())
+ .sum()
+}
+
+fn vec_reallocate() -> Vec<u8> {
+ let mut v = vec![1, 2];
+ v.push(3);
+ v.push(4);
+ v.push(5);
+ v
+}
+
+fn main() {
+ assert_eq!(vec_reallocate().len(), 5);
+ assert_eq!(vec_into_iter(), 30);
+ assert_eq!(vec_into_iter_zst(), 0);
+ assert_eq!(make_vec().capacity(), 4);
+ assert_eq!(make_vec_macro(), [1, 2]);
+ assert_eq!(make_vec_macro_repeat(), [42; 5]);
+ assert_eq!(make_vec_macro_repeat_zeroed(), [0; 7]);
+}