RLIMIT_STACK Stack Size Limit: SIGSEGV, Alternate Signal Stack, argv/env Space

 

36.3 — RLIMIT_STACK
Stack Size Limit: SIGSEGV, Alternate Signal Stack, argv/env Space | EmbeddedPathashala

What is RLIMIT_STACK?

RLIMIT_STACK sets the maximum size of the process’s main stack in bytes. It is in SUSv3 and widely available. When the stack grows beyond the soft limit, the kernel sends a SIGSEGV signal to the process.

The most common cause of RLIMIT_STACK being hit in practice is deep recursion (stack overflow) or declaring very large local arrays inside functions.

How SIGSEGV Delivery Works on Stack Overflow

There is a catch-22 when RLIMIT_STACK is exceeded: the kernel delivers SIGSEGV to the process, but to handle that signal the process needs to execute a signal handler — and that handler needs stack space. Since the stack is already full, there is nowhere to run the handler.

The solution is an alternate signal stack. You allocate a separate region of memory, register it with sigaltstack(), and install the SIGSEGV handler with the SA_ONSTACK flag. Then even when the main stack overflows, the handler can run on the alternate stack.

/* Setting up an alternate signal stack for stack overflow handling */
#include <signal.h>
#include <stdlib.h>

#define ALT_STACK_SIZE (SIGSTKSZ * 4)  /* typically 32 KB */

void setup_alt_stack(void)
{
    static char alt_stack_buf[ALT_STACK_SIZE];
    stack_t ss;
    struct sigaction sa;

    /* Register the alternate stack */
    ss.ss_sp    = alt_stack_buf;
    ss.ss_size  = ALT_STACK_SIZE;
    ss.ss_flags = 0;
    sigaltstack(&ss, NULL);

    /* Install SIGSEGV handler that runs on the alternate stack */
    sa.sa_handler = sigsegv_handler;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = SA_ONSTACK;  /* Run on alternate stack */
    sigaction(SIGSEGV, &sa, NULL);
}

argv and env Space — The Linux 2.6.23 Change

Since Linux 2.6.23: RLIMIT_STACK also determines the maximum total space available for the process’s command-line arguments and environment variables. Attempting to exec() a program with arguments or environment that would exceed this space causes the exec() to fail with E2BIG. See the execve(2) man page for exact details. This was a change from older kernels where these had a fixed 128 KB limit.

Code Example — Stack Size Limit and Stack Overflow

#include 
#include 
#include 
#include <sys/resource.h>

/* Alternate stack storage */
static char alt_stk[65536];

static void sigsegv_handler(int sig)
{
    /* Runs on alternate stack even if main stack overflowed */
    printf("SIGSEGV caught: stack overflow detected!\n");
    _exit(1);   /* Must use _exit() not exit() in signal handler */
}

/* Recursive function that will overflow the stack */
static void recurse(int depth)
{
    char local_buf[4096];  /* Force stack growth each call */
    local_buf[0] = depth;  /* Touch to prevent optimization */
    printf("  depth %d\n", depth);
    recurse(depth + 1);    /* Infinite recursion */
}

int main(void)
{
    struct rlimit rl;
    stack_t ss;
    struct sigaction sa;

    /* Set a small stack limit: 128 KB */
    rl.rlim_cur = 128 * 1024;
    rl.rlim_max = 128 * 1024;
    setrlimit(RLIMIT_STACK, &rl);
    printf("Stack limit set to 128 KB\n");

    /* Set up alternate signal stack */
    ss.ss_sp    = alt_stk;
    ss.ss_size  = sizeof(alt_stk);
    ss.ss_flags = 0;
    sigaltstack(&ss, NULL);

    /* Install SIGSEGV handler on alternate stack */
    sa.sa_handler = sigsegv_handler;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = SA_ONSTACK;
    sigaction(SIGSEGV, &sa, NULL);

    printf("Starting deep recursion...\n");
    recurse(0);  /* Will overflow and trigger SIGSEGV */

    return 0;
}
/* Compile: gcc -O0 -o stack_demo stack_demo.c
   Expected: recurse() runs until stack is full, then SIGSEGV handler fires */

Interview Questions

Q1. What signal is sent when a process exceeds RLIMIT_STACK?

SIGSEGV (Segmentation fault). The default action is to terminate the process with a core dump. The process can install a handler for SIGSEGV, but must use an alternate signal stack (sigaltstack() + SA_ONSTACK) because the main stack is already full and cannot be used by the handler.

Q2. Why must a SIGSEGV handler for stack overflow use an alternate signal stack?

When the stack overflows, it has no space left. A signal handler normally runs on the process’s main stack. If the main stack is full and the handler tries to use it, it causes another SIGSEGV, which cannot be caught (leading to immediate process termination). The alternate stack (registered via sigaltstack()) provides a separate memory region where the handler can execute safely.

Q3. What additional effect does RLIMIT_STACK have since Linux 2.6.23?

Since 2.6.23, RLIMIT_STACK also limits the space for the process’s command-line arguments (argv) and environment variables (envp). exec() fails with E2BIG if the total size of argv + envp would exceed this limit. Before 2.6.23, there was a fixed 128 KB limit for argv+envp regardless of RLIMIT_STACK.

Q4. What is a common cause of hitting RLIMIT_STACK in practice?

Deep or infinite recursion (stack overflow), declaring large local arrays inside functions (each call uses significant stack space), or calling functions with many or large parameters. In embedded systems, stack overflow is one of the most common causes of mysterious SIGSEGV crashes.

Leave a Reply

Your email address will not be published. Required fields are marked *