add attribute to limit the stack size

This commit is contained in:
Oliver Schneider 2016-07-05 13:23:58 +02:00
parent 88d98998e1
commit 4781a6ba54
No known key found for this signature in database
GPG Key ID: 56D6EEA0FC67AC46
4 changed files with 39 additions and 4 deletions

View File

@ -40,6 +40,7 @@ fn build_controller(
let krate = state.hir_crate.as_ref().unwrap();
let mut memory_size = 100*1024*1024; // 100MB
let mut step_limit = 1000_000;
let mut stack_limit = 100;
fn extract_str(lit: &syntax::ast::Lit) -> syntax::parse::token::InternedString {
match lit.node {
syntax::ast::LitKind::Str(ref s, _) => s.clone(),
@ -55,6 +56,7 @@ fn extract_str(lit: &syntax::ast::Lit) -> syntax::parse::token::InternedString {
match &**name {
"memory_size" => memory_size = extract_str(value).parse::<u64>().expect("not a number"),
"step_limit" => step_limit = extract_str(value).parse::<u64>().expect("not a number"),
"stack_limit" => stack_limit = extract_str(value).parse::<u64>().expect("not a number"),
_ => state.session.span_err(item.span, "unknown miri attribute"),
}
}
@ -67,7 +69,7 @@ fn extract_str(lit: &syntax::ast::Lit) -> syntax::parse::token::InternedString {
let mut mir_map = MirMap { map: mir_map.map.clone() };
run_mir_passes(tcx, &mut mir_map);
eval_main(tcx, &mir_map, node_id, memory_size, step_limit);
eval_main(tcx, &mir_map, node_id, memory_size, step_limit, stack_limit);
state.session.abort_if_errors();
});

View File

@ -35,6 +35,7 @@ pub enum EvalError<'tcx> {
memory_usage: u64,
},
ExecutionTimeLimitReached,
StackFrameLimitReached,
}
pub type EvalResult<'tcx, T> = Result<T, EvalError<'tcx>>;
@ -79,6 +80,8 @@ fn description(&self) -> &str {
"could not allocate more memory",
EvalError::ExecutionTimeLimitReached =>
"reached the configured maximum execution time",
EvalError::StackFrameLimitReached =>
"reached the configured maximum number of stack frames",
}
}

View File

@ -42,6 +42,9 @@ pub struct EvalContext<'a, 'tcx: 'a> {
/// The virtual call stack.
stack: Vec<Frame<'a, 'tcx>>,
/// The maximum number of stack frames allowed
stack_limit: usize,
}
/// A stack frame.
@ -133,7 +136,8 @@ enum ConstantKind {
}
impl<'a, 'tcx> EvalContext<'a, 'tcx> {
pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, mir_map: &'a MirMap<'tcx>, memory_size: u64) -> Self {
pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, mir_map: &'a MirMap<'tcx>, memory_size: u64, stack_limit: u64) -> Self {
assert_eq!(stack_limit as usize as u64, stack_limit);
EvalContext {
tcx: tcx,
mir_map: mir_map,
@ -141,6 +145,7 @@ pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, mir_map: &'a MirMap<'tcx>, memory_size:
memory: Memory::new(&tcx.data_layout, memory_size),
statics: HashMap::new(),
stack: Vec::new(),
stack_limit: stack_limit as usize,
}
}
@ -316,7 +321,11 @@ pub fn push_stack_frame(
substs: substs,
stmt: 0,
});
Ok(())
if self.stack.len() > self.stack_limit {
Err(EvalError::StackFrameLimitReached)
} else {
Ok(())
}
}
fn pop_stack_frame(&mut self) {
@ -930,10 +939,11 @@ pub fn eval_main<'a, 'tcx: 'a>(
node_id: ast::NodeId,
memory_size: u64,
step_limit: u64,
stack_limit: u64,
) {
let mir = mir_map.map.get(&node_id).expect("no mir for main function");
let def_id = tcx.map.local_def_id(node_id);
let mut ecx = EvalContext::new(tcx, mir_map, memory_size);
let mut ecx = EvalContext::new(tcx, mir_map, memory_size, stack_limit);
let substs = tcx.mk_substs(subst::Substs::empty());
let return_ptr = ecx.alloc_ret_ptr(mir.return_ty, substs)
.expect("should at least be able to allocate space for the main function's return value")

View File

@ -0,0 +1,20 @@
#![feature(custom_attribute)]
#![miri(stack_limit="2")]
fn bar() {
foo();
}
fn foo() {
cake(); //~ ERROR reached the configured maximum number of stack frames
}
fn cake() {
flubber();
}
fn flubber() {}
fn main() {
bar();
}