]> granicus.if.org Git - postgresql/commitdiff
Add support for detecting register-stack overrun on IA64.
authorTom Lane <tgl@sss.pgh.pa.us>
Sat, 6 Nov 2010 23:36:29 +0000 (19:36 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Sat, 6 Nov 2010 23:36:29 +0000 (19:36 -0400)
Per recent investigation, the register stack can grow faster than the
regular stack depending on compiler and choice of options.  To avoid
crashes we must check both stacks in check_stack_depth().

Since this is poorly-tested code, committing only to HEAD for the
moment ... but we might want to consider back-patching later.

src/backend/tcop/postgres.c

index 60f3c7c63d08432687db9231cf4e229c3d1d604e..ff2e9bd0aaa87b22b2aa66098aa54a35d61aec7a 100644 (file)
@@ -119,6 +119,12 @@ static long max_stack_depth_bytes = 100 * 1024L;
  */
 char      *stack_base_ptr = NULL;
 
+/*
+ * On IA64 we also have to remember the register stack base.
+ */
+#if defined(__ia64__) || defined(__ia64)
+char      *register_stack_base_ptr = NULL;
+#endif
 
 /*
  * Flag to mark SIGHUP. Whenever the main loop comes around it
@@ -2983,6 +2989,35 @@ ProcessInterrupts(void)
 }
 
 
+/*
+ * IA64-specific code to fetch the AR.BSP register for stack depth checks.
+ *
+ * We currently support gcc and icc here.
+ */
+#if defined(__ia64__) || defined(__ia64)
+
+#include <asm/ia64regs.h>
+
+static __inline__ char *
+ia64_get_bsp(void)
+{
+       char       *ret;
+
+#ifndef __INTEL_COMPILER
+       /* the ;; is a "stop", seems to be required before fetching BSP */
+       __asm__ __volatile__(
+               ";;\n"
+               "       mov     %0=ar.bsp       \n"
+:              "=r"(ret));
+#else
+  ret = (char *) __getReg(_IA64_REG_AR_BSP);
+#endif
+  return ret;
+}
+
+#endif /* IA64 */
+
+
 /*
  * check_stack_depth: check for excessively deep recursion
  *
@@ -3026,6 +3061,29 @@ check_stack_depth(void)
                                                 "after ensuring the platform's stack depth limit is adequate.",
                                                 max_stack_depth)));
        }
+
+       /*
+        * On IA64 there is a separate "register" stack that requires its own
+        * independent check.  For this, we have to measure the change in the
+        * "BSP" pointer from PostgresMain to here.  Logic is just as above,
+        * except that we know IA64's register stack grows up.
+        *
+        * Note we assume that the same max_stack_depth applies to both stacks.
+        */
+#if defined(__ia64__) || defined(__ia64)
+       stack_depth = (long) (ia64_get_bsp() - register_stack_base_ptr);
+
+       if (stack_depth > max_stack_depth_bytes &&
+               register_stack_base_ptr != NULL)
+       {
+               ereport(ERROR,
+                               (errcode(ERRCODE_STATEMENT_TOO_COMPLEX),
+                                errmsg("stack depth limit exceeded"),
+                                errhint("Increase the configuration parameter \"max_stack_depth\" (currently %dkB), "
+                                                "after ensuring the platform's stack depth limit is adequate.",
+                                                max_stack_depth)));
+       }
+#endif /* IA64 */
 }
 
 /* GUC assign hook for max_stack_depth */
@@ -3435,6 +3493,9 @@ PostgresMain(int argc, char *argv[], const char *username)
 
        /* 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
 
        /* Compute paths, if we didn't inherit them from postmaster */
        if (my_exec_path[0] == '\0')