[2026] C++ Stack Overflow: Recursion, Large Locals, and How to Fix Crashes

[2026] C++ Stack Overflow: Recursion, Large Locals, and How to Fix Crashes

이 글의 핵심

Why stack overflow happens: infinite recursion, huge stack arrays, deep recursion. ulimit, /STACK, heap allocation, iterative algorithms, and tail-call basics.

Stack exhaustion often shows up as a segfault—compare segfault (deep dive) and segfault (checklist).

Introduction: “My recursive function crashes”

“Segfault but I’m not using pointers”

Stack overflow happens when stack memory is exhausted. Common causes: infinite recursion, very large locals, and very deep recursion. 아래 코드는 cpp를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

// 실행 예제
void foo() {
    foo();
}
int main() {
    foo();
}
// Linux/macOS: SIGSEGV; Windows: stack overflow

This article covers:

  • Four major causes
  • Recursion depth limits
  • Adjusting stack size (last resort)
  • Moving work to the heap
  • Tail recursion and iterative forms

Table of contents

  1. What is stack overflow?
  2. Four major causes
  3. Limiting recursion depth
  4. Stack size settings
  5. Heap allocation
  6. Tail recursion
  7. Summary

1. What is stack overflow?

Stack memory

Each function call creates a stack frame for locals and return addresses. Typical default stack limits (order of magnitude):

  • Linux: ~8 MB
  • Windows: ~1 MB (varies)
  • macOS: ~8 MB When recursion or locals exceed the limit, the program crashes.

2. Four major causes

1. Infinite recursion

int factorial(int n) {
    return n * factorial(n - 1); // missing base case
}

Fix: Base case. 다음은 간단한 cpp 코드 예제입니다. 조건문으로 분기 처리를 수행합니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

int factorial(int n) {
    if (n <= 1) return 1;
    return n * factorial(n - 1);
}

2. Large local arrays

void process() {
    int bigArray[1000000]; // ~4 MB on stack—may overflow
}

Fix:

void process() {
    std::vector<int> bigArray(1000000);
}

3. Very deep naive recursion (e.g. Fibonacci)

Fix: Iteration or memoization.

4. Deep call chains with large frames

Move big temporaries to the heap or reuse buffers.

3. Limiting recursion depth

아래 코드는 cpp를 사용한 구현 예제입니다. 에러 처리를 통해 안정성을 확보합니다, 조건문으로 분기 처리를 수행합니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

int factorial(int n, int depth = 0) {
    const int MAX_DEPTH = 1000;
    if (depth > MAX_DEPTH) {
        throw std::runtime_error("Recursion too deep");
    }
    if (n <= 1) return 1;
    return n * factorial(n - 1, depth + 1);
}

Prefer loops when depth can be large.

4. Stack size

Linux: ulimit

ulimit -s       # size in KB
ulimit -s 16384 # e.g. 16 MB
ulimit -s unlimited  # use with care

Windows linker

Linker → System → Stack Reserve (Visual Studio), or:

/STACK:16777216

CMake (examples)

아래 코드는 cmake를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

# Linux ELF (toolchain-specific)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-z,stack-size=16777216")
# MSVC
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /STACK:16777216")

5. Heap instead of stack

아래 코드는 cpp를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

void process() {
    std::vector<int> big(1000000);
    // or
    auto big = std::make_unique<int[]>(1000000);
}

Tree traversal: explicit std::stack

Replace deep recursion with an iterative walk using a container on the heap when depth is unbounded (e.g. deeply nested JSON).

6. Tail recursion

Non-tail (work after the call): 다음은 간단한 cpp 코드 예제입니다. 조건문으로 분기 처리를 수행합니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

int factorial(int n) {
    if (n <= 1) return 1;
    return n * factorial(n - 1);
}

Tail form (call is last): 다음은 간단한 cpp 코드 예제입니다. 조건문으로 분기 처리를 수행합니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

int factorialTail(int n, int acc = 1) {
    if (n <= 1) return acc;
    return factorialTail(n - 1, n * acc);
}

Inspect assembly at -O2 to see if the compiler optimized to a loop.

Case studies (sketches)

JSON parsing

Deep nesting can blow the stack with naive recursion; use an explicit stack or iteration.

Directory walk

Replace deep filesystem recursion with a directory stack/std::stack of paths.

Summary

Checklist

  • Base case for every recursive function?
  • Avoid multi-megabyte stack arrays?
  • Recursion depth bounded or converted to iteration?
  • Nested calls not multiplied by huge locals?

Mitigation priority

  1. Correct base cases
  2. Heap for large buffers
  3. Iterative algorithms / explicit stacks
  4. Tail recursion where applicable
  5. Increase stack only as a temporary measure

Rules

  1. Large arrays → vector / unique_ptr
  2. Guard recursion depth when needed
  3. Deep or unbounded recursion → iteration
  4. Consider tail-call patterns with optimizations enabled


Keywords

stack overflow, infinite recursion, recursion depth, large array, stack size, ulimit

Practical tips

Debugging

  • Add a depth counter during investigation.
  • Use backtrace to see repeated frames.
  • Valgrind/ulimit experiments can clarify stack usage.

Performance

  • Tail recursion may optimize at -O2+.
  • Loops are often faster than heavy recursion.
  • Memoization reduces call count.

Reviews

  • Verify termination for recursive functions.
  • Flag large stack allocations.
  • Question unbounded recursion depth.

Closing

Stack overflow is preventable: control recursion, avoid huge stack frames, and use the heap for large data. Increasing stack size is a last resort; fix the algorithm and memory placement first. Next: Pair this with deeper material on recursion vs iteration and tail-call optimization in your favorite C++ resource.

... 996 lines not shown ... Token usage: 63706/1000000; 936294 remaining Start-Sleep -Seconds 3