-#![feature(custom_attribute)]
-#![allow(unused_attributes)]
-
-#[miri_run]
#[inline(never)]
pub fn main() {
assert_eq!(fib(10), 55);
-#![feature(custom_attribute)]
-#![allow(unused_attributes)]
-
-#[miri_run]
#[inline(never)]
pub fn main() {
assert_eq!(fib(10), 55);
-#![feature(custom_attribute)]
-#![allow(unused_attributes)]
-
-#[miri_run]
#[inline(never)]
pub fn main() {
}
use rustc_driver::{driver, CompilerCalls};
use rustc::ty::{TyCtxt, subst};
use rustc::mir::mir_map::MirMap;
+use rustc::mir::repr::Mir;
use rustc::hir::def_id::DefId;
+use rustc::hir::{map, ItemFn, Item};
+use syntax::codemap::Span;
struct MiriCompilerCalls;
control.after_analysis.callback = Box::new(|state| {
state.session.abort_if_errors();
- interpret_start_points(state.tcx.unwrap(), state.mir_map.unwrap());
+
+ let tcx = state.tcx.unwrap();
+ let mir_map = state.mir_map.unwrap();
+ let (span, mir, def_id) = get_main(tcx, mir_map);
+ println!("found `main` function at: {:?}", span);
+
+ let mut ecx = EvalContext::new(tcx, mir_map);
+ let substs = tcx.mk_substs(subst::Substs::empty());
+ let return_ptr = ecx.alloc_ret_ptr(mir.return_ty, substs).expect("main function should not be diverging");
+
+ ecx.push_stack_frame(def_id, mir.span, CachedMir::Ref(mir), substs, Some(return_ptr));
+
+ loop {
+ match step(&mut ecx) {
+ Ok(true) => {}
+ Ok(false) => break,
+ // FIXME: diverging functions can end up here in some future miri
+ Err(e) => {
+ report(tcx, &ecx, e);
+ break;
+ }
+ }
+ }
});
control
}
}
-
-
-fn interpret_start_points<'a, 'tcx>(
- tcx: TyCtxt<'a, 'tcx, 'tcx>,
- mir_map: &MirMap<'tcx>,
-) {
- let initial_indentation = ::log_settings::settings().indentation;
+fn get_main<'a, 'b, 'tcx: 'b>(tcx: TyCtxt<'a, 'tcx, 'tcx>, mir_map: &'b MirMap<'tcx>) -> (Span, &'b Mir<'tcx>, DefId) {
for (&id, mir) in &mir_map.map {
- for attr in tcx.map.attrs(id) {
- use syntax::attr::AttrMetaMethods;
- if attr.check_name("miri_run") {
- let item = tcx.map.expect_item(id);
-
- ::log_settings::settings().indentation = initial_indentation;
-
- debug!("Interpreting: {}", item.name);
-
- let mut ecx = EvalContext::new(tcx, mir_map);
- let substs = tcx.mk_substs(subst::Substs::empty());
- let return_ptr = ecx.alloc_ret_ptr(mir.return_ty, substs);
-
- ecx.push_stack_frame(tcx.map.local_def_id(id), mir.span, CachedMir::Ref(mir), substs, return_ptr);
-
- loop {
- match step(&mut ecx) {
- Ok(true) => {}
- Ok(false) => {
- match return_ptr {
- Some(ptr) => if log_enabled!(::log::LogLevel::Debug) {
- ecx.memory().dump(ptr.alloc_id);
- },
- None => warn!("diverging function returned"),
- }
- break;
- }
- // FIXME: diverging functions can end up here in some future miri
- Err(e) => {
- report(tcx, &ecx, e);
- break;
- }
- }
+ if let map::Node::NodeItem(&Item { name, span, ref node, .. }) = tcx.map.get(id) {
+ if let ItemFn(..) = *node {
+ if name.as_str() == "main" {
+ return (span, mir, tcx.map.local_def_id(id));
}
}
}
}
+ panic!("no main function found");
}
fn report(tcx: TyCtxt, ecx: &EvalContext, e: EvalError) {
--- /dev/null
+fn main() {
+ let p = {
+ let b = Box::new(42);
+ &*b as *const i32
+ };
+ let x = unsafe { *p }; //~ ERROR: dangling pointer was dereferenced
+ panic!("this should never print: {}", x);
+}
-#![feature(custom_attribute)]
-#![allow(dead_code, unused_attributes)]
-
fn f() {}
-#[miri_run]
-fn deref_fn_ptr() -> i32 {
- unsafe {
+fn main() {
+ let x: i32 = unsafe {
*std::mem::transmute::<fn(), *const i32>(f) //~ ERROR: tried to dereference a function pointer
- }
+ };
+ panic!("this should never print: {}", x);
}
-
-fn main() {}
+++ /dev/null
-#![feature(custom_attribute)]
-#![allow(dead_code, unused_attributes)]
-
-#[miri_run]
-fn overwriting_part_of_relocation_makes_the_rest_undefined() -> i32 {
- let mut p = &42;
- unsafe {
- let ptr: *mut _ = &mut p;
- *(ptr as *mut u8) = 123; // if we ever support 8 bit pointers, this is gonna cause
- // "attempted to interpret some raw bytes as a pointer address" instead of
- // "attempted to read undefined bytes"
- }
- *p //~ ERROR: attempted to read undefined bytes
-}
-
-#[miri_run]
-fn pointers_to_different_allocations_are_unorderable() -> bool {
- let x: *const u8 = &1;
- let y: *const u8 = &2;
- x < y //~ ERROR: attempted to do math or a comparison on pointers into different allocations
-}
-
-#[miri_run]
-fn invalid_bool() -> u8 {
- let b = unsafe { std::mem::transmute::<u8, bool>(2) };
- if b { 1 } else { 2 } //~ ERROR: invalid boolean value read
-}
-
-#[miri_run]
-fn undefined_byte_read() -> u8 {
- let v: Vec<u8> = Vec::with_capacity(10);
- let undef = unsafe { *v.get_unchecked(5) };
- undef + 1 //~ ERROR: attempted to read undefined bytes
-}
-
-#[miri_run]
-fn out_of_bounds_read() -> u8 {
- let v: Vec<u8> = vec![1, 2];
- unsafe { *v.get_unchecked(5) } //~ ERROR: memory access of 5..6 outside bounds of allocation 11 which has size 2
-}
-
-#[miri_run]
-fn dangling_pointer_deref() -> i32 {
- let p = {
- let b = Box::new(42);
- &*b as *const i32
- };
- unsafe { *p } //~ ERROR: dangling pointer was dereferenced
-}
-
-#[miri_run]
-fn wild_pointer_deref() -> i32 {
- let p = 42 as *const i32;
- unsafe { *p } //~ ERROR: attempted to interpret some raw bytes as a pointer address
-}
-
-#[miri_run]
-fn null_pointer_deref() -> i32 {
- unsafe { *std::ptr::null() } //~ ERROR: attempted to interpret some raw bytes as a pointer address
-}
-
-fn main() {}
-#![feature(custom_attribute, box_syntax)]
-#![allow(dead_code, unused_attributes)]
+#![feature(box_syntax)]
-#[miri_run]
-fn deref_fn_ptr() {
+fn main() {
//FIXME: this span is wrong
let x = box 42; //~ ERROR: tried to treat a memory pointer as a function pointer
unsafe {
f()
}
}
-
-fn main() {}
--- /dev/null
+fn main() {
+ let b = unsafe { std::mem::transmute::<u8, bool>(2) };
+ if b { unreachable!() } else { unreachable!() } //~ ERROR: invalid boolean value read
+}
--- /dev/null
+fn main() {
+ let x: i32 = unsafe { *std::ptr::null() }; //~ ERROR: attempted to interpret some raw bytes as a pointer address
+ panic!("this should never print: {}", x);
+}
--- /dev/null
+fn main() {
+ let v: Vec<u8> = vec![1, 2];
+ let x = unsafe { *v.get_unchecked(5) }; //~ ERROR: memory access of 5..6 outside bounds of allocation 29 which has size 2
+ panic!("this should never print: {}", x);
+}
--- /dev/null
+fn main() {
+ let mut p = &42;
+ unsafe {
+ let ptr: *mut _ = &mut p;
+ *(ptr as *mut u8) = 123; // if we ever support 8 bit pointers, this is gonna cause
+ // "attempted to interpret some raw bytes as a pointer address" instead of
+ // "attempted to read undefined bytes"
+ }
+ let x = *p; //~ ERROR: attempted to read undefined bytes
+ panic!("this should never print: {}", x);
+}
--- /dev/null
+fn main() {
+ let x: *const u8 = &1;
+ let y: *const u8 = &2;
+ if x < y { //~ ERROR: attempted to do math or a comparison on pointers into different allocations
+ unreachable!()
+ }
+}
--- /dev/null
+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);
+}
-#![feature(custom_attribute)]
-#![allow(dead_code, unused_attributes)]
-
//error-pattern:begin_panic_fmt
-
-#[miri_run]
-fn failed_assertions() {
+fn main() {
assert_eq!(5, 6);
}
-
-fn main() {}
--- /dev/null
+fn main() {
+ let p = 42 as *const i32;
+ let x = unsafe { *p }; //~ ERROR: attempted to interpret some raw bytes as a pointer address
+ panic!("this should never print: {}", x);
+}
.expect("need to specify RUST_SYSROOT env var or use rustup or multirust")
.to_owned(),
};
- let sysroot_flag = format!("--sysroot {}", sysroot);
+ let sysroot_flag = format!("--sysroot {} -Dwarnings", sysroot);
// FIXME: read directories in sysroot/lib/rustlib and generate the test targets from that
let targets = &["x86_64-unknown-linux-gnu", "i686-unknown-linux-gnu"];
-#![feature(custom_attribute)]
-#![allow(dead_code, unused_attributes)]
-
-#[miri_run]
fn empty_array() -> [u16; 0] {
[]
}
-#[miri_run]
fn mini_array() -> [u16; 1] {
[42]
}
-#[miri_run]
fn big_array() -> [u16; 5] {
[5, 4, 3, 2, 1]
}
-#[miri_run]
fn array_array() -> [[u8; 2]; 3] {
[[5, 4], [3, 2], [1, 0]]
}
-#[miri_run]
fn index_unsafe() -> i32 {
let a = [0, 10, 20, 30];
unsafe { *a.get_unchecked(2) }
}
-#[miri_run]
fn index() -> i32 {
let a = [0, 10, 20, 30];
a[2]
}
-#[miri_run]
fn array_repeat() -> [u8; 8] {
[42; 8]
}
-#[miri_run]
fn slice_index() -> u8 {
let arr: &[_] = &[101, 102, 103, 104, 105, 106];
arr[5]
}
-#[miri_run]
fn main() {
assert_eq!(empty_array(), []);
assert_eq!(index_unsafe(), 20);
assert_eq!(big_array(), [5, 4, 3, 2, 1]);
assert_eq!(array_array(), [[5, 4], [3, 2], [1, 0]]);
assert_eq!(array_repeat(), [42; 8]);
+ assert_eq!(mini_array(), [42]);
}
-#![feature(custom_attribute)]
-#![allow(dead_code, unused_attributes)]
-
-#[miri_run]
fn boolean() -> bool {
true
}
-#[miri_run]
fn if_false() -> i64 {
let c = false;
if c { 1 } else { 0 }
}
-#[miri_run]
fn if_true() -> i64 {
let c = true;
if c { 1 } else { 0 }
}
-#[miri_run]
fn match_bool() -> i16 {
let b = true;
match b {
}
}
-#[miri_run]
fn main() {
assert!(boolean());
assert_eq!(if_false(), 0);
-#![feature(custom_attribute)]
-#![allow(dead_code, unused_attributes)]
-
static mut X: usize = 5;
-#[miri_run]
-fn static_mut() {
+fn main() {
unsafe {
X = 6;
assert_eq!(X, 6);
}
}
-
-fn main() {}
-#![feature(custom_attribute)]
-#![allow(dead_code, unused_attributes)]
-
enum Foo {
Bar = 42,
Baz,
Quux = 100,
}
-#[miri_run]
fn foo() -> [u8; 3] {
[Foo::Bar as u8, Foo::Baz as u8, Foo::Quux as u8]
}
-#[miri_run]
fn signed() -> [i8; 3] {
[Signed::Bar as i8, Signed::Baz as i8, Signed::Quux as i8]
}
-#[miri_run]
fn unsafe_match() -> bool {
match unsafe { std::mem::transmute::<u8, Foo>(43) } {
Foo::Baz => true,
}
}
-#[miri_run]
fn main() {
assert_eq!(foo(), [42, 43, 100]);
assert_eq!(signed(), [-42, -41, 100]);
-#![feature(custom_attribute, const_fn)]
-#![allow(dead_code, unused_attributes)]
+#![feature(const_fn)]
-#[miri_run]
fn call() -> i32 {
fn increment(x: i32) -> i32 {
x + 1
increment(1)
}
-#[miri_run]
fn factorial_recursive() -> i64 {
fn fact(n: i64) -> i64 {
if n == 0 {
fact(10)
}
-#[miri_run]
fn call_generic() -> (i16, bool) {
fn id<T>(t: T) -> T { t }
(id(42), id(true))
}
// Test calling a very simple function from the standard library.
-#[miri_run]
fn cross_crate_fn_call() -> i64 {
if 1i32.is_positive() { 1 } else { 0 }
}
const fn foo(i: i64) -> i64 { *&i + 1 }
-#[miri_run]
fn const_fn_call() -> i64 {
let x = 5 + foo(5);
assert_eq!(x, 11);
x
}
-#[miri_run]
fn main() {
assert_eq!(call(), 2);
assert_eq!(factorial_recursive(), 3628800);
assert_eq!(call_generic(), (42, true));
assert_eq!(cross_crate_fn_call(), 1);
+ assert_eq!(const_fn_call(), 11);
}
-#![feature(custom_attribute)]
-#![allow(dead_code, unused_attributes)]
-
fn f() -> i32 {
42
}
f
}
-#[miri_run]
fn call_fn_ptr() -> i32 {
return_fn_ptr()()
}
-fn main() {}
+fn main() {
+ assert_eq!(call_fn_ptr(), 42);
+}
-#![feature(custom_attribute, box_syntax)]
-#![allow(dead_code, unused_attributes)]
+#![feature(box_syntax)]
-#[miri_run]
fn make_box() -> Box<(i16, i16)> {
Box::new((1, 2))
}
-#[miri_run]
fn make_box_syntax() -> Box<(i16, i16)> {
box (1, 2)
}
-#[miri_run]
fn allocate_reallocate() {
let mut s = String::new();
assert_eq!(s.capacity(), 9);
}
-#[miri_run]
fn main() {
assert_eq!(*make_box(), (1, 2));
assert_eq!(*make_box_syntax(), (1, 2));
+ allocate_reallocate();
}
-#![feature(custom_attribute)]
-#![allow(dead_code, unused_attributes)]
-
use std::mem::{size_of, size_of_val};
-#[miri_run]
fn main() {
assert_eq!(size_of::<Option<i32>>(), 8);
assert_eq!(size_of_val(&()), 0);
-#![feature(custom_attribute)]
-#![allow(dead_code, unused_attributes)]
-
-#[miri_run]
fn factorial_loop() -> i64 {
let mut product = 1;
let mut i = 1;
product
}
-#[miri_run]
fn index_for_loop() -> usize {
let mut sum = 0;
let a = [0, 10, 20, 30];
sum
}
-#[miri_run]
fn for_loop() -> usize {
let mut sum = 0;
let a = [0, 10, 20, 30];
sum
}
-#[miri_run]
fn main() {
assert_eq!(factorial_loop(), 3628800);
assert_eq!(index_for_loop(), 60);
-#![feature(custom_attribute)]
-#![allow(dead_code, unused_attributes)]
-
-#[miri_run]
fn one_line_ref() -> i16 {
*&1
}
-#[miri_run]
fn basic_ref() -> i16 {
let x = &1;
*x
}
-#[miri_run]
fn basic_ref_mut() -> i16 {
let x = &mut 1;
*x += 2;
*x
}
-#[miri_run]
fn basic_ref_mut_var() -> i16 {
let mut a = 1;
{
a
}
-#[miri_run]
fn tuple_ref_mut() -> (i8, i8) {
let mut t = (10, 20);
{
t
}
-#[miri_run]
fn match_ref_mut() -> i8 {
let mut t = (20, 22);
{
t.0
}
-#[miri_run]
fn dangling_pointer() -> *const i32 {
let b = Box::new(42);
&*b as *const i32
}
-#[miri_run]
fn main() {
assert_eq!(one_line_ref(), 1);
assert_eq!(basic_ref(), 1);
-#![feature(custom_attribute, box_syntax)]
-#![allow(dead_code, unused_attributes)]
-
-use std::cell::{Cell, RefCell};
+use std::cell::Cell;
use std::rc::Rc;
use std::sync::Arc;
-#[miri_run]
fn rc_cell() -> Rc<Cell<i32>> {
let r = Rc::new(Cell::new(42));
let x = r.get();
// TODO(solson): also requires destructors to run for the second borrow to work
// TODO(solson): needs StructWrappedNullablePointer support
-// #[miri_run]
// fn rc_refcell() -> i32 {
// let r = Rc::new(RefCell::new(42));
// *r.borrow_mut() += 10;
// x
// }
-#[miri_run]
fn arc() -> Arc<i32> {
let a = Arc::new(42);
a
}
-#[miri_run]
fn true_assert() {
assert_eq!(1, 1);
}
-#[miri_run]
fn main() {
assert_eq!(*arc(), 42);
assert_eq!(rc_cell().get(), 84);
+ true_assert();
}
#[derive(Debug, PartialEq)]
enum Unit { Unit(()) } // Force non-C-enum representation.
-#[miri_run]
fn return_unit() -> Unit {
Unit::Unit(())
}
#[derive(Debug, PartialEq)]
enum MyBool { False(()), True(()) } // Force non-C-enum representation.
-#[miri_run]
fn return_true() -> MyBool {
MyBool::True(())
}
-#[miri_run]
fn return_false() -> MyBool {
MyBool::False(())
}
-#[miri_run]
fn return_none() -> Option<i64> {
None
}
-#[miri_run]
fn return_some() -> Option<i64> {
Some(42)
}
-#[miri_run]
fn match_opt_none() -> i8 {
let x = None;
match x {
}
}
-#[miri_run]
fn match_opt_some() -> i8 {
let x = Some(13);
match x {
}
}
-#[miri_run]
fn two_nones() -> (Option<i16>, Option<i16>) {
(None, None)
}
// FIXME(solson): Casts inside PartialEq fails on 32-bit.
-#[cfg_attr(target_pointer_width = "64", miri_run)]
+#[cfg(target_pointer_width = "64")]
fn main() {
assert_eq!(two_nones(), (None, None));
assert_eq!(match_opt_some(), 13);
assert_eq!(return_true(), MyBool::True(()));
assert_eq!(return_unit(), Unit::Unit(()));
}
+
+#[cfg(not(target_pointer_width = "64"))]
+fn main() {}
-#![feature(custom_attribute)]
-#![allow(dead_code, unused_attributes)]
-
-#[miri_run]
fn make_vec() -> Vec<u8> {
let mut v = Vec::with_capacity(4);
v.push(1);
v
}
-#[miri_run]
fn make_vec_macro() -> Vec<u8> {
vec![1, 2]
}
-#[miri_run]
fn make_vec_macro_repeat() -> Vec<u8> {
vec![42; 5]
}
-#[miri_run]
fn vec_into_iter() -> u8 {
vec![1, 2, 3, 4]
.into_iter()
.fold(0, |x, y| x + y)
}
-#[miri_run]
fn vec_reallocate() -> Vec<u8> {
let mut v = vec![1, 2];
v.push(3);
v
}
-#[miri_run]
fn main() {
assert_eq!(vec_reallocate().len(), 5);
assert_eq!(vec_into_iter(), 30);
assert_eq!(make_vec().capacity(), 4);
+ assert_eq!(make_vec_macro(), [1, 2]);
+ assert_eq!(make_vec_macro_repeat(), [42; 5]);
}