OSDN Git Service

On platforms that have getrlimit(RLIMIT_STACK), use it to ensure that
authorTom Lane <tgl@sss.pgh.pa.us>
Sat, 7 Oct 2006 19:25:29 +0000 (19:25 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Sat, 7 Oct 2006 19:25:29 +0000 (19:25 +0000)
max_stack_depth is not set to an unsafe value.

This commit also provides configure-time checking for <sys/resource.h>,
and cleans up some perhaps-unportable code associated with use of that
include file and getrlimit().

configure
configure.in
contrib/pgbench/pgbench.c
doc/src/sgml/config.sgml
src/backend/tcop/postgres.c
src/backend/utils/misc/guc.c
src/include/pg_config.h.in
src/include/tcop/tcopprot.h
src/include/utils/pg_rusage.h

index f37d2f6..f01b03b 100755 (executable)
--- a/configure
+++ b/configure
@@ -7589,7 +7589,8 @@ done
 
 
 
-for ac_header in crypt.h dld.h endian.h fp_class.h getopt.h ieeefp.h langinfo.h poll.h pwd.h sys/ipc.h sys/poll.h sys/pstat.h sys/select.h sys/sem.h sys/socket.h sys/shm.h sys/time.h sys/un.h termios.h utime.h wchar.h wctype.h kernel/OS.h kernel/image.h SupportDefs.h
+
+for ac_header in crypt.h dld.h endian.h fp_class.h getopt.h ieeefp.h langinfo.h poll.h pwd.h sys/ipc.h sys/poll.h sys/pstat.h sys/resource.h sys/select.h sys/sem.h sys/socket.h sys/shm.h sys/time.h sys/un.h termios.h utime.h wchar.h wctype.h kernel/OS.h kernel/image.h SupportDefs.h
 do
 as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
 if eval "test \"\${$as_ac_Header+set}\" = set"; then
@@ -13454,7 +13455,8 @@ fi
 
 
 
-for ac_func in cbrt dlopen fcvt fdatasync getpeereid memmove poll pstat readlink setproctitle setsid sigprocmask symlink sysconf towlower utime utimes waitpid wcstombs
+
+for ac_func in cbrt dlopen fcvt fdatasync getpeereid getrlimit memmove poll pstat readlink setproctitle setsid sigprocmask symlink sysconf towlower utime utimes waitpid wcstombs
 do
 as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
 echo "$as_me:$LINENO: checking for $ac_func" >&5
index 5292146..444ca1d 100644 (file)
@@ -1,5 +1,5 @@
 dnl Process this file with autoconf to produce a configure script.
-dnl $PostgreSQL: pgsql/configure.in,v 1.481 2006/10/05 00:07:45 tgl Exp $
+dnl $PostgreSQL: pgsql/configure.in,v 1.482 2006/10/07 19:25:28 tgl Exp $
 dnl
 dnl Developers, please strive to achieve this order:
 dnl
@@ -717,7 +717,7 @@ fi
 ##
 
 dnl sys/socket.h is required by AC_FUNC_ACCEPT_ARGTYPES
-AC_CHECK_HEADERS([crypt.h dld.h endian.h fp_class.h getopt.h ieeefp.h langinfo.h poll.h pwd.h sys/ipc.h sys/poll.h sys/pstat.h sys/select.h sys/sem.h sys/socket.h sys/shm.h sys/time.h sys/un.h termios.h utime.h wchar.h wctype.h kernel/OS.h kernel/image.h SupportDefs.h])
+AC_CHECK_HEADERS([crypt.h dld.h endian.h fp_class.h getopt.h ieeefp.h langinfo.h poll.h pwd.h sys/ipc.h sys/poll.h sys/pstat.h sys/resource.h sys/select.h sys/sem.h sys/socket.h sys/shm.h sys/time.h sys/un.h termios.h utime.h wchar.h wctype.h kernel/OS.h kernel/image.h SupportDefs.h])
 
 # At least on IRIX, cpp test for netinet/tcp.h will fail unless
 # netinet/in.h is included first.
@@ -865,7 +865,7 @@ PGAC_VAR_INT_TIMEZONE
 AC_FUNC_ACCEPT_ARGTYPES
 PGAC_FUNC_GETTIMEOFDAY_1ARG
 
-AC_CHECK_FUNCS([cbrt dlopen fcvt fdatasync getpeereid memmove poll pstat readlink setproctitle setsid sigprocmask symlink sysconf towlower utime utimes waitpid wcstombs])
+AC_CHECK_FUNCS([cbrt dlopen fcvt fdatasync getpeereid getrlimit memmove poll pstat readlink setproctitle setsid sigprocmask symlink sysconf towlower utime utimes waitpid wcstombs])
 
 AC_CHECK_DECLS(fdatasync, [], [], [#include <unistd.h>])
 AC_CHECK_DECLS(posix_fadvise, [], [], [#include <fcntl.h>])
index 447e848..3c15346 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $PostgreSQL: pgsql/contrib/pgbench/pgbench.c,v 1.56 2006/10/04 00:29:45 momjian Exp $
+ * $PostgreSQL: pgsql/contrib/pgbench/pgbench.c,v 1.57 2006/10/07 19:25:28 tgl Exp $
  *
  * pgbench: a simple benchmark program for PostgreSQL
  * written by Tatsuo Ishii
@@ -37,8 +37,9 @@
 #include <sys/select.h>
 #endif
 
-/* for getrlimit */
-#include <sys/resource.h>
+#ifdef HAVE_SYS_RESOURCE_H
+#include <sys/resource.h>              /* for getrlimit */
+#endif
 #endif   /* ! WIN32 */
 
 extern char *optarg;
@@ -1172,7 +1173,7 @@ main(int argc, char **argv)
        int                     nsocks;                 /* return from select(2) */
        int                     maxsock;                /* max socket number to be waited */
 
-#if !(defined(__CYGWIN__) || defined(__MINGW32__))
+#ifdef HAVE_GETRLIMIT
        struct rlimit rlim;
 #endif
 
@@ -1233,8 +1234,8 @@ main(int argc, char **argv)
                                        fprintf(stderr, "invalid number of clients: %d\n", nclients);
                                        exit(1);
                                }
-#if !(defined(__CYGWIN__) || defined(__MINGW32__))
-#ifdef RLIMIT_NOFILE                   /* most platform uses RLIMIT_NOFILE */
+#ifdef HAVE_GETRLIMIT
+#ifdef RLIMIT_NOFILE                   /* most platforms use RLIMIT_NOFILE */
                                if (getrlimit(RLIMIT_NOFILE, &rlim) == -1)
 #else                                                  /* but BSD doesn't ... */
                                if (getrlimit(RLIMIT_OFILE, &rlim) == -1)
@@ -1245,11 +1246,11 @@ main(int argc, char **argv)
                                }
                                if (rlim.rlim_cur <= (nclients + 2))
                                {
-                                       fprintf(stderr, "You need at least %d open files resource but you are only allowed to use %ld.\n", nclients + 2, (long) rlim.rlim_cur);
-                                       fprintf(stderr, "Use limit/ulimt to increase the limit before using pgbench.\n");
+                                       fprintf(stderr, "You need at least %d open files but you are only allowed to use %ld.\n", nclients + 2, (long) rlim.rlim_cur);
+                                       fprintf(stderr, "Use limit/ulimit to increase the limit before using pgbench.\n");
                                        exit(1);
                                }
-#endif
+#endif /* HAVE_GETRLIMIT */
                                break;
                        case 'C':
                                is_connect = 1;
index b3223e3..549ca75 100644 (file)
@@ -1,4 +1,4 @@
-<!-- $PostgreSQL: pgsql/doc/src/sgml/config.sgml,v 1.89 2006/09/25 22:12:24 tgl Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/config.sgml,v 1.90 2006/10/07 19:25:28 tgl Exp $ -->
 
 <chapter Id="runtime-config">
   <title>Server Configuration</title>
@@ -846,14 +846,22 @@ SET ENABLE_SEQSCAN TO OFF;
         equivalent), less a safety margin of a megabyte or so.  The safety
         margin is needed because the stack depth is not checked in every
         routine in the server, but only in key potentially-recursive routines
-        such as expression evaluation.  Setting the parameter higher than
-        the actual kernel limit will mean that a runaway recursive function
-        can crash an individual backend process.  The default setting is
+        such as expression evaluation.  The default setting is
         2048 KB (two megabytes), which is conservatively small and unlikely
         to risk crashes.  However, it may be too small to allow execution
         of complex functions.
         Only superusers can change this setting.
        </para>
+
+       <para>
+        Setting <varname>max_stack_depth</> higher than
+        the actual kernel limit will mean that a runaway recursive function
+        can crash an individual backend process.  On platforms where
+        <productname>PostgreSQL</productname> can determine the kernel limit,
+        it will not let you set this variable to an unsafe value.  However,
+        not all platforms provide the information, so caution is recommended
+        in selecting a value.
+       </para>
       </listitem>
      </varlistentry>
 
@@ -2173,19 +2181,6 @@ SELECT * FROM parent WHERE key = 2400;
       </listitem>
      </varlistentry>
 
-        <varlistentry id="guc-gin-fuzzy-search-limit" xreflabel="gin_fuzzy_search_limit">
-         <term><varname>gin_fuzzy_search_limit</varname> (<type>integer</type>)</term>
-         <indexterm>
-         <primary><varname>gin_fuzzy_search_limit</> configuration parameter</primary>
-         </indexterm>
-         <listitem>
-          <para>
-               Soft upper limit of the size of the set returned by GIN index. For more
-               information see <xref linkend="gin-tips">.
-          </para>
-         </listitem>
-        </varlistentry>
-         
      </variablelist>
     </sect2>
    </sect1>
@@ -3718,6 +3713,19 @@ dynamic_library_path = 'C:\tools\postgresql;H:\my_project\lib;$libdir'
        </para>
       </listitem>
      </varlistentry>
+
+     <varlistentry id="guc-gin-fuzzy-search-limit" xreflabel="gin_fuzzy_search_limit">
+      <term><varname>gin_fuzzy_search_limit</varname> (<type>integer</type>)</term>
+      <indexterm>
+       <primary><varname>gin_fuzzy_search_limit</> configuration parameter</primary>
+      </indexterm>
+      <listitem>
+       <para>
+        Soft upper limit of the size of the set returned by GIN index. For more
+        information see <xref linkend="gin-tips">.
+       </para>
+      </listitem>
+     </varlistentry>
      
      <varlistentry id="guc-local-preload-libraries" xreflabel="local_preload_libraries">
       <term><varname>local_preload_libraries</varname> (<type>string</type>)</term>
index 9145904..ee63220 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.511 2006/10/07 16:43:28 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.512 2006/10/07 19:25:28 tgl Exp $
  *
  * NOTES
  *       this is the "main" module of the postgres backend and
 #include <signal.h>
 #include <fcntl.h>
 #include <sys/socket.h>
-#if HAVE_SYS_SELECT_H
+#ifdef HAVE_SYS_SELECT_H
 #include <sys/select.h>
 #endif
+#ifdef HAVE_SYS_RESOURCE_H
+#include <sys/resource.h>
+#endif
 #ifdef HAVE_GETOPT_H
 #include <getopt.h>
 #endif
 
+#ifndef HAVE_GETRUSAGE
+#include "rusagestub.h"
+#endif
+
 #include "access/printtup.h"
 #include "access/xact.h"
 #include "catalog/pg_type.h"
@@ -78,7 +85,7 @@ bool          Log_disconnections = false;
 LogStmtLevel log_statement = LOGSTMT_NONE;
 
 /* GUC variable for maximum stack depth (measured in kilobytes) */
-int                    max_stack_depth = 2048;
+int                    max_stack_depth = 100;
 
 /* wait N seconds to allow attach from a debugger */
 int                    PostAuthDelay = 0;
@@ -91,7 +98,7 @@ int                   PostAuthDelay = 0;
  */
 
 /* max_stack_depth converted to bytes for speed of checking */
-static long max_stack_depth_bytes = 2048 * 1024L;
+static long max_stack_depth_bytes = 100 * 1024L;
 
 /*
  * Stack base pointer -- initialized by PostgresMain. This is not static
@@ -2490,9 +2497,7 @@ ProcessInterrupts(void)
  * 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 ...
+ * before hitting the hardware limit.
  */
 void
 check_stack_depth(void)
@@ -2530,13 +2535,24 @@ check_stack_depth(void)
        }
 }
 
-/* GUC assign hook to update max_stack_depth_bytes from max_stack_depth */
+/* GUC assign hook for max_stack_depth */
 bool
 assign_max_stack_depth(int newval, bool doit, GucSource source)
 {
-       /* Range check was already handled by guc.c */
+       long            newval_bytes = newval * 1024L;
+       long            stack_rlimit = get_stack_depth_rlimit();
+
+       if (stack_rlimit > 0 && newval_bytes > stack_rlimit - STACK_DEPTH_SLOP)
+       {
+               ereport((source >= PGC_S_INTERACTIVE) ? ERROR : LOG,
+                               (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+                                errmsg("\"max_stack_depth\" must not exceed %ldkB",
+                                               (stack_rlimit - STACK_DEPTH_SLOP) / 1024L),
+                                errhint("Increase the platform's stack depth limit via \"ulimit -s\" or local equivalent.")));
+               return false;
+       }
        if (doit)
-               max_stack_depth_bytes = newval * 1024L;
+               max_stack_depth_bytes = newval_bytes;
        return true;
 }
 
@@ -3635,11 +3651,36 @@ PostgresMain(int argc, char *argv[], const char *username)
        return 1;                                       /* keep compiler quiet */
 }
 
-#ifndef HAVE_GETRUSAGE
-#include "rusagestub.h"
-#else
-#include <sys/resource.h>
-#endif   /* HAVE_GETRUSAGE */
+
+/*
+ * Obtain platform stack depth limit (in bytes)
+ *
+ * Return -1 if unlimited or not known
+ */
+long
+get_stack_depth_rlimit(void)
+{
+#if defined(HAVE_GETRLIMIT) && defined(RLIMIT_STACK)
+       static long val = 0;
+
+       /* This won't change after process launch, so check just once */
+       if (val == 0)
+       {
+               struct rlimit rlim;
+
+               if (getrlimit(RLIMIT_STACK, &rlim) < 0)
+                       val = -1;
+               else if (rlim.rlim_cur == RLIM_INFINITY)
+                       val = -1;
+               else
+                       val = rlim.rlim_cur;
+       }
+       return val;
+#else /* no getrlimit */
+       return -1;
+#endif
+}
+
 
 static struct rusage Save_r;
 static struct timeval Save_t;
index 96244ec..d118755 100644 (file)
@@ -10,7 +10,7 @@
  * Written by Peter Eisentraut <peter_e@gmx.net>.
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.355 2006/10/06 17:14:00 petere Exp $
+ *       $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.356 2006/10/07 19:25:28 tgl Exp $
  *
  *--------------------------------------------------------------------
  */
@@ -1214,7 +1214,7 @@ static struct config_int ConfigureNamesInt[] =
                        GUC_UNIT_KB
                },
                &max_stack_depth,
-               2048, 100, MAX_KILOBYTES, assign_max_stack_depth, NULL
+               100, 100, MAX_KILOBYTES, assign_max_stack_depth, NULL
        },
 
        {
@@ -1610,7 +1610,7 @@ static struct config_int ConfigureNamesInt[] =
        },
 
        {
-               {"gin_fuzzy_search_limit", PGC_USERSET, UNGROUPED,
+               {"gin_fuzzy_search_limit", PGC_USERSET, CLIENT_CONN_OTHER,
                        gettext_noop("Sets the maximum allowed result for exact search by GIN."),
                        NULL,
                        0
@@ -2702,6 +2702,7 @@ InitializeGUCOptions(void)
 {
        int                     i;
        char       *env;
+       long            stack_rlimit;
 
        /*
         * Build sorted array of all GUC variables.
@@ -2839,6 +2840,27 @@ InitializeGUCOptions(void)
        env = getenv("PGCLIENTENCODING");
        if (env != NULL)
                SetConfigOption("client_encoding", env, PGC_POSTMASTER, PGC_S_ENV_VAR);
+
+       /*
+        * rlimit isn't exactly an "environment variable", but it behaves about
+        * the same.  If we can identify the platform stack depth rlimit, increase
+        * default stack depth setting up to whatever is safe (but at most 2MB).
+        */
+       stack_rlimit = get_stack_depth_rlimit();
+       if (stack_rlimit > 0)
+       {
+               int             new_limit = (stack_rlimit - STACK_DEPTH_SLOP) / 1024L;
+
+               if (new_limit > 100)
+               {
+                       char    limbuf[16];
+
+                       new_limit = Min(new_limit, 2048);
+                       sprintf(limbuf, "%d", new_limit);
+                       SetConfigOption("max_stack_depth", limbuf,
+                                                       PGC_POSTMASTER, PGC_S_ENV_VAR);
+               }
+       }
 }
 
 
index c6fe887..0043e9a 100644 (file)
 /* Define to 1 if you have the `getpwuid_r' function. */
 #undef HAVE_GETPWUID_R
 
+/* Define to 1 if you have the `getrlimit' function. */
+#undef HAVE_GETRLIMIT
+
 /* Define to 1 if you have the `getrusage' function. */
 #undef HAVE_GETRUSAGE
 
 /* Define to 1 if you have the <sys/pstat.h> header file. */
 #undef HAVE_SYS_PSTAT_H
 
+/* Define to 1 if you have the <sys/resource.h> header file. */
+#undef HAVE_SYS_RESOURCE_H
+
 /* Define to 1 if you have the <sys/select.h> header file. */
 #undef HAVE_SYS_SELECT_H
 
index e6637ed..2006b7c 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/tcop/tcopprot.h,v 1.84 2006/10/04 00:30:10 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/tcop/tcopprot.h,v 1.85 2006/10/07 19:25:29 tgl Exp $
  *
  * OLD COMMENTS
  *       This file was created so that other c files could get the two
@@ -23,6 +23,9 @@
 #include "utils/guc.h"
 
 
+/* Required daylight between max_stack_depth and the kernel limit, in bytes */
+#define STACK_DEPTH_SLOP (512 * 1024L)
+
 extern CommandDest whereToSendOutput;
 extern DLLIMPORT const char *debug_query_string;
 extern int     max_stack_depth;
@@ -62,6 +65,7 @@ extern void FloatExceptionHandler(SIGNAL_ARGS);
 extern void prepare_for_client_read(void);
 extern void client_read_ended(void);
 extern int     PostgresMain(int argc, char *argv[], const char *username);
+extern long get_stack_depth_rlimit(void);
 extern void ResetUsage(void);
 extern void ShowUsage(const char *title);
 extern int     check_log_duration(char *msec_str, bool was_logged);
index 32e4090..bb11812 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/utils/pg_rusage.h,v 1.2 2006/03/05 15:59:07 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/utils/pg_rusage.h,v 1.3 2006/10/07 19:25:29 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -16,7 +16,7 @@
 
 #include <sys/time.h>
 
-#ifdef HAVE_GETRUSAGE
+#ifdef HAVE_SYS_RESOURCE_H
 #include <sys/resource.h>
 #else
 #include "rusagestub.h"