Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit8899a2a

Browse files
committed
Replace max_expr_depth parameter with a max_stack_depth parameter that
is measured in kilobytes and checked against actual physical executionstack depth, as per my proposal of 30-Dec. This gives us a fairlybulletproof defense against crashing due to runaway recursive functions.
1 parenta09b9a3 commit8899a2a

File tree

13 files changed

+157
-79
lines changed

13 files changed

+157
-79
lines changed

‎doc/src/sgml/runtime.sgml

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<!--
2-
$PostgreSQL: pgsql/doc/src/sgml/runtime.sgml,v 1.253 2004/03/2403:48:41 neilc Exp $
2+
$PostgreSQL: pgsql/doc/src/sgml/runtime.sgml,v 1.254 2004/03/2422:40:28 tgl Exp $
33
-->
44

55
<Chapter Id="runtime">
@@ -889,6 +889,26 @@ SET ENABLE_SEQSCAN TO OFF;
889889
</listitem>
890890
</varlistentry>
891891

892+
<varlistentry id="guc-max-stack-depth" xreflabel="max_stack_depth">
893+
<term><varname>max_stack_depth</varname> (<type>integer</type>)</term>
894+
<listitem>
895+
<para>
896+
Specifies the maximum safe depth of the server's execution stack.
897+
The ideal setting for this parameter is the actual stack size limit
898+
enforced by the kernel (as set by <literal>ulimit -s</> or local
899+
equivalent), less a safety margin of a megabyte or so. The safety
900+
margin is needed because the stack depth is not checked in every
901+
routine in the server, but only in key potentially-recursive routines
902+
such as expression evaluation. Setting the parameter higher than
903+
the actual kernel limit will mean that a runaway recursive function
904+
can crash an individual backend process. The default setting is
905+
2048 KB (two megabytes), which is conservatively small and unlikely
906+
to risk crashes. However, it may be too small to allow execution
907+
of complex functions.
908+
</para>
909+
</listitem>
910+
</varlistentry>
911+
892912
</variablelist>
893913
</sect3>
894914
<sect3 id="runtime-config-resource-fsm">
@@ -2573,18 +2593,6 @@ dynamic_library_path = '/usr/local/lib/postgresql:/home/my_project/lib:$libdir'
25732593
</listitem>
25742594
</varlistentry>
25752595

2576-
<varlistentry id="guc-max-expr-depth" xreflabel="max_expr_depth">
2577-
<term><varname>max_expr_depth</varname> (<type>integer</type>)</term>
2578-
<listitem>
2579-
<para>
2580-
Sets the maximum expression nesting depth of the parser. The
2581-
default value of 10000 is high enough for any normal query,
2582-
but you can raise it if needed. (But if you raise it too high,
2583-
you run the risk of server crashes due to stack overflow.)
2584-
</para>
2585-
</listitem>
2586-
</varlistentry>
2587-
25882596
</variablelist>
25892597
</sect3>
25902598
</sect2>

‎src/backend/executor/execQual.c

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.156 2004/03/17 20:48:42 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.157 2004/03/24 22:40:28 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -27,6 +27,11 @@
2727
*trying to speed it up, the execution plan should be pre-processed
2828
*to facilitate attribute sharing between nodes wherever possible,
2929
*instead of doing needless copying.-cim 5/31/91
30+
*
31+
*During expression evaluation, we check_stack_depth only in
32+
*ExecMakeFunctionResult rather than at every single node. This
33+
*is a compromise that trades off precision of the stack limit setting
34+
*to gain speed.
3035
*/
3136

3237
#include"postgres.h"
@@ -840,6 +845,9 @@ ExecMakeFunctionResult(FuncExprState *fcache,
840845
boolhasSetArg;
841846
inti;
842847

848+
/* Guard against stack overflow due to overly complex expressions */
849+
check_stack_depth();
850+
843851
/*
844852
* arguments is a list of expressions to evaluate before passing to
845853
* the function manager. We skip the evaluation if it was already
@@ -1058,6 +1066,9 @@ ExecMakeFunctionResultNoSets(FuncExprState *fcache,
10581066
FunctionCallInfoDatafcinfo;
10591067
inti;
10601068

1069+
/* Guard against stack overflow due to overly complex expressions */
1070+
check_stack_depth();
1071+
10611072
if (isDone)
10621073
*isDone=ExprSingleResult;
10631074

@@ -2503,6 +2514,10 @@ ExecInitExpr(Expr *node, PlanState *parent)
25032514

25042515
if (node==NULL)
25052516
returnNULL;
2517+
2518+
/* Guard against stack overflow due to overly complex expressions */
2519+
check_stack_depth();
2520+
25062521
switch (nodeTag(node))
25072522
{
25082523
caseT_Var:

‎src/backend/optimizer/util/clauses.c

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.166 2004/03/21 22:29:11 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.167 2004/03/24 22:40:28 tgl Exp $
1212
*
1313
* HISTORY
1414
* AUTHORDATEMAJOR EVENT
@@ -2347,6 +2347,10 @@ expression_tree_walker(Node *node,
23472347
*/
23482348
if (node==NULL)
23492349
return false;
2350+
2351+
/* Guard against stack overflow due to overly complex expressions */
2352+
check_stack_depth();
2353+
23502354
switch (nodeTag(node))
23512355
{
23522356
caseT_Var:
@@ -2720,6 +2724,10 @@ expression_tree_mutator(Node *node,
27202724

27212725
if (node==NULL)
27222726
returnNULL;
2727+
2728+
/* Guard against stack overflow due to overly complex expressions */
2729+
check_stack_depth();
2730+
27232731
switch (nodeTag(node))
27242732
{
27252733
caseT_Var:

‎src/backend/parser/parse_expr.c

Lines changed: 3 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.166 2004/03/17 20:48:42 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.167 2004/03/24 22:40:29 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -35,9 +35,6 @@
3535
#include"utils/syscache.h"
3636

3737

38-
intmax_expr_depth=DEFAULT_MAX_EXPR_DEPTH;
39-
staticintexpr_depth_counter=0;
40-
4138
boolTransform_null_equals= false;
4239

4340
staticNode*typecast_expression(ParseState*pstate,Node*expr,
@@ -47,19 +44,6 @@ static Node *transformIndirection(ParseState *pstate, Node *basenode,
4744
List*indirection);
4845

4946

50-
/*
51-
* Initialize for parsing a new query.
52-
*
53-
* We reset the expression depth counter here, in case it was left nonzero
54-
* due to ereport()'ing out of the last parsing operation.
55-
*/
56-
void
57-
parse_expr_init(void)
58-
{
59-
expr_depth_counter=0;
60-
}
61-
62-
6347
/*
6448
* transformExpr -
6549
* Analyze and transform expressions. Type checking and type casting is
@@ -92,20 +76,8 @@ transformExpr(ParseState *pstate, Node *expr)
9276
if (expr==NULL)
9377
returnNULL;
9478

95-
/*
96-
* Guard against an overly complex expression leading to coredump due
97-
* to stack overflow here, or in later recursive routines that
98-
* traverse expression trees. Note that this is very unlikely to
99-
* happen except with pathological queries; but we don't want someone
100-
* to be able to crash the backend quite that easily...
101-
*/
102-
if (++expr_depth_counter>max_expr_depth)
103-
ereport(ERROR,
104-
(errcode(ERRCODE_STATEMENT_TOO_COMPLEX),
105-
errmsg("expression too complex"),
106-
errdetail("Nesting depth exceeds maximum expression depth %d.",
107-
max_expr_depth),
108-
errhint("Increase the configuration parameter \"max_expr_depth\".")));
79+
/* Guard against stack overflow due to overly complex expressions */
80+
check_stack_depth();
10981

11082
switch (nodeTag(expr))
11183
{
@@ -938,8 +910,6 @@ transformExpr(ParseState *pstate, Node *expr)
938910
break;
939911
}
940912

941-
expr_depth_counter--;
942-
943913
returnresult;
944914
}
945915

‎src/backend/parser/parser.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
* Portions Copyright (c) 1994, Regents of the University of California
1515
*
1616
* IDENTIFICATION
17-
* $PostgreSQL: pgsql/src/backend/parser/parser.c,v 1.60 2003/11/29 19:51:52 pgsql Exp $
17+
* $PostgreSQL: pgsql/src/backend/parser/parser.c,v 1.61 2004/03/24 22:40:29 tgl Exp $
1818
*
1919
*-------------------------------------------------------------------------
2020
*/
@@ -50,7 +50,6 @@ raw_parser(const char *str)
5050

5151
scanner_init(str);
5252
parser_init();
53-
parse_expr_init();
5453

5554
yyresult=yyparse();
5655

‎src/backend/tcop/postgres.c

Lines changed: 74 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.396 2004/03/21 22:29:11 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.397 2004/03/24 22:40:29 tgl Exp $
1212
*
1313
* NOTES
1414
* this is the "main" module of the postgres backend and
@@ -92,11 +92,22 @@ bool Log_disconnections = false;
9292
*/
9393
intXfuncMode=0;
9494

95+
/* GUC variable for maximum stack depth (measured in kilobytes) */
96+
intmax_stack_depth=2048;
97+
98+
9599
/* ----------------
96100
*private variables
97101
* ----------------
98102
*/
99103

104+
/* max_stack_depth converted to bytes for speed of checking */
105+
staticintmax_stack_depth_bytes=2048*1024;
106+
107+
/* stack base pointer (initialized by PostgresMain) */
108+
staticchar*stack_base_ptr=NULL;
109+
110+
100111
/*
101112
* Flag to mark SIGHUP. Whenever the main loop comes around it
102113
* will reread the configuration file. (Better than doing the
@@ -1970,6 +1981,64 @@ ProcessInterrupts(void)
19701981
}
19711982

19721983

1984+
/*
1985+
* check_stack_depth: check for excessively deep recursion
1986+
*
1987+
* This should be called someplace in any recursive routine that might possibly
1988+
* recurse deep enough to overflow the stack. Most Unixen treat stack
1989+
* overflow as an unrecoverable SIGSEGV, so we want to error out ourselves
1990+
* before hitting the hardware limit. Unfortunately we have no direct way
1991+
* to detect the hardware limit, so we have to rely on the admin to set a
1992+
* GUC variable for it ...
1993+
*/
1994+
void
1995+
check_stack_depth(void)
1996+
{
1997+
charstack_top_loc;
1998+
intstack_depth;
1999+
2000+
/*
2001+
* Compute distance from PostgresMain's local variables to my own
2002+
*
2003+
* Note: in theory stack_depth should be ptrdiff_t or some such, but
2004+
* since the whole point of this code is to bound the value to something
2005+
* much less than integer-sized, int should work fine.
2006+
*/
2007+
stack_depth= (int) (stack_base_ptr-&stack_top_loc);
2008+
/*
2009+
* Take abs value, since stacks grow up on some machines, down on others
2010+
*/
2011+
if (stack_depth<0)
2012+
stack_depth=-stack_depth;
2013+
/*
2014+
* Trouble?
2015+
*
2016+
* The test on stack_base_ptr prevents us from erroring out if called
2017+
* during process setup or in a non-backend process. Logically it should
2018+
* be done first, but putting it here avoids wasting cycles during normal
2019+
* cases.
2020+
*/
2021+
if (stack_depth>max_stack_depth_bytes&&
2022+
stack_base_ptr!=NULL)
2023+
{
2024+
ereport(ERROR,
2025+
(errcode(ERRCODE_STATEMENT_TOO_COMPLEX),
2026+
errmsg("stack depth limit exceeded"),
2027+
errhint("Increase the configuration parameter \"max_stack_depth\".")));
2028+
}
2029+
}
2030+
2031+
/* GUC assign hook to update max_stack_depth_bytes from max_stack_depth */
2032+
bool
2033+
assign_max_stack_depth(intnewval,booldoit,GucSourcesource)
2034+
{
2035+
/* Range check was already handled by guc.c */
2036+
if (doit)
2037+
max_stack_depth_bytes=newval*1024;
2038+
return true;
2039+
}
2040+
2041+
19732042
staticvoid
19742043
usage(char*progname)
19752044
{
@@ -2030,6 +2099,7 @@ PostgresMain(int argc, char *argv[], const char *username)
20302099
GucSourcegucsource;
20312100
char*tmp;
20322101
intfirstchar;
2102+
charstack_base;
20332103
StringInfoDatainput_message;
20342104
volatileboolsend_rfq= true;
20352105

@@ -2069,6 +2139,9 @@ PostgresMain(int argc, char *argv[], const char *username)
20692139

20702140
SetProcessingMode(InitProcessing);
20712141

2142+
/* Set up reference point for stack depth checking */
2143+
stack_base_ptr=&stack_base;
2144+
20722145
/*
20732146
* Set default values for command-line options.
20742147
*/

‎src/backend/utils/misc/guc.c

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
* Written by Peter Eisentraut <peter_e@gmx.net>.
1111
*
1212
* IDENTIFICATION
13-
* $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.192 2004/03/23 01:23:48 tgl Exp $
13+
* $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.193 2004/03/24 22:40:29 tgl Exp $
1414
*
1515
*--------------------------------------------------------------------
1616
*/
@@ -1023,6 +1023,15 @@ static struct config_int ConfigureNamesInt[] =
10231023
16384,1024,INT_MAX /1024,NULL,NULL
10241024
},
10251025

1026+
{
1027+
{"max_stack_depth",PGC_SUSET,RESOURCES_MEM,
1028+
gettext_noop("Sets the maximum stack depth, in kilobytes."),
1029+
NULL
1030+
},
1031+
&max_stack_depth,
1032+
2048,100,INT_MAX /1024,assign_max_stack_depth,NULL
1033+
},
1034+
10261035
{
10271036
{"vacuum_cost_page_hit",PGC_USERSET,RESOURCES,
10281037
gettext_noop("Vacuum cost for a page found in the buffer cache."),
@@ -1097,14 +1106,6 @@ static struct config_int ConfigureNamesInt[] =
10971106
0,0,INT_MAX,NULL,NULL
10981107
},
10991108
#endif
1100-
{
1101-
{"max_expr_depth",PGC_USERSET,CLIENT_CONN_OTHER,
1102-
gettext_noop("Sets the maximum expression nesting depth."),
1103-
NULL
1104-
},
1105-
&max_expr_depth,
1106-
DEFAULT_MAX_EXPR_DEPTH,10,INT_MAX,NULL,NULL
1107-
},
11081109

11091110
{
11101111
{"statement_timeout",PGC_USERSET,CLIENT_CONN_STATEMENT,
@@ -1246,7 +1247,7 @@ static struct config_int ConfigureNamesInt[] =
12461247
},
12471248

12481249
{
1249-
{"debug_shared_buffers",PGC_POSTMASTER,RESOURCES_MEM,
1250+
{"debug_shared_buffers",PGC_POSTMASTER,STATS_MONITORING,
12501251
gettext_noop("Interval to report shared buffer status in seconds"),
12511252
NULL
12521253
},

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp