/*-------------------------------------------------------------------------
*
* stack_depth . c
* Functions for monitoring and limiting process stack depth
*
* Portions Copyright ( c ) 1996 - 2025 , PostgreSQL Global Development Group
* Portions Copyright ( c ) 1994 , Regents of the University of California
*
*
* IDENTIFICATION
* src / backend / utils / misc / stack_depth . c
*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
#include "postgres.h"
#include <limits.h>
#include <sys/resource.h>
#include "miscadmin.h"
#include "utils/guc_hooks.h"
/* GUC variable for maximum stack depth (measured in kilobytes) */
int max_stack_depth = 100 ;
/* max_stack_depth converted to bytes for speed of checking */
static ssize_t max_stack_depth_bytes = 100 * (ssize_t) 1024 ;
/*
* Stack base pointer - - initialized by set_stack_base ( ) , which
* should be called from main ( ) .
*/
static char *stack_base_ptr = NULL;
/*
* set_stack_base : set up reference point for stack depth checking
*
* Returns the old reference point , if any .
*/
pg_stack_base_t
set_stack_base(void )
{
#ifndef HAVE__BUILTIN_FRAME_ADDRESS
char stack_base;
#endif
pg_stack_base_t old;
old = stack_base_ptr;
/*
* Set up reference point for stack depth checking . On recent gcc we use
* _ _ builtin_frame_address ( ) to avoid a warning about storing a local
* variable ' s address in a long - lived variable .
*/
#ifdef HAVE__BUILTIN_FRAME_ADDRESS
stack_base_ptr = __builtin_frame_address(0 );
#else
stack_base_ptr = &stack_base;
#endif
return old;
}
/*
* restore_stack_base : restore reference point for stack depth checking
*
* This can be used after set_stack_base ( ) to restore the old value . This
* is currently only used in PL / Java . When PL / Java calls a backend function
* from different thread , the thread ' s stack is at a different location than
* the main thread ' s stack , so it sets the base pointer before the call , and
* restores it afterwards .
*/
void
restore_stack_base(pg_stack_base_t base)
{
stack_base_ptr = base;
}
/*
* check_stack_depth / stack_is_too_deep : check for excessively deep recursion
*
* This should be called someplace in any recursive routine that might possibly
* recurse deep enough to overflow the stack . Most Unixen treat stack
* overflow as an unrecoverable SIGSEGV , so we want to error out ourselves
* before hitting the hardware limit .
*
* check_stack_depth ( ) just throws an error summarily . stack_is_too_deep ( )
* can be used by code that wants to handle the error condition itself .
*/
void
check_stack_depth(void )
{
if (stack_is_too_deep())
{
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)));
}
}
bool
stack_is_too_deep(void )
{
char stack_top_loc;
ssize_t stack_depth;
/*
* Compute distance from reference point to my local variables
*/
stack_depth = (ssize_t) (stack_base_ptr - &stack_top_loc);
/*
* Take abs value , since stacks grow up on some machines , down on others
*/
if (stack_depth < 0 )
stack_depth = -stack_depth;
/*
* Trouble ?
*
* The test on stack_base_ptr prevents us from erroring out if called
* before that ' s been set . Logically it should be done first , but putting
* it last avoids wasting cycles during normal cases .
*/
if (stack_depth > max_stack_depth_bytes &&
stack_base_ptr != NULL)
return true ;
return false ;
}
/* GUC check hook for max_stack_depth */
bool
check_max_stack_depth(int *newval, void **extra, GucSource source)
{
ssize_t newval_bytes = *newval * (ssize_t) 1024 ;
ssize_t stack_rlimit = get_stack_depth_rlimit();
if (stack_rlimit > 0 && newval_bytes > stack_rlimit - STACK_DEPTH_SLOP)
{
GUC_check_errdetail("\" max_stack_depth\" must not exceed %zdkB." ,
(stack_rlimit - STACK_DEPTH_SLOP) / 1024 );
GUC_check_errhint("Increase the platform's stack depth limit via \" ulimit -s\" or local equivalent." );
return false ;
}
return true ;
}
/* GUC assign hook for max_stack_depth */
void
assign_max_stack_depth(int newval, void *extra)
{
ssize_t newval_bytes = newval * (ssize_t) 1024 ;
max_stack_depth_bytes = newval_bytes;
}
/*
* Obtain platform stack depth limit ( in bytes )
*
* Return - 1 if unknown
*
* Note : we choose to use ssize_t not size_t as the result type because
* callers compute values that could theoretically go negative ,
* such as " result - STACK_DEPTH_SLOP " .
*/
ssize_t
get_stack_depth_rlimit(void )
{
#if defined (HAVE_GETRLIMIT)
static ssize_t val = 0 ;
/* This won't change after process launch, so check just once */
if (val == 0 )
{
struct rlimit rlim;
if (getrlimit(RLIMIT_STACK, &rlim) < 0 )
val = -1 ;
else if (rlim.rlim_cur == RLIM_INFINITY)
val = SSIZE_MAX;
/* rlim_cur is probably of an unsigned type, so check for overflow */
else if (rlim.rlim_cur >= SSIZE_MAX)
val = SSIZE_MAX;
else
val = rlim.rlim_cur;
}
return val;
#else
/* On Windows we set the backend stack size in src/backend/Makefile */
return WIN32_STACK_RLIMIT;
#endif
}
Messung V0.5 in Prozent C=95 H=94 G=94
¤ Dauer der Verarbeitung: 0.15 Sekunden
(vorverarbeitet am 2026-08-08)
¤
*© Formatika GbR, Deutschland