Computer >> 컴퓨터 >  >> 프로그래밍 >> C++

힙 오버플로(Heap Overflow)와 스택 오버플로(Stack Overflow) 완벽 정리

힙 오버플로(Heap Overflow)

힙(Heap)은 프로세스 메모리 영역 중 하나로, 동적 변수(dynamic variables)를 저장하는 데 사용됩니다. C 언어에서는 malloc(), calloc(), realloc()과 같은 표준 라이브러리 함수를 통해 힙 영역에 메모리를 동적으로 할당할 수 있습니다.

힙 오버플로는 다음과 같은 상황에서 발생합니다.

1. 과도한 크기의 동적 메모리 할당

필요한 양보다 훨씬 큰 메모리를 한 번에 동적 할당하려고 하면 힙 영역이 가용 메모리를 초과하게 되어 오버플로가 발생합니다.

int main() {
    float *ptr = (float *)malloc(sizeof(float) * 1000000);
}

2. 메모리 해제 누수(Memory Leak)

메모리를 계속 할당만 하고 사용 후 free()로 해제하지 않으면, 사용 가능한 힙 공간이 점점 고갈되어 결국 힙 오버플로가 발생합니다.

int main() {
    for (int i = 0; i < 100000000000; i++) {
        int *p = (int *)malloc(sizeof(int));
        // free(p)를 호출하지 않아 메모리 누수 발생
    }
}

스택 오버플로(Stack Overflow)

스택(Stack)은 LIFO(Last In First Out, 후입선출) 구조의 메모리 영역으로, 함수 내부에서 사용되는 지역 변수(local variables), 함수 호출 시 전달되는 매개변수(parameter), 그리고 함수 종료 후 복귀할 주소(return address) 등을 저장합니다.

컴퓨터 메모리에서 스택의 크기는 제한적이기 때문에, 프로그램이 이 한계를 초과하는 메모리를 사용하면 스택 오버플로가 발생합니다.

스택 오버플로는 주로 다음과 같은 경우에 발생합니다.

1. 무한 재귀 호출

함수가 자기 자신을 무한히 재귀 호출하면, 호출될 때마다 새로운 지역 변수와 복귀 주소가 스택에 쌓입니다. 스택이 이를 감당하지 못하면 오버플로가 발생합니다.

void calculate(int a) {
    if (a == 0)
        return;
    a = 6;
    calculate(a); // 종료 조건에 도달하지 못해 무한 재귀 발생
}

int main() {
    int a = 5;
    calculate(a);
}

참고: 위 코드는 a가 6으로 고정되므로 종료 조건 a == 0에 도달할 수 없어 무한 재귀에 빠집니다.

2. 대형 지역 변수 또는 배열 선언

지역 변수를 대량으로 선언하거나, 차원이 매우 큰 배열이나 행렬(matrix)을 스택에 선언하면 스택 크기를 초과하여 오버플로가 발생합니다.

int main() {
    int A[20000][20000]; // 약 1.6GB에 달하는 거대한 배열이 스택에 할당됨
}

정리

힙 오버플로는 동적 메모리의 과도한 할당이나 해제 누수로 인해 발생하고, 스택 오버플로는 무한 재귀 호출이나 지나치게 큰 지역 변수 선언으로 인해 발생합니다. 두 오류 모두 프로그램 비정상 종료(crash)의 주요 원인이 되므로, 메모리 할당 후 반드시 해제하고, 재귀 함수에는 명확한 종료 조건을 두는 것이 중요합니다.