Do stack-depth checking in all postmaster children.
authorHeikki Linnakangas <heikki.linnakangas@iki.fi>
Sun, 8 Apr 2012 15:28:12 +0000 (18:28 +0300)
committerHeikki Linnakangas <heikki.linnakangas@iki.fi>
Sun, 8 Apr 2012 16:08:13 +0000 (19:08 +0300)
We used to only initialize the stack base pointer when starting up a regular
backend, not in other processes. In particular, autovacuum workers can run
arbitrary user code, and without stack-depth checking, infinite recursion
in e.g an index expression will bring down the whole cluster.

The comment about PL/Java using set_stack_base() is not yet true. As the
code stands, PL/java still modifies the stack_base_ptr variable directly.
However, it's been discussed in the PL/Java mailing list that it should be
changed to use the function, because PL/Java is currently oblivious to the
register stack used on Itanium. There's another issues with PL/Java, namely
that the stack base pointer it sets is not really the base of the stack, it
could be something close to the bottom of the stack. That's a separate issue
that might need some further changes to this code, but that's a different
story.

Backpatch to all supported releases.

src/backend/postmaster/postmaster.c
src/backend/tcop/postgres.c
src/include/miscadmin.h

index 067edcfe290d19f2d9bb24d71cf21504d676e1a4..3f7605ce9b1ef004d6430fe31d9b632798b49fe5 100644 (file)
@@ -970,6 +970,11 @@ PostmasterMain(int argc, char *argv[])
         */
        set_max_safe_fds();
 
+       /*
+        * Set reference point for stack-depth checking.
+        */
+       set_stack_base();
+
        /*
         * Initialize the list of active backends.
         */
@@ -3990,6 +3995,11 @@ SubPostmasterMain(int argc, char *argv[])
        memset(&port, 0, sizeof(Port));
        read_backend_variables(argv[2], &port);
 
+       /*
+        * Set reference point for stack-depth checking
+        */
+       set_stack_base();
+
        /*
         * Set up memory area for GSS information. Mirrors the code in ConnCreate
         * for the non-exec case.
index 660a67412dcc53e3e474ef7c7baa6f3f37535988..638ba0fe066eb43246fab3480211133354e8e3fc 100644 (file)
@@ -114,8 +114,10 @@ int                        PostAuthDelay = 0;
 static long max_stack_depth_bytes = 100 * 1024L;
 
 /*
- * Stack base pointer -- initialized by PostgresMain. This is not static
- * so that PL/Java can modify it.
+ * Stack base pointer -- initialized by PostmasterMain and inherited by
+ * subprocesses. This is not static because old versions of PL/Java modify
+ * it directly. Newer versions use set_stack_base(), but we want to stay
+ * binary-compatible for the time being.
  */
 char      *stack_base_ptr = NULL;
 
@@ -3002,6 +3004,53 @@ ia64_get_bsp(void)
 #endif   /* IA64 */
 
 
+/*
+ * set_stack_base: set up reference point for stack depth checking
+ *
+ * Returns the old reference point, if any.
+ */
+pg_stack_base_t
+set_stack_base(void)
+{
+       char            stack_base;
+       pg_stack_base_t old;
+
+#if defined(__ia64__) || defined(__ia64)
+       old.stack_base_ptr = stack_base_ptr;
+       old.register_stack_base_ptr = register_stack_base_ptr;
+#else
+       old = stack_base_ptr;
+#endif
+
+       /* Set up reference point for stack depth checking */
+       stack_base_ptr = &stack_base;
+#if defined(__ia64__) || defined(__ia64)
+       register_stack_base_ptr = ia64_get_bsp();
+#endif
+
+       return old;
+}
+
+/*
+ * restore_stack_base: restore reference point for stack depth checking
+ *
+ * This can be used after set_stack_base() to restore the old value. This
+ * is currently only used in PL/Java. When PL/Java calls a backend function
+ * from different thread, the thread's stack is at a different location than
+ * the main thread's stack, so it sets the base pointer before the call, and
+ * restores it afterwards.
+ */
+void
+restore_stack_base(pg_stack_base_t base)
+{
+#if defined(__ia64__) || defined(__ia64)
+       stack_base_ptr = base.stack_base_ptr;
+       register_stack_base_ptr = base.register_stack_base_ptr;
+#else
+       stack_base_ptr = base;
+#endif
+}
+
 /*
  * check_stack_depth: check for excessively deep recursion
  *
@@ -3017,7 +3066,7 @@ check_stack_depth(void)
        long            stack_depth;
 
        /*
-        * Compute distance from PostgresMain's local variables to my own
+        * Compute distance from reference point to to my local variables
         */
        stack_depth = (long) (stack_base_ptr - &stack_top_loc);
 
@@ -3459,7 +3508,6 @@ PostgresMain(int argc, char *argv[], const char *username)
 {
        const char *dbname;
        int                     firstchar;
-       char            stack_base;
        StringInfoData input_message;
        sigjmp_buf      local_sigjmp_buf;
        volatile bool send_ready_for_query = true;
@@ -3486,10 +3534,7 @@ PostgresMain(int argc, char *argv[], const char *username)
        SetProcessingMode(InitProcessing);
 
        /* Set up reference point for stack depth checking */
-       stack_base_ptr = &stack_base;
-#if defined(__ia64__) || defined(__ia64)
-       register_stack_base_ptr = ia64_get_bsp();
-#endif
+       set_stack_base();
 
        /* Compute paths, if we didn't inherit them from postmaster */
        if (my_exec_path[0] == '\0')
index 9d194171a564bf9be8786a4649f64bc3aa6810a4..29363ead1a0ae7c9d641dd6b70ba1c09967f7116 100644 (file)
@@ -235,6 +235,19 @@ extern bool VacuumCostActive;
 
 
 /* in tcop/postgres.c */
+
+#if defined(__ia64__) || defined(__ia64)
+typedef struct
+{
+       char       *stack_base_ptr;
+       char       *register_stack_base_ptr;
+} pg_stack_base_t;
+#else
+typedef char *pg_stack_base_t;
+#endif
+
+extern pg_stack_base_t set_stack_base(void);
+extern void restore_stack_base(pg_stack_base_t base);
 extern void check_stack_depth(void);
 
 /* in tcop/utility.c */