OSDN Git Service

Add safety check on expression nesting depth. Default value is set by
authorTom Lane <tgl@sss.pgh.pa.us>
Fri, 17 Mar 2000 05:29:07 +0000 (05:29 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Fri, 17 Mar 2000 05:29:07 +0000 (05:29 +0000)
a config.h #define, and the runtime value can be controlled via SET.

doc/src/sgml/ref/set.sgml
src/backend/commands/variable.c
src/backend/parser/parse_expr.c
src/backend/parser/parser.c
src/bin/psql/tab-complete.c
src/include/config.h.in
src/include/parser/parse_expr.h

index 87d4d6f..cd6265e 100644 (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>
index 81c1e10..482b9a2 100644 (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
@@ -1104,6 +1146,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
        },
        {
index e2e297c..419ad4d 100644 (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 $
  *
  *-------------------------------------------------------------------------
  */
 #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;
 }
 
index a4be685..488df8a 100644 (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)
index 54561cb..5aec29d 100644 (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
index fb47206..b7a95be 100644 (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
 
 /* 
  * 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.
  * We don't check for deadlocks just before sleeping because a deadlock is
 #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.
  *
 /* #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
  * attributes into Tcl lists.  CAUTION: this conversion is *wrong* unless
 #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
 #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.
  *------------------------------------------------------------------------
  */
 
index 50d7b28..7c76001 100644 (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 $
  *
  *-------------------------------------------------------------------------
  */
 #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 */