Line data Source code
1 : /*------------------------------------------------------------------------- 2 : * 3 : * stack_depth.c 4 : * Functions for monitoring and limiting process stack depth 5 : * 6 : * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group 7 : * Portions Copyright (c) 1994, Regents of the University of California 8 : * 9 : * 10 : * IDENTIFICATION 11 : * src/backend/utils/misc/stack_depth.c 12 : * 13 : *------------------------------------------------------------------------- 14 : */ 15 : 16 : #include "postgres.h" 17 : 18 : #include <limits.h> 19 : #include <sys/resource.h> 20 : 21 : #include "miscadmin.h" 22 : #include "utils/guc_hooks.h" 23 : 24 : 25 : /* GUC variable for maximum stack depth (measured in kilobytes) */ 26 : int max_stack_depth = 100; 27 : 28 : /* max_stack_depth converted to bytes for speed of checking */ 29 : static long max_stack_depth_bytes = 100 * 1024L; 30 : 31 : /* 32 : * Stack base pointer -- initialized by set_stack_base(), which 33 : * should be called from main(). 34 : */ 35 : static char *stack_base_ptr = NULL; 36 : 37 : 38 : /* 39 : * set_stack_base: set up reference point for stack depth checking 40 : * 41 : * Returns the old reference point, if any. 42 : */ 43 : pg_stack_base_t 44 3308 : set_stack_base(void) 45 : { 46 : #ifndef HAVE__BUILTIN_FRAME_ADDRESS 47 : char stack_base; 48 : #endif 49 : pg_stack_base_t old; 50 : 51 3308 : old = stack_base_ptr; 52 : 53 : /* 54 : * Set up reference point for stack depth checking. On recent gcc we use 55 : * __builtin_frame_address() to avoid a warning about storing a local 56 : * variable's address in a long-lived variable. 57 : */ 58 : #ifdef HAVE__BUILTIN_FRAME_ADDRESS 59 3308 : stack_base_ptr = __builtin_frame_address(0); 60 : #else 61 : stack_base_ptr = &stack_base; 62 : #endif 63 : 64 3308 : return old; 65 : } 66 : 67 : /* 68 : * restore_stack_base: restore reference point for stack depth checking 69 : * 70 : * This can be used after set_stack_base() to restore the old value. This 71 : * is currently only used in PL/Java. When PL/Java calls a backend function 72 : * from different thread, the thread's stack is at a different location than 73 : * the main thread's stack, so it sets the base pointer before the call, and 74 : * restores it afterwards. 75 : */ 76 : void 77 0 : restore_stack_base(pg_stack_base_t base) 78 : { 79 0 : stack_base_ptr = base; 80 0 : } 81 : 82 : 83 : /* 84 : * check_stack_depth/stack_is_too_deep: check for excessively deep recursion 85 : * 86 : * This should be called someplace in any recursive routine that might possibly 87 : * recurse deep enough to overflow the stack. Most Unixen treat stack 88 : * overflow as an unrecoverable SIGSEGV, so we want to error out ourselves 89 : * before hitting the hardware limit. 90 : * 91 : * check_stack_depth() just throws an error summarily. stack_is_too_deep() 92 : * can be used by code that wants to handle the error condition itself. 93 : */ 94 : void 95 564008798 : check_stack_depth(void) 96 : { 97 564008798 : if (stack_is_too_deep()) 98 : { 99 30 : ereport(ERROR, 100 : (errcode(ERRCODE_STATEMENT_TOO_COMPLEX), 101 : errmsg("stack depth limit exceeded"), 102 : errhint("Increase the configuration parameter \"max_stack_depth\" (currently %dkB), " 103 : "after ensuring the platform's stack depth limit is adequate.", 104 : max_stack_depth))); 105 : } 106 564008768 : } 107 : 108 : bool 109 585748390 : stack_is_too_deep(void) 110 : { 111 : char stack_top_loc; 112 : long stack_depth; 113 : 114 : /* 115 : * Compute distance from reference point to my local variables 116 : */ 117 585748390 : stack_depth = (long) (stack_base_ptr - &stack_top_loc); 118 : 119 : /* 120 : * Take abs value, since stacks grow up on some machines, down on others 121 : */ 122 585748390 : if (stack_depth < 0) 123 0 : stack_depth = -stack_depth; 124 : 125 : /* 126 : * Trouble? 127 : * 128 : * The test on stack_base_ptr prevents us from erroring out if called 129 : * before that's been set. Logically it should be done first, but putting 130 : * it last avoids wasting cycles during normal cases. 131 : */ 132 585748390 : if (stack_depth > max_stack_depth_bytes && 133 30 : stack_base_ptr != NULL) 134 30 : return true; 135 : 136 585748360 : return false; 137 : } 138 : 139 : 140 : /* GUC check hook for max_stack_depth */ 141 : bool 142 10226 : check_max_stack_depth(int *newval, void **extra, GucSource source) 143 : { 144 10226 : long newval_bytes = *newval * 1024L; 145 10226 : long stack_rlimit = get_stack_depth_rlimit(); 146 : 147 10226 : if (stack_rlimit > 0 && newval_bytes > stack_rlimit - STACK_DEPTH_SLOP) 148 : { 149 0 : GUC_check_errdetail("\"max_stack_depth\" must not exceed %ldkB.", 150 0 : (stack_rlimit - STACK_DEPTH_SLOP) / 1024L); 151 0 : GUC_check_errhint("Increase the platform's stack depth limit via \"ulimit -s\" or local equivalent."); 152 0 : return false; 153 : } 154 10226 : return true; 155 : } 156 : 157 : /* GUC assign hook for max_stack_depth */ 158 : void 159 10234 : assign_max_stack_depth(int newval, void *extra) 160 : { 161 10234 : long newval_bytes = newval * 1024L; 162 : 163 10234 : max_stack_depth_bytes = newval_bytes; 164 10234 : } 165 : 166 : /* 167 : * Obtain platform stack depth limit (in bytes) 168 : * 169 : * Return -1 if unknown 170 : */ 171 : long 172 13022 : get_stack_depth_rlimit(void) 173 : { 174 : #if defined(HAVE_GETRLIMIT) 175 : static long val = 0; 176 : 177 : /* This won't change after process launch, so check just once */ 178 13022 : if (val == 0) 179 : { 180 : struct rlimit rlim; 181 : 182 1982 : if (getrlimit(RLIMIT_STACK, &rlim) < 0) 183 0 : val = -1; 184 1982 : else if (rlim.rlim_cur == RLIM_INFINITY) 185 0 : val = LONG_MAX; 186 : /* rlim_cur is probably of an unsigned type, so check for overflow */ 187 1982 : else if (rlim.rlim_cur >= LONG_MAX) 188 0 : val = LONG_MAX; 189 : else 190 1982 : val = rlim.rlim_cur; 191 : } 192 13022 : return val; 193 : #else 194 : /* On Windows we set the backend stack size in src/backend/Makefile */ 195 : return WIN32_STACK_RLIMIT; 196 : #endif 197 : }