Age Owner Branch data TLA 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-2026, 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 ssize_t max_stack_depth_bytes = 100 * (ssize_t) 1024;
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
529 tgl@sss.pgh.pa.us 44 :CBC 2176 : 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 : 2176 : 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. This is also important
57 : : * with address sanitizer, see comment in stack_is_too_deep().
58 : : */
59 : : #ifdef HAVE__BUILTIN_FRAME_ADDRESS
60 : 2176 : stack_base_ptr = __builtin_frame_address(0);
61 : : #else
62 : : stack_base_ptr = &stack_base;
63 : : #endif
64 : :
65 : 2176 : return old;
66 : : }
67 : :
68 : : /*
69 : : * restore_stack_base: restore reference point for stack depth checking
70 : : *
71 : : * This can be used after set_stack_base() to restore the old value. This
72 : : * is currently only used in PL/Java. When PL/Java calls a backend function
73 : : * from different thread, the thread's stack is at a different location than
74 : : * the main thread's stack, so it sets the base pointer before the call, and
75 : : * restores it afterwards.
76 : : */
77 : : void
529 tgl@sss.pgh.pa.us 78 :UBC 0 : restore_stack_base(pg_stack_base_t base)
79 : : {
80 : 0 : stack_base_ptr = base;
81 : 0 : }
82 : :
83 : :
84 : : /*
85 : : * check_stack_depth/stack_is_too_deep: check for excessively deep recursion
86 : : *
87 : : * This should be called someplace in any recursive routine that might possibly
88 : : * recurse deep enough to overflow the stack. Most Unixen treat stack
89 : : * overflow as an unrecoverable SIGSEGV, so we want to error out ourselves
90 : : * before hitting the hardware limit.
91 : : *
92 : : * check_stack_depth() just throws an error summarily. stack_is_too_deep()
93 : : * can be used by code that wants to handle the error condition itself.
94 : : */
95 : : void
529 tgl@sss.pgh.pa.us 96 :CBC 178173471 : check_stack_depth(void)
97 : : {
98 [ + + ]: 178173471 : if (stack_is_too_deep())
99 : : {
100 [ + - ]: 20 : ereport(ERROR,
101 : : (errcode(ERRCODE_STATEMENT_TOO_COMPLEX),
102 : : errmsg("stack depth limit exceeded"),
103 : : errhint("Increase the configuration parameter \"max_stack_depth\" (currently %dkB), "
104 : : "after ensuring the platform's stack depth limit is adequate.",
105 : : max_stack_depth)));
106 : : }
107 : 178173451 : }
108 : :
109 : : bool
110 : 192048246 : stack_is_too_deep(void)
111 : : {
112 : : #ifndef HAVE__BUILTIN_FRAME_ADDRESS
113 : : char stack_top_loc;
114 : : #endif
115 : : ssize_t stack_depth;
116 : : char *stack_address;
117 : :
118 : : /*
119 : : * With address sanitizer's stack-use-after-return check, stack variables
120 : : * are moved to heap allocations, to allow to detect references to the
121 : : * memory at a later time. That would break our stack-depth check. Luckily
122 : : * __builtin_frame_address() works correctly, even under asan.
123 : : */
124 : : #ifndef HAVE__BUILTIN_FRAME_ADDRESS
125 : : stack_address = &stack_top_loc;
126 : : #else
2 andres@anarazel.de 127 : 192048246 : stack_address = (char *) __builtin_frame_address(0);
128 : : #endif
129 : :
130 : : /*
131 : : * Compute distance from reference point to my stack frame.
132 : : */
133 : 192048246 : stack_depth = (ssize_t) (stack_base_ptr - stack_address);
134 : :
135 : : /*
136 : : * Take abs value, since stacks grow up on some machines, down on others
137 : : */
529 tgl@sss.pgh.pa.us 138 [ - + ]: 192048246 : if (stack_depth < 0)
529 tgl@sss.pgh.pa.us 139 :UBC 0 : stack_depth = -stack_depth;
140 : :
141 : : /*
142 : : * Trouble?
143 : : *
144 : : * The test on stack_base_ptr prevents us from erroring out if called
145 : : * before that's been set. Logically it should be done first, but putting
146 : : * it last avoids wasting cycles during normal cases.
147 : : */
529 tgl@sss.pgh.pa.us 148 [ + + ]:CBC 192048246 : if (stack_depth > max_stack_depth_bytes &&
149 [ + - ]: 20 : stack_base_ptr != NULL)
150 : 20 : return true;
151 : :
152 : 192048226 : return false;
153 : : }
154 : :
155 : :
156 : : /* GUC check hook for max_stack_depth */
157 : : bool
158 : 7553 : check_max_stack_depth(int *newval, void **extra, GucSource source)
159 : : {
485 160 : 7553 : ssize_t newval_bytes = *newval * (ssize_t) 1024;
161 : 7553 : ssize_t stack_rlimit = get_stack_depth_rlimit();
162 : :
529 163 [ + - - + ]: 7553 : if (stack_rlimit > 0 && newval_bytes > stack_rlimit - STACK_DEPTH_SLOP)
164 : : {
485 tgl@sss.pgh.pa.us 165 :UBC 0 : GUC_check_errdetail("\"max_stack_depth\" must not exceed %zdkB.",
166 : 0 : (stack_rlimit - STACK_DEPTH_SLOP) / 1024);
529 167 : 0 : GUC_check_errhint("Increase the platform's stack depth limit via \"ulimit -s\" or local equivalent.");
168 : 0 : return false;
169 : : }
529 tgl@sss.pgh.pa.us 170 :CBC 7553 : return true;
171 : : }
172 : :
173 : : /* GUC assign hook for max_stack_depth */
174 : : void
175 : 7559 : assign_max_stack_depth(int newval, void *extra)
176 : : {
485 177 : 7559 : ssize_t newval_bytes = newval * (ssize_t) 1024;
178 : :
529 179 : 7559 : max_stack_depth_bytes = newval_bytes;
180 : 7559 : }
181 : :
182 : : /*
183 : : * Obtain platform stack depth limit (in bytes)
184 : : *
185 : : * Return -1 if unknown
186 : : *
187 : : * Note: we choose to use ssize_t not size_t as the result type because
188 : : * callers compute values that could theoretically go negative,
189 : : * such as "result - STACK_DEPTH_SLOP".
190 : : */
191 : : ssize_t
192 : 9802 : get_stack_depth_rlimit(void)
193 : : {
194 : : #if defined(HAVE_GETRLIMIT)
195 : : static ssize_t val = 0;
196 : :
197 : : /* This won't change after process launch, so check just once */
198 [ + + ]: 9802 : if (val == 0)
199 : : {
200 : : struct rlimit rlim;
201 : :
202 [ - + ]: 1292 : if (getrlimit(RLIMIT_STACK, &rlim) < 0)
529 tgl@sss.pgh.pa.us 203 :UBC 0 : val = -1;
529 tgl@sss.pgh.pa.us 204 [ - + ]:CBC 1292 : else if (rlim.rlim_cur == RLIM_INFINITY)
485 tgl@sss.pgh.pa.us 205 :UBC 0 : val = SSIZE_MAX;
206 : : /* rlim_cur is probably of an unsigned type, so check for overflow */
485 tgl@sss.pgh.pa.us 207 [ - + ]:CBC 1292 : else if (rlim.rlim_cur >= SSIZE_MAX)
485 tgl@sss.pgh.pa.us 208 :UBC 0 : val = SSIZE_MAX;
209 : : else
529 tgl@sss.pgh.pa.us 210 :CBC 1292 : val = rlim.rlim_cur;
211 : : }
212 : 9802 : return val;
213 : : #else
214 : : /* On Windows we set the backend stack size in src/backend/Makefile */
215 : : return WIN32_STACK_RLIMIT;
216 : : #endif
217 : : }
|