Add safety check on expression nesting depth. Default value is set by

a config.h #define, and the runtime value can be controlled via SET.
This commit is contained in:
Tom Lane 2000-03-17 05:29:07 +00:00
parent 341b328b18
commit 0e314d747e
7 changed files with 143 additions and 37 deletions

View File

@ -1,5 +1,5 @@
<!--
$Header: /cvsroot/pgsql/doc/src/sgml/ref/set.sgml,v 1.31 2000/02/27 21:07:03 tgl Exp $
$Header: /cvsroot/pgsql/doc/src/sgml/ref/set.sgml,v 1.32 2000/03/17 05:29:03 tgl Exp $
Postgres documentation
-->
@ -770,6 +770,30 @@ SET TRANSACTION ISOLATION LEVEL { READ COMMITTED | SERIALIZABLE }
</listitem>
</varlistentry>
<varlistentry>
<term>MAX_EXPR_DEPTH</term>
<listitem>
<para>
Sets the maximum expression nesting depth that the parser will
accept. The default value is high enough for any normal query,
but you can raise it if you need to. (But if you raise it too high,
you run the risk of backend crashes due to stack overflow.)
<variablelist>
<varlistentry>
<term><replaceable class="parameter">integer</replaceable></term>
<term>ON</term>
<listitem>
<para>
Maximum depth.
</para>
</listitem>
</varlistentry>
</variablelist>
</para>
</listitem>
</varlistentry>
</variablelist>
</para>
</refsect2>

View File

@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/variable.c,v 1.31 2000/02/27 21:10:41 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/variable.c,v 1.32 2000/03/17 05:29:04 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -25,6 +25,7 @@
#include "miscadmin.h"
#include "optimizer/cost.h"
#include "optimizer/paths.h"
#include "parser/parse_expr.h"
#include "utils/builtins.h"
#include "utils/tqual.h"
#include "utils/trace.h"
@ -86,6 +87,9 @@ static bool parse_geqo(char *);
static bool show_ksqo(void);
static bool reset_ksqo(void);
static bool parse_ksqo(char *);
static bool reset_max_expr_depth(void);
static bool show_max_expr_depth(void);
static bool parse_max_expr_depth(char *);
static bool show_XactIsoLevel(void);
static bool reset_XactIsoLevel(void);
static bool parse_XactIsoLevel(char *);
@ -935,6 +939,44 @@ reset_ksqo()
return TRUE;
}
/*
* MAX_EXPR_DEPTH
*/
static bool
parse_max_expr_depth(char *value)
{
int newval;
if (value == NULL)
{
reset_max_expr_depth();
return TRUE;
}
newval = pg_atoi(value, sizeof(int), '\0');
if (newval < 10) /* somewhat arbitrary limit */
elog(ERROR, "Bad value for MAX_EXPR_DEPTH (%s)", value);
max_expr_depth = newval;
return TRUE;
}
static bool
show_max_expr_depth()
{
elog(NOTICE, "MAX_EXPR_DEPTH is %d", max_expr_depth);
return TRUE;
}
static bool
reset_max_expr_depth(void)
{
max_expr_depth = DEFAULT_MAX_EXPR_DEPTH;
return TRUE;
}
/* SET TRANSACTION */
static bool
@ -1103,6 +1145,10 @@ static struct VariableParsers
{
"ksqo", parse_ksqo, show_ksqo, reset_ksqo
},
{
"max_expr_depth", parse_max_expr_depth,
show_max_expr_depth, reset_max_expr_depth
},
{
"XactIsoLevel", parse_XactIsoLevel, show_XactIsoLevel, reset_XactIsoLevel
},

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.73 2000/03/14 23:06:32 thomas Exp $
* $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.74 2000/03/17 05:29:05 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -32,6 +32,11 @@
#include "utils/builtins.h"
#include "utils/syscache.h"
int max_expr_depth = DEFAULT_MAX_EXPR_DEPTH;
static int expr_depth_counter = 0;
static Node *parser_typecast_constant(Value *expr, TypeName *typename);
static Node *parser_typecast_expression(ParseState *pstate,
Node *expr, TypeName *typename);
@ -40,6 +45,20 @@ static Node *transformIdent(ParseState *pstate, Ident *ident, int precedence);
static Node *transformIndirection(ParseState *pstate, Node *basenode,
List *indirection);
/*
* Initialize for parsing a new query.
*
* We reset the expression depth counter here, in case it was left nonzero
* due to elog()'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
@ -55,6 +74,17 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
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)
elog(ERROR, "Expression too complex: nesting depth exceeds max_expr_depth = %d",
max_expr_depth);
switch (nodeTag(expr))
{
case T_Attr:
@ -532,6 +562,8 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
break;
}
expr_depth_counter--;
return result;
}

View File

@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/parser.c,v 1.43 2000/01/26 05:56:43 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/parser/parser.c,v 1.44 2000/03/17 05:29:05 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -16,6 +16,7 @@
#include "parser/analyze.h"
#include "parser/gramparse.h"
#include "parser/parser.h"
#include "parser/parse_expr.h"
#if defined(FLEX_SCANNER)
extern void DeleteBuffer(void);
@ -46,6 +47,8 @@ parser(char *str, Oid *typev, int nargs)
parsetree = NIL; /* in case parser forgets to set it */
parser_init(typev, nargs);
parse_expr_init();
yyresult = yyparse();
#if defined(FLEX_SCANNER)

View File

@ -3,7 +3,7 @@
*
* Copyright 2000 by PostgreSQL Global Development Group
*
* $Header: /cvsroot/pgsql/src/bin/psql/tab-complete.c,v 1.15 2000/03/05 13:30:19 petere Exp $
* $Header: /cvsroot/pgsql/src/bin/psql/tab-complete.c,v 1.16 2000/03/17 05:29:06 tgl Exp $
*/
/*-----------
@ -195,6 +195,7 @@ char ** psql_completion(char *text, int start, int end)
"client_encoding",
"server_encoding",
"KSQO",
"max_expr_depth",
"XactIsoLevel",
"PG_Options",
NULL

View File

@ -1,8 +1,14 @@
/* the purpose of this file is to reduce the use of #ifdef's through
* the code base by those porting the software, and to facilitate the
* eventual use of autoconf to build the server
/*
* PostgreSQL configuration-settings file.
*
* config.h.in is processed by configure to produce config.h.
*
* If you want to modify any of the tweakable settings in the first part
* of this file, you can do it in config.h.in before running configure,
* or in config.h afterwards. Of course, if you edit config.h, then your
* changes will be overwritten the next time you run configure.
*
* $Id: config.h.in,v 1.110 2000/03/17 05:29:06 tgl Exp $
*/
#ifndef CONFIG_H
@ -11,7 +17,7 @@
/*
* Default runtime limit on number of backend server processes per postmaster;
* this is just the default setting for the postmaster's -N switch.
* (Actual value is set by configure script.)
* (Actual value is now set by configure script.)
*/
#undef DEF_MAXBACKENDS
@ -70,17 +76,11 @@
/*
* DEF_PGPORT is the TCP port number on which the Postmaster listens by
* default. This can be overriden by command options, environment variables,
* and the postconfig hook. (set by configure script)
* and the postconfig hook. (now set by configure script)
*/
#undef DEF_PGPORT
/*
* If you do not plan to use Host based authentication,
* comment out the following line (set by build script)
*/
#undef HBA
/*
* As soon as the backend blocks on a lock, it waits this number of seconds
* before checking for a deadlock.
@ -89,12 +89,6 @@
*/
#define DEADLOCK_CHECK_TIMER 1
/*
* This flag enables the use of indexes in plans generated for function
* executions which normally are always executed with sequential scans.
*/
#define INDEXSCAN_PATCH
/*
* Maximum number of columns in an index and maximum number of arguments
* to a function. They must be the same value.
@ -121,16 +115,6 @@
*/
/* #define UNSAFE_FLOATS */
/*
* There is a bug in the function executor. The backend crashes while trying to
* execute an sql function containing an utility command (create, notify, ...).
* The bug is part in the planner, which returns a number of plans different
* than the number of commands if there are utility commands in the query, and
* in part in the function executor which assumes that all commands are normal
* query commands and causes a SIGSEGV trying to execute commands without plan.
*/
#define FUNC_UTIL_PATCH
/*
* Define this to make libpgtcl's "pg_result -assign" command process C-style
* backslash sequences in returned tuple data and convert Postgres array
@ -188,7 +172,7 @@
#define FASTBUILD /* access/nbtree/nbtsort.c */
/*
* TBL_FREE_CMD_MEMORY: free memory allocated for an user query inside
* TBL_FREE_CMD_MEMORY: free memory allocated for a user query inside
* transaction block after this query is done.
*/
#define TBL_FREE_CMD_MEMORY
@ -232,9 +216,22 @@
*/
#define MAXPGPATH 1024
/*
* DEFAULT_MAX_EXPR_DEPTH: default value of max_expr_depth SET variable.
*/
#define DEFAULT_MAX_EXPR_DEPTH 10000
/*
* Leftover cruft for enabling long-since-verified patches.
* You don't want to touch these.
*/
#define INDEXSCAN_PATCH
#define FUNC_UTIL_PATCH
/*
*------------------------------------------------------------------------
* The following is set using configure.
* Everything past here is set by the configure script.
*------------------------------------------------------------------------
*/

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: parse_expr.h,v 1.17 2000/02/26 21:11:09 tgl Exp $
* $Id: parse_expr.h,v 1.18 2000/03/17 05:29:07 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -20,9 +20,12 @@
#define EXPR_COLUMN_FIRST 1
#define EXPR_RELATION_FIRST 2
extern int max_expr_depth;
extern Node *transformExpr(ParseState *pstate, Node *expr, int precedence);
extern Oid exprType(Node *expr);
extern int32 exprTypmod(Node *expr);
extern bool exprIsLengthCoercion(Node *expr, int32 *coercedTypmod);
extern void parse_expr_init(void);
#endif /* PARSE_EXPR_H */