1
0
mirror of https://github.com/postgres/postgres.git synced 2025-11-01 21:31:19 +03:00

Replace max_expr_depth parameter with a max_stack_depth parameter that

is measured in kilobytes and checked against actual physical execution
stack depth, as per my proposal of 30-Dec.  This gives us a fairly
bulletproof defense against crashing due to runaway recursive functions.
This commit is contained in:
Tom Lane
2004-03-24 22:40:29 +00:00
parent a09b9a36d3
commit 8899a2aba9
13 changed files with 157 additions and 79 deletions

View File

@@ -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.
*/