TECH 으로 돌아가기
TECH HACKER NEWS 오늘 7분 읽기 20 READS

44년 만에 드러난 인포컴 '인피델'의 와일드 포인터 버그

고전 텍스트 어드벤처 개발사 인포컴의 게임을 메모리 수준 디버거로 뜯어보던 개발자 앤드루 플로킨(zarf)이, 1983년작 '인피델(Infidel)'에서 지금껏 본 것 중 가장 심각한 버그를 발견했다. 플레이에는 거의 영향을 주지 않아 흔히 '사소하다'고 치부될 만한 종류지만, 실체는 의도치 않게 메모리를 덮어쓰는 와일드 포인터 버그다. C 프로그래머 출신인 그는 메모리 손상을 가장 큰 죄악으로 여긴다고 말한다. 게다가 이것은 게임 코드 자체의 실수가 아니라 ZIL 컴파일러의 버그였다. 분석 대상은 매킨토시용 업데이트판(릴리스 22, 시리얼 840522)이며, 원본(830916)도 주소만 다를 뿐 동일한 문제를 안고 있다.

끝없는 사막이라는 눈속임

인피델의 무대는 이집트 사막이다. 캠프를 기준으로 동쪽 3x3 격자만 정상적인 지도이고, 그 바깥으로 벗어나면 플레이어는 '길을 잃은' 상태가 된다. 이때 게임은 ENDLESS-DESERT라는 단 하나의 방으로 모든 미지의 사막 칸을 표현한다. 인챈터에서 처음 쓰인 기법으로, 플레이어가 움직여도 캠프나 지도 구역으로 돌아오지 않는 한 계속 같은 방으로 되돌아오게 만든다. 대신 위도·경도 좌표를 추적해 둔다.

이 눈속임을 그럴듯하게 유지하려면 물건을 옮겨 두는 처리가 필요하다. 사막에 물건을 떨어뜨리고 이동하면, 그 아이템은 무대 뒤로 치워지고 좌표와 함께 DESERT-TABLE이라는 배열에 기록된다. 나중에 같은 좌표로 돌아오면 다시 꺼내어 보여 주는 식이다. 다만 떨어뜨린 물건은 3분의 1 확률로 모래에 묻혀 영영 사라지는데, 이 무작위성이 나중에 버그를 더 찾기 어렵게 만든 요소이기도 하다.

상수가 아닌 전역 변수

문제는 물건을 치우는 DESERT-TO-TABLE 루틴에 있다. 이 루틴은 기록할 배열 주소 TBL을 선택적 인자로 받고, 기본값으로 DESERT-TABLE(주소 11129)을 쓰도록 되어 있다. 플로킨은 디버거의 상태 탭에 이 배열 내용을 표시하려다 배열이 끝내 비어 있다는 사실을 발견했다. 물건은 분명 사라졌다 나타나는데, 어디로도 저장되지 않고 있었던 것이다.

디스어셈블해 보니 TBL을 11129로 초기화하는 코드가 없었다. Z-머신 함수는 지역 변수를 상수로 초기화하는 슬롯을 두는데, ZIL은 DESERT-TABLE을 상수로 간주해 그 '값'이 아니라 전역 변수 번호인 30(16진수 1e)을 TBL에 넣어 버렸다. 전역 변수는 16번부터 매겨지며 DESERT-TABLE은 15번째라 번호가 30이다. 값은 게임 내내 11129로 고정되지만 변수인 이상 컴파일 시점의 상수가 아니다. 즉 기본값이 전역 변수라는 경우를 아무도 상정하지 않은 탓에, 컴파일러는 오류를 내지도, F처럼 별도 STORE 명령을 생성하지도 않고 그냥 30을 썼다.

결과적으로 루틴은 11129가 아니라 주소 30번지부터 메모리를 덮어쓴다. 되돌리는 TABLE-TO-DESERT 루틴도 똑같이 30번지에서 읽어 오기 때문에 겉보기 동작은 멀쩡하다. 그러나 그사이 메모리는 짓밟히고 있었다.

운 좋게 숨어 있던 재앙

피해가 눈에 띄지 않은 것은 순전히 운이었다. 메모리 앞부분 64바이트는 헤더인데, Z-머신 버전 3에서 실제로 의미를 갖는 영역은 0~29번지뿐이고 30~63번지는 쓰이지 않는다. 만약 DESERT-TABLE이 세 번째 전역(번호 18)이었다면 게임의 시리얼 번호가 손상돼 훨씬 일찍 들통났을 것이다. 64번지부터는 자주 쓰는 단어 96개를 묶어 둔 축약(abbreviations) 데이터가 시작된다. 플로킨은 사막에 아홉 개의 물건을 떨어뜨리면 마지막 하나가 이 축약 테이블 앞부분을 덮어쓸 것이라 예측했고, 모래에 묻히는 확률을 뚫고 재현에 성공했다. 그러자 환각 묘사 속 'the'가 'You'로 바뀌어 출력됐고, 다른 시도에서는 인터프리터가 무한 루프에 빠져 크래시가 나기도 했다.

이 버그는 그대로 출시됐고 인포컴의 플레이테스터를 포함해 아무도 알아채지 못했다. 1984년 개정판도 손대지 않았다. 사막은 피라미드를 찾기 전 시간을 때우는 공간일 뿐 아무것도 없는 곳이라, 애초에 여덟 개가 넘는 물건을 거기 버릴 이유가 없었기 때문이다. 세심하기로 유명한 인포컴이지만 이 구역만큼은 집중적으로 테스트되지 않았다는 방증이다. 플로킨은 모래 구덩이를 다루는 PROP-TO-TBL·TBL-TO-PROP 루틴에도 PROP-TBL(주소 11329, 전역 22번)을 대상으로 한 같은 버그가 있으나, ENDLESS-DESERT에서는 땅을 팔 수 없어 이 루틴 자체가 쓰이지 않는 사장된 흔적으로 보인다고 덧붙였다.

실무자가 가져갈 교훈

수정은 간단하다. TBL의 인자 기본값을 없애고 루틴 첫머리에서 명시적으로 DESERT-TABLE을 대입하거나, 호출부에서 두 번째 인자로 넘기면 된다. 다만 이 사례가 남기는 함의는 작지 않다. 컴파일러가 '상수'와 '값이 변하지 않는 변수'를 혼동했고, 그 결과가 조용한 메모리 손상으로 이어졌다는 점이다. 겉으로 대칭이 맞아떨어지는 읽기·쓰기 경로 때문에 오동작이 수십 년간 가려졌고, 거의 가 보지 않는 기능 구석은 테스트 커버리지에서 통째로 빠져 있었다. 정적 분석이 닿지 않는 가정, 사용 빈도가 낮은 경로의 잠복 결함, 그리고 적절한 관측 도구 하나가 어떻게 오래된 버그를 드러내는지를 동시에 보여 주는 사례다.

SOURCE · HACKER NEWS
원문 전체 보기 → https://blog.zarfhome.com/2026/10/infidel-goes-wild
SHARE
NEXT · CHOOSE

변화를 읽었다면,
내가 만들 수익 구조를 고릅니다.

정보를 더 모으는 데서 멈추지 않고, 광고·외주·판매·중개·구독 중 내 상황에 맞는 출발점을 정해보세요.

21가지 수익 구조 살펴보기 →
처리 중...