Skip to content

Commit

Permalink
Guard against infinitely expanding generic/inline functions
Browse files Browse the repository at this point in the history
Closes #2220

Test case disabled until a memory-leak issue is resolved.
  • Loading branch information
marijnh committed Apr 23, 2012
1 parent 2782cfb commit 68f8812
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 6 deletions.
24 changes: 18 additions & 6 deletions src/rustc/middle/trans/base.rs
Expand Up @@ -1938,31 +1938,41 @@ fn monomorphic_fn(ccx: @crate_ctxt, fn_id: ast::def_id, real_substs: [ty::t],

let map_node = ccx.tcx.items.get(fn_id.node);
// Get the path so that we can create a symbol
let (pt, name) = alt map_node {
let (pt, name, span) = alt map_node {
ast_map::node_item(i, pt) {
alt i.node {
ast::item_res(_, _, _, dtor_id, _, _) {
item_ty = ty::node_id_to_type(ccx.tcx, dtor_id);
}
_ {}
}
(pt, i.ident)
(pt, i.ident, i.span)
}
ast_map::node_variant(v, _, pt) { (pt, v.node.name) }
ast_map::node_method(m, _, pt) { (pt, m.ident) }
ast_map::node_variant(v, enm, pt) { (pt, v.node.name, enm.span) }
ast_map::node_method(m, _, pt) { (pt, m.ident, m.span) }
ast_map::node_native_item(i, ast::native_abi_rust_intrinsic, pt)
{ (pt, i.ident) }
{ (pt, i.ident, i.span) }
ast_map::node_native_item(_, abi, _) {
// Natives don't have to be monomorphized.
ret {val: get_item_val(ccx, fn_id.node),
must_cast: true};
}
ast_map::node_ctor(nm, _, _, pt) { (pt, nm) }
ast_map::node_ctor(nm, _, _, pt) { (pt, nm, ast_util::dummy_sp()) }
_ { fail "unexpected node type"; }
};
let mono_ty = ty::subst_tps(ccx.tcx, substs, item_ty);
let llfty = type_of_fn_from_ty(ccx, mono_ty);

let depth = option::get_or_default(ccx.monomorphizing.find(fn_id), 0u);
// Random cut-off -- code that needs to instantiate the same function
// recursively more than ten times can probably safely be assumed to be
// causing an infinite expansion.
if depth > 10u {
ccx.sess.span_fatal(
span, "overly deep expansion of inlined function");
}
ccx.monomorphizing.insert(fn_id, depth + 1u);

let pt = *pt + [path_name(ccx.names(name))];
let s = mangle_exported_name(ccx, pt, mono_ty);
let lldecl = decl_internal_cdecl_fn(ccx.llmod, s, llfty);
Expand Down Expand Up @@ -2014,6 +2024,7 @@ fn monomorphic_fn(ccx: @crate_ctxt, fn_id: ast::def_id, real_substs: [ty::t],
}
}
}
ccx.monomorphizing.insert(fn_id, depth);
{val: lldecl, must_cast: must_cast}
}

Expand Down Expand Up @@ -5022,6 +5033,7 @@ fn trans_crate(sess: session::session, crate: @ast::crate, tcx: ty::ctxt,
tydescs: ty::new_ty_hash(),
external: util::common::new_def_hash(),
monomorphized: map::hashmap(hash_mono_id, {|a, b| a == b}),
monomorphizing: ast_util::new_def_id_hash(),
type_use_cache: util::common::new_def_hash(),
vtables: map::hashmap(hash_mono_id, {|a, b| a == b}),
const_cstr_cache: map::str_hash(),
Expand Down
1 change: 1 addition & 0 deletions src/rustc/middle/trans/common.rs
Expand Up @@ -95,6 +95,7 @@ type crate_ctxt = {
external: hashmap<ast::def_id, option<ast::node_id>>,
// Cache instances of monomorphized functions
monomorphized: hashmap<mono_id, ValueRef>,
monomorphizing: hashmap<ast::def_id, uint>,
// Cache computed type parameter uses (see type_use.rs)
type_use_cache: hashmap<ast::def_id, [type_use::type_uses]>,
// Cache generated vtables
Expand Down
30 changes: 30 additions & 0 deletions src/test/compile-fail/infinite-instantiation.rs
@@ -0,0 +1,30 @@
// error-pattern: overly deep expansion
// issue 2258
// This is currently exposing a memory leak, and xfailed for that reason
// xfail-test

iface to_opt {
fn to_option() -> option<self>;
}

impl of to_opt for uint {
fn to_option() -> option<uint> {
some(self)
}
}

impl<T:copy> of to_opt for option<T> {
fn to_option() -> option<option<T>> {
some(self)
}
}

fn function<T:to_opt>(counter: uint, t: T) {
if counter > 0u {
function(counter - 1u, t.to_option());
}
}

fn main() {
function(22u, 22u);
}

0 comments on commit 68f8812

Please sign in to comment.