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

C++에서 세그먼테이션 오류는 정의되지 않은 동작일까?

정의되지 않은 동작(Undefined Behavior)이란?

정의되지 않은 동작(Undefined Behavior, UB)은 컴파일러나 운영체제처럼 프로그램을 구현하는 쪽과 컴퓨터 자신에게 결과에 대해 신경 쓰지 않고 자유롭게 동작할 수 있는 권한을 부여하는 개념입니다. 즉, C++ 표준이 특정 상황에서의 결과를 규정하지 않기 때문에, 그 상황에서 프로그램이 어떻게 동작하든 표준 차원에서는 잘못된 것으로 간주하지 않습니다.

세그먼테이션 오류는 왜 '항상' 발생하지 않을까?

흥미로운 점은 세그먼테이션 오류(segmentation fault)가 발생하는 상황이 본질적으로 일시적(transient)이라는 사실입니다. 배열의 범위를 벗어난 접근과 같은 코드가 항상 프로그램을 크래시시키는 것이 아니라, 때로는 아무 문제 없이 정상적으로 실행되거나, 적어도 정상적으로 동작하는 것처럼 보일 수 있습니다.

다음 코드 예제를 살펴보겠습니다.

#include <iostream>
int main() {
    int arr[2];
    arr[0] = 0;
    arr[1] = 1;
    arr[2] = 2; // 정의되지 않은 동작
    arr[3] = 3; // 정의되지 않은 동작
}

결과는 구현 환경에 따라 달라진다

위 코드는 정상적으로 실행될 수도 있고, 세그먼테이션 오류로 비정상 종료될 수도 있습니다. C++ 표준이 이러한 상황의 결과를 정의하지 않기 때문에, 실제 동작은 컴파일러 종류, 최적화 옵션, 운영체제의 메모리 관리 방식 등 구현 환경에 따라 달라집니다.

예를 들어, arr[2]arr[3]이 우연히 스택 메모리 내의 사용되지 않는 여유 공간에 해당한다면 프로그램은 겉보기에 멀쩡하게 실행될 수 있습니다. 하지만 그 영역이 함수의 반환 주소 같은 중요한 데이터를 덮어쓴다면, 프로그램은 크래시하거나 완전히 예측 불가능한 방식으로 동작하게 됩니다. 결국 같은 코드라도 실행 환경과 시점에 따라 전혀 다른 결과를 낳을 수 있다는 것이 정의되지 않은 동작의 본질입니다.

참고 자료

정의되지 않은 동작에 대해 더 깊이 알고 싶다면 다음 글을 참고해 보세요.
What Every C Programmer Should Know About Undefined Behavior (LLVM 블로그)