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:
parent
341b328b18
commit
0e314d747e
@ -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>
|
||||
|
@ -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
|
||||
},
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
*------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
@ -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 */
|
||||
|
Loading…
x
Reference in New Issue
Block a user