From 68811c68c7342d7307b684313962edd105b88a83 Mon Sep 17 00:00:00 2001 From: Kaz Kylheku Date: Thu, 20 Oct 2016 07:00:03 -0700 Subject: Check call graph circularity in circ_backpatch. The circ_backpatch function could suffer runaway recursion, so we must add a cycle check. This could happen due to hitting cyclical objects when traversing structs. Structs have static slots that could contain cyclic objects, as well as construction logic which can generate slots that contain cycles and are not overridden by anything in the literal. * parser.c (circ_backpatch): Take struct circ_stack * argument; extend the circ_stack in recursive calls. Do circular check on entry. (parser_resolve_circ): Pass null pointer as the new stack argument to circ_backpatch. --- parser.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/parser.c b/parser.c index bb023343..cd542fe8 100644 --- a/parser.c +++ b/parser.c @@ -234,8 +234,13 @@ static val patch_ref(parser_t *p, val obj) return nil; } -static void circ_backpatch(parser_t *p, val obj) +static void circ_backpatch(parser_t *p, struct circ_stack *up, val obj) { + struct circ_stack cs = { up, obj }; + + if (!parser_callgraph_circ_check(up, obj)) + return; + tail: if (!p->circ_count) return; @@ -252,7 +257,7 @@ tail: if (ra) rplaca(obj, ra); else - circ_backpatch(p, a); + circ_backpatch(p, &cs, a); if (rd) { rplacd(obj, rd); @@ -274,7 +279,7 @@ tail: if (rv) set(vecref_l(obj, in), rv); else - circ_backpatch(p, v); + circ_backpatch(p, &cs, v); if (!p->circ_count) break; } @@ -291,7 +296,7 @@ tail: if (rs) set_from(obj, rs); else - circ_backpatch(p, s); + circ_backpatch(p, &cs, s); if (re) { set_to(obj, re); @@ -311,7 +316,7 @@ tail: val iter = hash_begin(obj); val cell; while ((cell = hash_next(iter))) - circ_backpatch(p, cell); + circ_backpatch(p, &cs, cell); } } else if (structp(obj)) { val stype = struct_type(obj); @@ -324,7 +329,7 @@ tail: if (rsv) slotset(obj, sn, rsv); else - circ_backpatch(p, sv); + circ_backpatch(p, &cs, sv); } } break; @@ -339,7 +344,8 @@ void parser_resolve_circ(parser_t *p) if (p->circ_count == 0) return; - circ_backpatch(p, p->syntax_tree); + + circ_backpatch(p, 0, p->syntax_tree); if (p->circ_count > 0) yyerrorf(p->scanner, lit("not all ## refs replaced in object ~s"), -- cgit v1.2.3