Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

checker: limit recursion in Checker.ensure_type_exists/2 to 40 levels (it is usually 4 or less) #21734

Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions vlib/v/checker/checker.v
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import v.comptime
// prevent stack overflows by restricting too deep recursion:
const expr_level_cutoff_limit = 40
const stmt_level_cutoff_limit = 40
const type_level_cutoff_limit = 40 // it is very rarely deeper than 4
const iface_level_cutoff_limit = 100
const generic_fn_cutoff_limit_per_fn = 10_000 // how many times post_process_generic_fns, can visit the same function before bailing out

Expand Down Expand Up @@ -101,6 +102,7 @@ mut:
// increases for `x := optfn() or { statement_list3 }`;
// files []ast.File
expr_level int // to avoid infinite recursion segfaults due to compiler bugs
type_level int // to avoid infinite recursion segfaults due to compiler bugs in ensure_type_exists
ensure_generic_type_level int // to avoid infinite recursion segfaults in ensure_generic_type_specify_type_names
cur_orm_ts ast.TypeSymbol
cur_anon_fn &ast.AnonFn = unsafe { nil }
Expand Down Expand Up @@ -4947,6 +4949,15 @@ fn (mut c Checker) ensure_type_exists(typ ast.Type, pos token.Pos) bool {
c.error('unknown type', pos)
return false
}
c.type_level++
defer {
c.type_level--
}
if c.type_level > checker.type_level_cutoff_limit {
c.error('checker: too many levels of Checker.ensure_type_exists calls: ${c.type_level}, probably due to a self referencing type',
pos)
return false
}
sym := c.table.sym(typ)
if !c.is_builtin_mod && sym.kind == .struct_ && !sym.is_pub && sym.mod != c.mod {
c.error('struct `${sym.name}` was declared as private to module `${sym.mod}`, so it can not be used inside module `${c.mod}`',
Expand Down
Loading