Coverage Report

Created: 2026-11-09 07:20

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/postgres/src/backend/utils/misc/stack_depth.c
Line
Count
Source
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
44
set_stack_base(void)
45
7.30k
{
46
#ifndef HAVE__BUILTIN_FRAME_ADDRESS
47
  char    stack_base;
48
#endif
49
7.30k
  pg_stack_base_t old;
50
51
7.30k
  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
7.30k
#ifdef HAVE__BUILTIN_FRAME_ADDRESS
60
7.30k
  stack_base_ptr = __builtin_frame_address(0);
61
#else
62
  stack_base_ptr = &stack_base;
63
#endif
64
65
7.30k
  return old;
66
7.30k
}
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
78
restore_stack_base(pg_stack_base_t base)
79
0
{
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
96
check_stack_depth(void)
97
18.9k
{
98
18.9k
  if (stack_is_too_deep())
99
3
  {
100
3
    ereport(ERROR,
101
3
        (errcode(ERRCODE_STATEMENT_TOO_COMPLEX),
102
3
         errmsg("stack depth limit exceeded"),
103
3
         errhint("Increase the configuration parameter \"max_stack_depth\" (currently %dkB), "
104
3
             "after ensuring the platform's stack depth limit is adequate.",
105
3
             max_stack_depth)));
106
3
  }
107
18.9k
}
108
109
bool
110
stack_is_too_deep(void)
111
18.9k
{
112
#ifndef HAVE__BUILTIN_FRAME_ADDRESS
113
  char    stack_top_loc;
114
#endif
115
18.9k
  ssize_t   stack_depth;
116
18.9k
  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
127
18.9k
  stack_address = (char *) __builtin_frame_address(0);
128
18.9k
#endif
129
130
  /*
131
   * Compute distance from reference point to my stack frame.
132
   */
133
18.9k
  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
   */
138
18.9k
  if (stack_depth < 0)
139
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
   */
148
18.9k
  if (stack_depth > max_stack_depth_bytes &&
149
3
    stack_base_ptr != NULL)
150
3
    return true;
151
152
18.9k
  return false;
153
18.9k
}
154
155
156
/* GUC check hook for max_stack_depth */
157
bool
158
check_max_stack_depth(int *newval, void **extra, GucSource source)
159
4
{
160
4
  ssize_t   newval_bytes = *newval * (ssize_t) 1024;
161
4
  ssize_t   stack_rlimit = get_stack_depth_rlimit();
162
163
4
  if (stack_rlimit > 0 && newval_bytes > stack_rlimit - STACK_DEPTH_SLOP)
164
0
  {
165
0
    GUC_check_errdetail("\"max_stack_depth\" must not exceed %zdkB.",
166
0
              (stack_rlimit - STACK_DEPTH_SLOP) / 1024);
167
0
    GUC_check_errhint("Increase the platform's stack depth limit via \"ulimit -s\" or local equivalent.");
168
0
    return false;
169
0
  }
170
4
  return true;
171
4
}
172
173
/* GUC assign hook for max_stack_depth */
174
void
175
assign_max_stack_depth(int newval, void *extra)
176
4
{
177
4
  ssize_t   newval_bytes = newval * (ssize_t) 1024;
178
179
4
  max_stack_depth_bytes = newval_bytes;
180
4
}
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
get_stack_depth_rlimit(void)
193
6
{
194
6
#if defined(HAVE_GETRLIMIT)
195
6
  static ssize_t val = 0;
196
197
  /* This won't change after process launch, so check just once */
198
6
  if (val == 0)
199
2
  {
200
2
    struct rlimit rlim;
201
202
2
    if (getrlimit(RLIMIT_STACK, &rlim) < 0)
203
0
      val = -1;
204
2
    else if (rlim.rlim_cur == RLIM_INFINITY)
205
0
      val = SSIZE_MAX;
206
    /* rlim_cur is probably of an unsigned type, so check for overflow */
207
2
    else if (rlim.rlim_cur >= SSIZE_MAX)
208
0
      val = SSIZE_MAX;
209
2
    else
210
2
      val = rlim.rlim_cur;
211
2
  }
212
6
  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
6
}