diff options
Diffstat (limited to 'src/backend')
-rw-r--r-- | src/backend/executor/execQual.c | 17 | ||||
-rw-r--r-- | src/backend/optimizer/util/clauses.c | 10 | ||||
-rw-r--r-- | src/backend/parser/parse_expr.c | 36 | ||||
-rw-r--r-- | src/backend/parser/parser.c | 3 | ||||
-rw-r--r-- | src/backend/tcop/postgres.c | 75 | ||||
-rw-r--r-- | src/backend/utils/misc/guc.c | 21 | ||||
-rw-r--r-- | src/backend/utils/misc/postgresql.conf.sample | 5 |
7 files changed, 117 insertions, 50 deletions
diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c index fc16cccdda9..4c6f95a9a6f 100644 --- a/src/backend/executor/execQual.c +++ b/src/backend/executor/execQual.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.156 2004/03/17 20:48:42 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.157 2004/03/24 22:40:28 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -27,6 +27,11 @@ * trying to speed it up, the execution plan should be pre-processed * to facilitate attribute sharing between nodes wherever possible, * instead of doing needless copying. -cim 5/31/91 + * + * During expression evaluation, we check_stack_depth only in + * ExecMakeFunctionResult rather than at every single node. This + * is a compromise that trades off precision of the stack limit setting + * to gain speed. */ #include "postgres.h" @@ -840,6 +845,9 @@ ExecMakeFunctionResult(FuncExprState *fcache, bool hasSetArg; int i; + /* Guard against stack overflow due to overly complex expressions */ + check_stack_depth(); + /* * arguments is a list of expressions to evaluate before passing to * the function manager. We skip the evaluation if it was already @@ -1058,6 +1066,9 @@ ExecMakeFunctionResultNoSets(FuncExprState *fcache, FunctionCallInfoData fcinfo; int i; + /* Guard against stack overflow due to overly complex expressions */ + check_stack_depth(); + if (isDone) *isDone = ExprSingleResult; @@ -2503,6 +2514,10 @@ ExecInitExpr(Expr *node, PlanState *parent) if (node == NULL) return NULL; + + /* Guard against stack overflow due to overly complex expressions */ + check_stack_depth(); + switch (nodeTag(node)) { case T_Var: diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c index c006cd49a1f..b05f760ade2 100644 --- a/src/backend/optimizer/util/clauses.c +++ b/src/backend/optimizer/util/clauses.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.166 2004/03/21 22:29:11 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.167 2004/03/24 22:40:28 tgl Exp $ * * HISTORY * AUTHOR DATE MAJOR EVENT @@ -2347,6 +2347,10 @@ expression_tree_walker(Node *node, */ if (node == NULL) return false; + + /* Guard against stack overflow due to overly complex expressions */ + check_stack_depth(); + switch (nodeTag(node)) { case T_Var: @@ -2720,6 +2724,10 @@ expression_tree_mutator(Node *node, if (node == NULL) return NULL; + + /* Guard against stack overflow due to overly complex expressions */ + check_stack_depth(); + switch (nodeTag(node)) { case T_Var: diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c index 3881cc39538..83daae9b62b 100644 --- a/src/backend/parser/parse_expr.c +++ b/src/backend/parser/parse_expr.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.166 2004/03/17 20:48:42 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.167 2004/03/24 22:40:29 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -35,9 +35,6 @@ #include "utils/syscache.h" -int max_expr_depth = DEFAULT_MAX_EXPR_DEPTH; -static int expr_depth_counter = 0; - bool Transform_null_equals = false; static Node *typecast_expression(ParseState *pstate, Node *expr, @@ -48,19 +45,6 @@ static Node *transformIndirection(ParseState *pstate, Node *basenode, /* - * Initialize for parsing a new query. - * - * We reset the expression depth counter here, in case it was left nonzero - * due to ereport()'ing out of the last parsing operation. - */ -void -parse_expr_init(void) -{ - expr_depth_counter = 0; -} - - -/* * transformExpr - * Analyze and transform expressions. Type checking and type casting is * done here. The optimizer and the executor cannot handle the original @@ -92,20 +76,8 @@ transformExpr(ParseState *pstate, Node *expr) if (expr == NULL) return NULL; - /* - * Guard against an overly complex expression leading to coredump due - * to stack overflow here, or in later recursive routines that - * traverse expression trees. Note that this is very unlikely to - * happen except with pathological queries; but we don't want someone - * to be able to crash the backend quite that easily... - */ - if (++expr_depth_counter > max_expr_depth) - ereport(ERROR, - (errcode(ERRCODE_STATEMENT_TOO_COMPLEX), - errmsg("expression too complex"), - errdetail("Nesting depth exceeds maximum expression depth %d.", - max_expr_depth), - errhint("Increase the configuration parameter \"max_expr_depth\"."))); + /* Guard against stack overflow due to overly complex expressions */ + check_stack_depth(); switch (nodeTag(expr)) { @@ -938,8 +910,6 @@ transformExpr(ParseState *pstate, Node *expr) break; } - expr_depth_counter--; - return result; } diff --git a/src/backend/parser/parser.c b/src/backend/parser/parser.c index 4e31e799726..54cc8a1c00c 100644 --- a/src/backend/parser/parser.c +++ b/src/backend/parser/parser.c @@ -14,7 +14,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/parser/parser.c,v 1.60 2003/11/29 19:51:52 pgsql Exp $ + * $PostgreSQL: pgsql/src/backend/parser/parser.c,v 1.61 2004/03/24 22:40:29 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -50,7 +50,6 @@ raw_parser(const char *str) scanner_init(str); parser_init(); - parse_expr_init(); yyresult = yyparse(); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 91442d49e6e..ff0ac6aa64a 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.396 2004/03/21 22:29:11 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.397 2004/03/24 22:40:29 tgl Exp $ * * NOTES * this is the "main" module of the postgres backend and @@ -92,11 +92,22 @@ bool Log_disconnections = false; */ int XfuncMode = 0; +/* GUC variable for maximum stack depth (measured in kilobytes) */ +int max_stack_depth = 2048; + + /* ---------------- * private variables * ---------------- */ +/* max_stack_depth converted to bytes for speed of checking */ +static int max_stack_depth_bytes = 2048*1024; + +/* stack base pointer (initialized by PostgresMain) */ +static char *stack_base_ptr = NULL; + + /* * Flag to mark SIGHUP. Whenever the main loop comes around it * will reread the configuration file. (Better than doing the @@ -1970,6 +1981,64 @@ ProcessInterrupts(void) } +/* + * check_stack_depth: check for excessively deep recursion + * + * This should be called someplace in any recursive routine that might possibly + * recurse deep enough to overflow the stack. Most Unixen treat stack + * overflow as an unrecoverable SIGSEGV, so we want to error out ourselves + * before hitting the hardware limit. Unfortunately we have no direct way + * to detect the hardware limit, so we have to rely on the admin to set a + * GUC variable for it ... + */ +void +check_stack_depth(void) +{ + char stack_top_loc; + int stack_depth; + + /* + * Compute distance from PostgresMain's local variables to my own + * + * Note: in theory stack_depth should be ptrdiff_t or some such, but + * since the whole point of this code is to bound the value to something + * much less than integer-sized, int should work fine. + */ + stack_depth = (int) (stack_base_ptr - &stack_top_loc); + /* + * Take abs value, since stacks grow up on some machines, down on others + */ + if (stack_depth < 0) + stack_depth = -stack_depth; + /* + * Trouble? + * + * The test on stack_base_ptr prevents us from erroring out if called + * during process setup or in a non-backend process. Logically it should + * be done first, but putting it here avoids wasting cycles during normal + * cases. + */ + if (stack_depth > max_stack_depth_bytes && + stack_base_ptr != NULL) + { + ereport(ERROR, + (errcode(ERRCODE_STATEMENT_TOO_COMPLEX), + errmsg("stack depth limit exceeded"), + errhint("Increase the configuration parameter \"max_stack_depth\"."))); + } +} + +/* GUC assign hook to update max_stack_depth_bytes from max_stack_depth */ +bool +assign_max_stack_depth(int newval, bool doit, GucSource source) +{ + /* Range check was already handled by guc.c */ + if (doit) + max_stack_depth_bytes = newval * 1024; + return true; +} + + static void usage(char *progname) { @@ -2030,6 +2099,7 @@ PostgresMain(int argc, char *argv[], const char *username) GucSource gucsource; char *tmp; int firstchar; + char stack_base; StringInfoData input_message; volatile bool send_rfq = true; @@ -2069,6 +2139,9 @@ PostgresMain(int argc, char *argv[], const char *username) SetProcessingMode(InitProcessing); + /* Set up reference point for stack depth checking */ + stack_base_ptr = &stack_base; + /* * Set default values for command-line options. */ diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 280977d60c1..c14b4286930 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -10,7 +10,7 @@ * Written by Peter Eisentraut <peter_e@gmx.net>. * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.192 2004/03/23 01:23:48 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.193 2004/03/24 22:40:29 tgl Exp $ * *-------------------------------------------------------------------- */ @@ -1024,6 +1024,15 @@ static struct config_int ConfigureNamesInt[] = }, { + {"max_stack_depth", PGC_SUSET, RESOURCES_MEM, + gettext_noop("Sets the maximum stack depth, in kilobytes."), + NULL + }, + &max_stack_depth, + 2048, 100, INT_MAX / 1024, assign_max_stack_depth, NULL + }, + + { {"vacuum_cost_page_hit", PGC_USERSET, RESOURCES, gettext_noop("Vacuum cost for a page found in the buffer cache."), NULL @@ -1097,14 +1106,6 @@ static struct config_int ConfigureNamesInt[] = 0, 0, INT_MAX, NULL, NULL }, #endif - { - {"max_expr_depth", PGC_USERSET, CLIENT_CONN_OTHER, - gettext_noop("Sets the maximum expression nesting depth."), - NULL - }, - &max_expr_depth, - DEFAULT_MAX_EXPR_DEPTH, 10, INT_MAX, NULL, NULL - }, { {"statement_timeout", PGC_USERSET, CLIENT_CONN_STATEMENT, @@ -1246,7 +1247,7 @@ static struct config_int ConfigureNamesInt[] = }, { - {"debug_shared_buffers", PGC_POSTMASTER, RESOURCES_MEM, + {"debug_shared_buffers", PGC_POSTMASTER, STATS_MONITORING, gettext_noop("Interval to report shared buffer status in seconds"), NULL }, diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample index ff12fbdf829..0001a9ffbb3 100644 --- a/src/backend/utils/misc/postgresql.conf.sample +++ b/src/backend/utils/misc/postgresql.conf.sample @@ -58,7 +58,7 @@ #shared_buffers = 1000 # min 16, at least max_connections*2, 8KB each #work_mem = 1024 # min 64, size in KB #maintenance_work_mem = 16384 # min 1024, size in KB -#debug_shared_buffers = 0 # 0-600 seconds +#max_stack_depth = 2048 # min 100, size in KB #vacuum_cost_page_hit = 1 # 0-10000 credits #vacuum_cost_page_miss = 10 # 0-10000 credits @@ -204,6 +204,8 @@ #log_executor_stats = false #log_statement_stats = false +#debug_shared_buffers = 0 # 0-600 seconds + # - Query/Index Statistics Collector - #stats_start_collector = true @@ -243,7 +245,6 @@ #explain_pretty_print = true #dynamic_library_path = '$libdir' -#max_expr_depth = 10000 # min 10 #--------------------------------------------------------------------------- |