diff --git a/src/err.h b/src/err.h index 27a332e0..27a41b14 100644 --- a/src/err.h +++ b/src/err.h @@ -146,7 +146,7 @@ EXTERN char *ErrMsg[] /* OK */ "Ok", /* E_MISS_END */ "Missing ']'", /* E_MISS_QUOTE */ "Missing quote", -/* E_OP_STK_OVER */ "Expression too complex - too many operators", +/* E_OP_STK_OVER */ "Expression too complex", /* E_VA_STK_OVER */ "Expression too complex - too many operands", /* E_MISS_RIGHT_PAREN */ "Missing ')'", /* E_UNDEF_FUNC */ "Undefined function", diff --git a/src/expr.c b/src/expr.c index c465d2f1..d66c9052 100644 --- a/src/expr.c +++ b/src/expr.c @@ -166,6 +166,12 @@ static expr_node *expr_node_free_list = NULL; than using the stack */ #define STACK_ARGS_MAX 5 +/* Maximum parse level before we bail (to avoid SEGV from filling stack)*/ + +#define MAX_PARSE_LEVEL 1000 +static int parse_level_high_water = 0; +#define CHECK_PARSE_LEVEL() do { if (level > parse_level_high_water) { parse_level_high_water = level; } if (level > MAX_PARSE_LEVEL) { *r = E_OP_STK_OVER; return NULL; } } while(0) + /* Macro that only does "x" if the "-x" debug flag is on */ #define DBG(x) do { if (DebugFlag & DB_PRTEXPR) { x; } } while(0) @@ -182,7 +188,7 @@ static int ExprNodesHighWater = 0; static int ExprNodesUsed = 0; /* Forward references */ -static expr_node * parse_expression_aux(char const **e, int *r, Var *locals); +static expr_node * parse_expression_aux(char const **e, int *r, Var *locals, int level); static char const *get_operator_name(expr_node *node); /* This is super-skanky... we keep track of the currently-executing @@ -1770,12 +1776,14 @@ static int set_long_name(expr_node *node, char const *s) /* Returns an expr_node on success, NULL on failure. */ /* */ /***************************************************************/ -static expr_node * parse_function_call(char const **e, int *r, Var *locals) +static expr_node * parse_function_call(char const **e, int *r, Var *locals, int level) { - expr_node *node = alloc_expr_node(r); + expr_node *node; expr_node *arg; char *s; + CHECK_PARSE_LEVEL(); + node = alloc_expr_node(r); if (!node) { return NULL; } @@ -1813,7 +1821,7 @@ static expr_node * parse_function_call(char const **e, int *r, Var *locals) if (TOKEN_IS(")")) { continue; } - arg = parse_expression_aux(e, r, locals); + arg = parse_expression_aux(e, r, locals, level+1); if (*r != OK) { free_expr_tree(node); return NULL; @@ -2036,10 +2044,11 @@ static int make_atom(expr_node *atom, Var *locals) /* FUNCTION_CALL */ /* */ /***************************************************************/ -static expr_node *parse_atom(char const **e, int *r, Var *locals) +static expr_node *parse_atom(char const **e, int *r, Var *locals, int level) { expr_node *node; char const *s; + CHECK_PARSE_LEVEL(); *r = PEEK_TOKEN(); if (*r != OK) return NULL; @@ -2059,7 +2068,7 @@ static expr_node *parse_atom(char const **e, int *r, Var *locals) if (*r != OK) { return NULL; } - node = parse_expression_aux(e, r, locals); + node = parse_expression_aux(e, r, locals, level+1); if (*r != OK) { return NULL; } @@ -2088,7 +2097,7 @@ static expr_node *parse_atom(char const **e, int *r, Var *locals) /* Is it a function call? */ if (*(s + DBufLen(&ExprBuf) - 1) == '(') { - return parse_function_call(e, r, locals); + return parse_function_call(e, r, locals, level+1); } /* It's a constant or a variable reference */ @@ -2114,11 +2123,12 @@ static expr_node *parse_atom(char const **e, int *r, Var *locals) /* ATOM */ /* */ /***************************************************************/ -static expr_node *parse_factor(char const **e, int *r, Var *locals) +static expr_node *parse_factor(char const **e, int *r, Var *locals, int level) { expr_node *node; expr_node *factor_node; char op; + CHECK_PARSE_LEVEL(); *r = PEEK_TOKEN(); if (*r != OK) { return NULL; @@ -2131,7 +2141,7 @@ static expr_node *parse_factor(char const **e, int *r, Var *locals) } /* Pull off the peeked token */ GET_TOKEN(); - node = parse_factor(e, r, locals); + node = parse_factor(e, r, locals, level+1); if (*r != OK) { return NULL; } @@ -2162,7 +2172,7 @@ static expr_node *parse_factor(char const **e, int *r, Var *locals) add_child(factor_node, node); return factor_node; } - return parse_atom(e, r, locals); + return parse_atom(e, r, locals, level+1); } /***************************************************************/ @@ -2175,12 +2185,13 @@ static expr_node *parse_factor(char const **e, int *r, Var *locals) /* FACTOR_EXP '%' TERM_EXP */ /* */ /***************************************************************/ -static expr_node *parse_term_expr(char const **e, int *r, Var *locals) +static expr_node *parse_term_expr(char const **e, int *r, Var *locals, int level) { expr_node *node; expr_node *term_node; + CHECK_PARSE_LEVEL(); - node = parse_factor(e, r, locals); + node = parse_factor(e, r, locals, level+1); if (*r != OK) { return free_expr_tree(node); } @@ -2207,7 +2218,7 @@ static expr_node *parse_term_expr(char const **e, int *r, Var *locals) if (*r != OK) { return free_expr_tree(term_node); } - node = parse_factor(e, r, locals); + node = parse_factor(e, r, locals, level+1); if (*r != OK) { return free_expr_tree(term_node); } @@ -2230,12 +2241,13 @@ static expr_node *parse_term_expr(char const **e, int *r, Var *locals) /* TERM_EXP '-' CMP_EXP */ /* */ /***************************************************************/ -static expr_node *parse_cmp_expr(char const **e, int *r, Var *locals) +static expr_node *parse_cmp_expr(char const **e, int *r, Var *locals, int level) { expr_node *node; expr_node *cmp_node; + CHECK_PARSE_LEVEL(); - node = parse_term_expr(e, r, locals); + node = parse_term_expr(e, r, locals, level+1); if (*r != OK) { return free_expr_tree(node); } @@ -2255,7 +2267,7 @@ static expr_node *parse_cmp_expr(char const **e, int *r, Var *locals) if (*r != OK) { return free_expr_tree(cmp_node); } - node = parse_term_expr(e, r, locals); + node = parse_term_expr(e, r, locals, level+1); if (*r != OK) { return free_expr_tree(cmp_node); } @@ -2276,12 +2288,13 @@ static expr_node *parse_cmp_expr(char const **e, int *r, Var *locals) /* CMP_EXP '<=' EQ_EXP */ /* */ /***************************************************************/ -static expr_node *parse_eq_expr(char const **e, int *r, Var *locals) +static expr_node *parse_eq_expr(char const **e, int *r, Var *locals, int level) { expr_node *node; expr_node *eq_node; + CHECK_PARSE_LEVEL(); - node = parse_cmp_expr(e, r, locals); + node = parse_cmp_expr(e, r, locals, level+1); if (*r != OK) { return free_expr_tree(node); } @@ -2305,7 +2318,7 @@ static expr_node *parse_eq_expr(char const **e, int *r, Var *locals) if (*r != OK) { return free_expr_tree(eq_node); } - node = parse_cmp_expr(e, r, locals); + node = parse_cmp_expr(e, r, locals, level+1); if (*r != OK) { free_expr_tree(eq_node); return free_expr_tree(node); @@ -2325,12 +2338,13 @@ static expr_node *parse_eq_expr(char const **e, int *r, Var *locals) /* EQ_EXP '!=' AND_EXP */ /* */ /***************************************************************/ -static expr_node *parse_and_expr(char const **e, int *r, Var *locals) +static expr_node *parse_and_expr(char const **e, int *r, Var *locals, int level) { expr_node *node; expr_node *and_node; + CHECK_PARSE_LEVEL(); - node = parse_eq_expr(e, r, locals); + node = parse_eq_expr(e, r, locals, level+1); if (*r != OK) { return free_expr_tree(node); } @@ -2350,7 +2364,7 @@ static expr_node *parse_and_expr(char const **e, int *r, Var *locals) if (*r != OK) { return free_expr_tree(and_node); } - node = parse_eq_expr(e, r, locals); + node = parse_eq_expr(e, r, locals, level+1); if (*r != OK) { return free_expr_tree(and_node); } @@ -2368,12 +2382,13 @@ static expr_node *parse_and_expr(char const **e, int *r, Var *locals) /* AND_EXP '&&' OR_EXP */ /* */ /***************************************************************/ -static expr_node *parse_or_expr(char const **e, int *r, Var *locals) +static expr_node *parse_or_expr(char const **e, int *r, Var *locals, int level) { expr_node *node; expr_node *logand_node; + CHECK_PARSE_LEVEL(); - node = parse_and_expr(e, r, locals); + node = parse_and_expr(e, r, locals, level+1); if (*r != OK) { return free_expr_tree(node); @@ -2391,7 +2406,7 @@ static expr_node *parse_or_expr(char const **e, int *r, Var *locals) logand_node->type = N_OPERATOR; logand_node->u.operator_func = logical_and; add_child(logand_node, node); - node = parse_and_expr(e, r, locals); + node = parse_and_expr(e, r, locals, level+1); if (*r != OK) { free_expr_tree(logand_node); return free_expr_tree(node); @@ -2410,11 +2425,13 @@ static expr_node *parse_or_expr(char const **e, int *r, Var *locals) /* OR_EXP '||' EXPR */ /* */ /***************************************************************/ -static expr_node *parse_expression_aux(char const **e, int *r, Var *locals) +static expr_node *parse_expression_aux(char const **e, int *r, Var *locals, int level) { expr_node *node; expr_node *logor_node; - node = parse_or_expr(e, r, locals); + CHECK_PARSE_LEVEL(); + + node = parse_or_expr(e, r, locals, level+1); if (*r != OK) { return free_expr_tree(node); @@ -2431,7 +2448,7 @@ static expr_node *parse_expression_aux(char const **e, int *r, Var *locals) logor_node->type = N_OPERATOR; logor_node->u.operator_func = logical_or; add_child(logor_node, node); - node = parse_or_expr(e, r, locals); + node = parse_or_expr(e, r, locals, level+1); if (*r != OK) { free_expr_tree(logor_node); return free_expr_tree(node); @@ -2462,7 +2479,7 @@ expr_node *parse_expression(char const **e, int *r, Var *locals) return NULL; } - expr_node *node = parse_expression_aux(e, r, locals); + expr_node *node = parse_expression_aux(e, r, locals, 0); if (DebugFlag & DB_PARSE_EXPR) { fprintf(ErrFp, "Parsed expression: "); while (*orig && orig != *e) { @@ -3010,4 +3027,5 @@ void print_expr_nodes_stats(void) fprintf(stderr, " Expression nodes allocated: %d (%u bytes)\n", ExprNodesAllocated, (unsigned) (ExprNodesAllocated * sizeof(expr_node))); fprintf(stderr, "Expression nodes high-water: %d\n", ExprNodesHighWater); fprintf(stderr, " Expression nodes leaked: %d\n", ExprNodesUsed); + fprintf(stderr, " Parse level high-water: %d\n", parse_level_high_water); } diff --git a/src/langs/finnish.h b/src/langs/finnish.h index 4bca3d15..921859d9 100644 --- a/src/langs/finnish.h +++ b/src/langs/finnish.h @@ -145,7 +145,7 @@ EXTERN char *ErrMsg[] = "Ok", "Puuttuva ']'", "Puuttuva lainausmerkki", - "Liian monimutkainen lauseke - liikaa operaattoreita", + "Liian monimutkainen lauseke", "Liian monimutkainen lauseke - liikaa operandeja", "Puuttuva ')'", "Määrittelemätön funktio", diff --git a/src/langs/french.h b/src/langs/french.h index 704affff..6bc8d8b0 100644 --- a/src/langs/french.h +++ b/src/langs/french.h @@ -119,7 +119,7 @@ EXTERN char *ErrMsg[] = "Ok", "']' manquant", "Apostrophe manquant", - "Expression trop complexe - trop d'opérateurs", + "Expression trop complexe", "Expression trop complexe - trop d'opérandes", "')' manquante", "Fonction non-définie", diff --git a/src/langs/polish.h b/src/langs/polish.h index 7a7deb04..c8df28d2 100644 --- a/src/langs/polish.h +++ b/src/langs/polish.h @@ -135,7 +135,7 @@ EXTERN char *ErrMsg[] = "OK", "Brakujący ']'", "Brakujący nawias", - "Zbyt skomplikowane wyrażenie - za dużo operatorów", + "Zbyt skomplikowane wyrażenie", "Zbyt skomplikowane wyrażenie - za dużo argumentów", "Brakujący ')'", "Nie zdefiniowana funkcja", diff --git a/src/langs/portbr.h b/src/langs/portbr.h index f21241ae..d76bfb92 100644 --- a/src/langs/portbr.h +++ b/src/langs/portbr.h @@ -144,7 +144,7 @@ EXTERN char *ErrMsg[] = "Ok", "Falta um ']'", "Falta uma aspa", - "Expressao muito complexa - muitos operadores", + "Expressao muito complexa", "Expressao muito complexa - muitos operandos", "Falta um ')'", "Funcao nao definida",