이 글에서는 C/C++ 프로그래밍에서 자주 마주치는 코어 덤프(Core Dump), 즉 세그먼테이션 오류(Segmentation Fault)가 발생하는 원인을 예제 코드와 함께 살펴봅니다.
세그먼테이션 오류는 프로그램이 허용되지 않은 메모리 영역에 접근할 때 발생합니다. 대표적인 원인으로는 다음과 같은 경우가 있습니다.
- 읽기 전용(read-only) 메모리 영역에 데이터를 쓰려고 시도할 때
- 손상되었거나 유효하지 않은 메모리 주소에 접근하려고 할 때
- 이미 해제(free)된 메모리를 다시 사용하려고 할 때
예제 1: 문자열 리터럴 수정
문자열 리터럴은 컴파일 타임에 읽기 전용 메모리 세그먼트(.rodata)에 저장됩니다. 따라서 포인터를 통해 리터럴의 내용을 변경하려 하면 세그먼테이션 오류가 발생합니다.
int main(){
char *str;
str = "GfG";
*(str+1) = 'n'; // 읽기 전용 메모리에 쓰기 시도 → 오류 발생
return 0;
}위 코드에서 str은 문자열 리터럴 "GfG"의 시작 주소를 가리킵니다. *(str+1) = 'n'은 두 번째 문자 'f'를 'n'으로 바꾸려는 시도인데, 이 영역은 수정이 불가능한 읽기 전용 공간이므로 프로그램이 비정상 종료됩니다.
예제 2: 배열 인덱스 범위 초과 접근
C/C++에서는 배열 경계 검사를 컴파일러가 수행하지 않습니다. 따라서 선언된 크기를 벗어난 인덱스에 접근해도 컴파일은 성공하지만, 실행 시 정의되지 않은 동작(undefined behavior) 또는 세그먼테이션 오류로 이어질 수 있습니다.
#include <iostream>
using namespace std;
int main(){
int arr[2];
arr[3] = 10; // 크기 2짜리 배열의 범위를 벗어난 접근
return 0;
}크기가 2인 배열에 인덱스 3으로 접근하는 것은 허용된 메모리 범위를 넘어서는 행위입니다. 운영체제나 메모리 배치에 따라 즉시 오류가 발생하지 않을 수도 있지만, 잠재적으로 심각한 버그의 원인이 됩니다.
예제 3: 해제된 메모리 접근 (댕글링 포인터)
free()로 이미 해제한 메모리에 다시 접근하는 것도 대표적인 오류 원인입니다. 이처럼 해제된 메모리를 여전히 가리키는 포인터를 댕글링 포인터(Dangling Pointer)라고 부릅니다.
#include <stdio.h>
#include <stdlib.h>
int main(void){
int* p = malloc(8);
*p = 100;
free(p); // 메모리 해제
*p = 110; // 해제된 메모리에 쓰기 시도 → 오류 발생
return 0;
}참고로 위 예제에서 사용된 <alloc.h>는 구식(Turbo C 계열) 헤더이며, 표준 환경에서는 <stdlib.h>를 사용해야 합니다.
실행 결과
위와 같은 코드를 실행하면 일반적으로 다음과 같은 결과가 출력되며 프로그램이 비정상적으로 종료됩니다.
Abnormal termination of program
정리 및 예방 팁
세그먼테이션 오류를 예방하려면 다음 사항을 항상 유의해야 합니다.
- 문자열 리터럴은
char*가 아닌const char*로 받아 실수로 수정하지 않도록 합니다. - 배열 접근 시 인덱스가 유효 범위 내에 있는지 반드시 확인합니다.
free()호출 후에는 포인터에NULL을 대입하여 댕글링 포인터를 방지합니다.
디버깅 도구인 GDB나 Valgrind를 활용하면 코어 덤프 파일을 분석해 오류가 발생한 정확한 위치를 추적할 수 있으므로, 적극적으로 활용하는 것이 좋습니다.