From c59e3809f3d1ee74185bef8eebb1d523cc2a1369 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Grubbstr=C3=B6m=20=28Grubba=29?= <grubba@grubba.org> Date: Fri, 23 Aug 2013 14:25:47 +0200 Subject: [PATCH] [compiler] Avoid recursion on the C-stack. las.c:count_args() now uses the parent links (as per an old FIXME), to avoid running out of C-stack when counting huge argument lists. Fixes [bug 6860]. --- src/las.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 64 insertions(+), 8 deletions(-) diff --git a/src/las.c b/src/las.c index 786563a65e..fe88ef3233 100644 --- a/src/las.c +++ b/src/las.c @@ -218,13 +218,9 @@ void check_tree(node *n, int depth) } #endif -/* FIXME: Ought to use parent pointer to avoid recursion. */ -INT32 count_args(node *n) +static int low_count_args(node *n) { int a,b; - check_tree(n,0); - - fatal_check_c_stack(16384); if(!n) return 0; switch(n->token) @@ -241,8 +237,7 @@ INT32 count_args(node *n) case F_CAST: if(n->type == void_type_string) return 0; - else - return count_args(CAR(n)); + return count_args(CAR(n)); case F_SOFT_CAST: return count_args(CAR(n)); @@ -267,7 +262,6 @@ INT32 count_args(node *n) int tmp1,tmp2; tmp1=count_args(CADR(n)); tmp2=count_args(CDDR(n)); - if(tmp1==-1 || tmp2==-1) return -1; if(tmp1 < tmp2) return tmp1; return tmp2; } @@ -293,6 +287,68 @@ INT32 count_args(node *n) if(n->type == void_type_string) return 0; return 1; } + /* NOT_REACHED */ +} + +INT32 count_args(node *n) +{ + int total = 0; + int a,b; + node *orig = n; + node *orig_parent; + node *prev = NULL; + check_tree(n,0); + + fatal_check_c_stack(16384); + + if(!n) return 0; + + orig_parent = n->parent; + n->parent = NULL; + + while(1) { + int val; + while ((n->token == F_COMMA_EXPR) || + (n->token == F_VAL_LVAL) || + (n->token == F_ARG_LIST)) { + if (CAR(n)) { + CAR(n)->parent = n; + n = CAR(n); + } else if (CDR(n)) { + CDR(n)->parent = n; + n = CDR(n); + } else { + /* Unlikely, but... */ + goto backtrack; + } + } + + /* Leaf. */ + val = low_count_args(n); + if (val == -1) { + total = -1; + break; + } + if (n->parent && (CAR(n->parent) == CDR(n->parent))) { + /* Same node in both CDR and CAR ==> count twice. */ + val *= 2; + } + total += val; + + backtrack: + while (n->parent && + (!CDR(n->parent) || (n == CDR(n->parent)))) { + n = n->parent; + } + if (!(n = n->parent)) break; + /* Found a parent where we haven't visited CDR. */ + CDR(n)->parent = n; + n = CDR(n); + } + + orig->parent = orig_parent; + + return total; } /* FIXME: Ought to use parent pointer to avoid recursion. */ -- GitLab