PostgreSQL Source Code git master
stack_depth.c
Go to the documentation of this file.
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) */
27
28/* max_stack_depth converted to bytes for speed of checking */
29static 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 */
35static 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 */
45{
46#ifndef HAVE__BUILTIN_FRAME_ADDRESS
47 char stack_base;
48#endif
50
51 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 stack_base_ptr = __builtin_frame_address(0);
60#else
61 stack_base_ptr = &stack_base;
62#endif
63
64 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 */
76void
78{
79 stack_base_ptr = base;
80}
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 */
94void
96{
98 {
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.",
105 }
106}
107
108bool
110{
111 char stack_top_loc;
112 ssize_t stack_depth;
113
114 /*
115 * Compute distance from reference point to my local variables
116 */
117 stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
118
119 /*
120 * Take abs value, since stacks grow up on some machines, down on others
121 */
122 if (stack_depth < 0)
123 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 if (stack_depth > max_stack_depth_bytes &&
133 stack_base_ptr != NULL)
134 return true;
135
136 return false;
137}
138
139
140/* GUC check hook for max_stack_depth */
141bool
143{
144 ssize_t newval_bytes = *newval * (ssize_t) 1024;
145 ssize_t stack_rlimit = get_stack_depth_rlimit();
146
147 if (stack_rlimit > 0 && newval_bytes > stack_rlimit - STACK_DEPTH_SLOP)
148 {
149 GUC_check_errdetail("\"max_stack_depth\" must not exceed %zdkB.",
150 (stack_rlimit - STACK_DEPTH_SLOP) / 1024);
151 GUC_check_errhint("Increase the platform's stack depth limit via \"ulimit -s\" or local equivalent.");
152 return false;
153 }
154 return true;
155}
156
157/* GUC assign hook for max_stack_depth */
158void
160{
161 ssize_t newval_bytes = newval * (ssize_t) 1024;
162
163 max_stack_depth_bytes = newval_bytes;
164}
165
166/*
167 * Obtain platform stack depth limit (in bytes)
168 *
169 * Return -1 if unknown
170 *
171 * Note: we choose to use ssize_t not size_t as the result type because
172 * callers compute values that could theoretically go negative,
173 * such as "result - STACK_DEPTH_SLOP".
174 */
175ssize_t
177{
178#if defined(HAVE_GETRLIMIT)
179 static ssize_t val = 0;
180
181 /* This won't change after process launch, so check just once */
182 if (val == 0)
183 {
184 struct rlimit rlim;
185
186 if (getrlimit(RLIMIT_STACK, &rlim) < 0)
187 val = -1;
188 else if (rlim.rlim_cur == RLIM_INFINITY)
189 val = SSIZE_MAX;
190 /* rlim_cur is probably of an unsigned type, so check for overflow */
191 else if (rlim.rlim_cur >= SSIZE_MAX)
192 val = SSIZE_MAX;
193 else
194 val = rlim.rlim_cur;
195 }
196 return val;
197#else
198 /* On Windows we set the backend stack size in src/backend/Makefile */
199 return WIN32_STACK_RLIMIT;
200#endif
201}
int errhint(const char *fmt,...)
Definition: elog.c:1317
int errcode(int sqlerrcode)
Definition: elog.c:853
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:149
#define newval
#define GUC_check_errdetail
Definition: guc.h:480
GucSource
Definition: guc.h:112
#define GUC_check_errhint
Definition: guc.h:484
long val
Definition: informix.c:689
#define STACK_DEPTH_SLOP
Definition: miscadmin.h:296
char * pg_stack_base_t
Definition: miscadmin.h:298
static rewind_source * source
Definition: pg_rewind.c:89
void restore_stack_base(pg_stack_base_t base)
Definition: stack_depth.c:77
int max_stack_depth
Definition: stack_depth.c:26
ssize_t get_stack_depth_rlimit(void)
Definition: stack_depth.c:176
bool check_max_stack_depth(int *newval, void **extra, GucSource source)
Definition: stack_depth.c:142
bool stack_is_too_deep(void)
Definition: stack_depth.c:109
void assign_max_stack_depth(int newval, void *extra)
Definition: stack_depth.c:159
static char * stack_base_ptr
Definition: stack_depth.c:35
static ssize_t max_stack_depth_bytes
Definition: stack_depth.c:29
void check_stack_depth(void)
Definition: stack_depth.c:95
pg_stack_base_t set_stack_base(void)
Definition: stack_depth.c:44