본문으로 건너뛰기
Previous
Next
C++ Stack Overflow: Recursion, Large Locals, and How to Fix

C++ Stack Overflow: Recursion, Large Locals, and How to Fix

C++ Stack Overflow: Recursion, Large Locals, and How to Fix

이 글의 핵심

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)](/en/blog/cpp-error-02-segmentation-fault/ and [segfault (checklist)](/en/blog/cpp-error-27-segmentation-fault/.

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.

// 실행 예제
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.

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

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)

# 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

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):

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

Tail form (call is last):

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.


자주 묻는 질문 (FAQ)

Q. 이 내용을 실무에서 언제 쓰나요?

A. Why stack overflow happens: infinite recursion, huge stack arrays, deep recursion. ulimit, /STACK, heap allocation, iter… 실무에서는 위 본문의 예제와 선택 가이드를 참고해 적용하면 됩니다.

Q. 선행으로 읽으면 좋은 글은?

A. 각 글 하단의 이전 글 또는 관련 글 링크를 따라가면 순서대로 배울 수 있습니다. C++ 시리즈 목차에서 전체 흐름을 확인할 수 있습니다.

Q. 더 깊이 공부하려면?

A. cppreference와 해당 라이브러리 공식 문서를 참고하세요. 글 말미의 참고 자료 링크도 활용하면 좋습니다.


같이 보면 좋은 글 (내부 링크)

이 주제와 연결되는 다른 글입니다.

  • [C++ Segmentation Fault: Five Causes and Debugging with GDB,](/en/blog/cpp-error-02-segmentation-fault/
  • [C++ Segmentation Fault: Causes, Debugging, and Prevention](/en/blog/cpp-error-27-segmentation-fault/
  • C++ 스택 vs 힙 | 재귀에서 프로그램이 죽는 이유와 스택 오버플로우 사례

이 글에서 다루는 키워드 (관련 검색어)

C++, Stack overflow, Recursion, Crash, Memory, Debugging 등으로 검색하시면 이 글이 도움이 됩니다.