정의되지 않은 동작(UB)이 괜찮다고 생각하는 사람들에게

2 hours ago 3

정의되지 않은 동작(UB) 의 결과를 예측할 수 있고 최악에도 세그멘테이션 폴트만 발생한다는 생각은 코드 예제의 실제 컴파일 결과와 어긋남 GCC 16.2의 -O1 예제에서는 std::unreachable() 뒤에 함수 복귀 명령이 없어, 호출하지 않은 explode()의 코드까지 실행됨 널 포인터 역참조 예제에서 GCC는 코드에 적힌 99 대신 주소 0에 0을 쓰고 ud2로 중단하는 코드를 생성하지만, Clang은 뒤에 배치된 함수 코드로 실행이 이어짐 널 포인터에 ptr += 10을 적용한 예제에서는 주소 40에 99를 쓰는 코드가 생성되며, 예상한 결과와 일치하더라도 UB라는 점은 달라지지 않음 컴파일러는 UB를 탐지할 의무가 없으며, 같은 위치에서 유발한 UB라도 뒤따르는 코드 실행, 다른 값 저장과 강제 종료, 겉보기대로 동작하는 결과가 모두 가능함 호출하지 않은 함수 실행과 널 포인터 쓰기 앞선 C의 정의되지 않은 동작에 관한 글에 일부 독자는 동작을 알 수 있으며 최악에도 세그멘테이션 폴트만 발생한다고 반응했지만, 다음 예제들은 그렇지 않은 결과를 보임 예제는 모터와 기어를 제어하는 메모리 매핑 장치를 가정하고, volatile int device_command 를 0으로 초기화함 serve_hot_chocolate()는 device_command = 42를 실행한 뒤, 해당 지점에서 UB를 유발하는 std::unreachable()을 호출함 그다음 정의된 explode()는 device_command = 3을 실행함 GCC 16.2, -O1 의 어셈블리 출력에는 42를 저장하는 명령과 explode()의 3을 저장하는 명령 사이에 복귀 명령이 없음 따라서 explode()를 호출하지 않았어도 그 코드까지 실행한 뒤 ret에 도달함 std::unreachable()을 int* ptr = nullptr; *ptr = 99;로 바꾼 GCC 결과는 주소 0에 0을 쓰는 명령과 ud2를 생성함 원래 코드의 99는 생성된 프로그램에 나타나지 않으며, ud2는 잘못된 명령어로 프로그램을 중단시킴 널 포인터 쓰기를 남긴 이유가 디버거 오류 메시지 개선을 위한 것인지는 추측에 불과함 같은 널 포인터 역참조 예제의 Clang 결과는 42를 저장한 뒤 3을 저장하는 코드로 이어짐 이 경우에도 호출하지 않은 explode()의 코드가 실행됨 널 포인터 산술과 UB가 허용하는 결과 널 포인터에 ptr += 10 을 추가...

Read Entire Article




피플앤툴즈 네트워크
🛍 샵