GTA San Andreas의 20년 된 버그, Windows 11 24H2에서 발견
(cookieplmonster.github.io)-
GTA San Andreas의 20년 된 버그가 Windows 11 24H2에서 드러남
- GTA San Andreas에서 Skimmer 비행기가 Windows 11 24H2에서 사라지는 버그가 보고됨
- SilentPatch를 사용해도 문제 해결이 되지 않음
- Windows 11 23H2에서는 문제가 발생하지 않음
- Windows 11 24H2로 업데이트한 사용자들 모두 이 버그를 경험함
버그 조사
무엇이 잘못되었는가?
- SilentPatch 설치 시 게임이 멈추는 문제 발생
-
CPlane::PreRender
에서 작은 루프에 갇히는 현상 발견 - 비행기의 블레이드 속도가 비정상적으로 높게 설정됨
- 블레이드 속도는 비행기의 고도에 비례하여 계산됨
왜 그리고 어떻게?
- Skimmer의
vehicles.ide
정의에서 필요한 매개변수가 누락됨 - Vice City에서는 Skimmer가 보트로 정의되어 있었음
- San Andreas에서 비행기로 변경되었으나 필요한 매개변수가 추가되지 않음
진정한 근본 원인
- Windows 11 24H2에서 스택 사용 방식이 변경되어 문제가 발생함
-
LeaveCriticalSection
이 스택 공간을 더 많이 사용하게 됨 - 이전에는
fgets
와LeaveCriticalSection
이 스택 공간을 덮지 않았으나, 이제는 덮게 됨
이 문제가 이제서야 발생한 이유
- Windows 11 24H2의 변경 사항으로 인해 스택 공간이 변경됨
- 게임이 초기화되지 않은 지역 변수를 사용하여 발생한 문제
- 다른 플랫폼에서는 이미 수정된 문제였음
게임에서 이 문제를 해결하고 싶다면?
- 다음 SilentPatch 핫픽스에 코드 수정이 포함될 예정
-
vehicles.ide
파일을 수동으로 수정하여 문제 해결 가능
마지막 말
- 이 버그는 특정 OS 릴리스와 직접적으로 연결된다는 점에서 흥미로움
- 스택 레이아웃의 변경이 호환성에 영향을 미칠 수 있음을 보여줌
- 입력 데이터를 검증하고 컴파일 경고를 무시하지 말아야 함
Hacker News 의견
- Raymond Chen의 작업을 기대할 만한 내용임. 이는 매우 높은 칭찬임
- 문제의 원인을 더 깊이 추적한 것이 기쁨
- 개인적인 의견으로, 계약의 일부가 아닌 것은 무작위로 처리해야 함. 예를 들어, 언어에서 맵의 반복 순서가 보장되지 않는다면, 언어가 이를 무작위로 처리해야 함. 그렇지 않으면 코드가 불안정해짐
- 컴파일 경고를 무시하지 말아야 함. 이 코드는 원래 코드에서 경고를 발생시켰을 가능성이 높음
- 여기서 예상할 수 있는 컴파일러 오류는 무엇일까? 아마도 scanf의 반환 값을 확인하지 않아 매개변수 수와 일치하는지 확인하지 않는 것일 수 있음. 그렇지 않으면 컴파일러가 알 수 없는 데이터 파일 오류처럼 보임
- 기술적인 글을 읽는 것을 항상 즐김. AI 시대에 이런 글이 얼마나 더 희귀해질지 궁금함
- Windows의 중요한 섹션 잠금/해제 구현에서 무엇이 변경되었는지 궁금함
- 접근 문제를 겪는 사람들을 위한 링크 제공
- 스택을 넘어 읽고 쓰는 것이 항상 너무 쉬웠음. 이는 단순히 실패해야 함
- 완화 조치가 존재함 - ASLR, NX 페이지, 스택 스매싱 보호 등. 그러나 스택을 넘어선 오래된 데이터를 읽는 것을 완전히 막지는 못함
- 하드웨어가 스택 영역의 사용되지 않은 부분을 읽거나 쓰지 못하게 한다면 어떨까 하는 생각 실험
- 스택의 시작 주소 A, 크기 S, 현재 깊이 D를 추적하는 방법 제안
- CPU에 스택이 주소 A에 크기 S로 존재한다고 알리는 명령 추가
- 스택에 N 바이트를 예약하는 점프 명령 추가
- 기존 반환 명령에 스택 인식 기능 추가
- 현재 깊이를 넘어선 스택 영역에 대한 읽기 또는 쓰기 실패
- 스택이 아래로 성장하는 아키텍처에서는 산술이 반대로 적용됨
- 단점으로는 하나의 호출 규약을 고정시키고, CPU 메모리 관리자가 많은 상태를 필요로 함
- 스택은 어디에나 존재함. 하드웨어 스택 인식은 새로운 완화 조치를 열어줌
- 이 아이디어가 일반적이지 않은 이유는 무엇일까? 시도된 적이 있을까?
- 이 모든 발견은 Windows 11 24H2의 문제가 아님을 증명함. 게임이 정의되지 않은 동작에 의존하고 있음
- 정의되지 않은 동작은 매우 교활하며, 이미 실수를 했음에도 불구하고 옳다고 믿게 만듦
- C 또는 C++ 프로그램이 정의되지 않은 동작을 유발하면, 프로그램 실행에서 무엇이든 발생할 수 있음
- 운이 좋으면 프로그램이 적절한 오류 메시지를 표시하거나 충돌하여 문제가 있음을 즉시 알 수 있음
- 운이 나쁘면 프로그램이 데이터를 조용히 망가뜨리고, 문제를 인식할 때쯤에는 원인이 과거 실행 기록에 묻혀 있음
- 매우 운이 나쁘면 프로그램이 원하는 대로 작동하다가 관련 없는 코드를 변경하거나 컴파일러 버전, 운영 체제 등을 변경하면 새로운 버그가 나타남
- 개발자로서 더 나은 방법을 찾기 위한 제안
- C 또는 C++에서 정의되지 않은 동작을 읽고 이해하며 암기하고, 이를 피해야 함
- 디버그 모드로 애플리케이션을 컴파일하고 릴리스 모드와 비교하여 차이가 있으면 심각한 문제가 있음
- 런타임에 정의되지 않은 동작을 잡기 위해 -fsanitize=undefined,address와 같은 도구 사용
- Java, C#, Python과 같은 관리 언어 사용 권장. 또는 Rust와 같은 안전한 저수준 언어 사용
- 디버거 사용 권장. 디버거를 사용하지 않는 것의 문제에 대한 이야기를 들음
- Silent에게 많은 사랑을 보냄. 10년 넘게 내가 좋아하는 게임을 개선해 줌