본문으로 건너뛰기
피드

아폴로 11호 유도 컴퓨터에서 57년간 숨어있던 미발견 버그를 찾아냄

general 약 9분
vote
0
댓글
북마크

JUXT팀이 오픈소스 행동 명세 언어 Allium과 Claude를 사용해 아폴로 유도 컴퓨터(AGC)의 자이로 제어 코드에서 57년간 발견되지 않았던 리소스 락 누수 버그를 찾아냈다. 에러 경로에서 LGYRO 락을 해제하지 않는 결함으로, 누락된 코드는 단 4바이트. 기존 코드 리뷰와 에뮬레이션으로는 잡을 수 없었던 걸 리소스 생명주기 모델링으로 발견한 사례다.

  • 1

    AGC 자이로 제어 코드의 BADEND 에러 경로에서 LGYRO 락 미해제 — 누락 코드 4바이트

  • 2

    케이징 후 재시작 없이 자이로 재사용 시 모든 자이로 조작이 영구 블로킹

  • 3

    Allium + Claude로 13만 줄 어셈블리를 1만 2,500줄 행동 명세로 증류하여 발견

  • 4

    AGC의 방어적 코딩(재시작 시 메모리 초기화)이 오히려 버그를 57년간 은폐

  • 5

    현대 코드에서도 CWE-772(리소스 미해제) 패턴은 여전히 흔한 문제

  • 역사상 가장 많이 분석된 코드베이스 중 하나인 아폴로 유도 컴퓨터(AGC) 코드에서 57년간 아무도 발견하지 못한 버그를 찾아냄
    • 자이로 제어 코드의 에러 경로에서 리소스 락(LGYRO)을 해제하지 않는 결함
    • 누락된 코드는 딱 2줄, 4바이트 — CAF ZERO / TS LGYRO
    • 수천 명의 개발자가 읽었고, 에뮬레이터로 명령어 하나하나 검증했지만 못 찾은 걸 행동 명세(behavioral specification) 접근법으로 잡아냄

버그의 정체

  • AGC는 자이로스코프를 토크할 때 LGYRO라는 공유 락을 획득함 — 두 루틴이 동시에 자이로 하드웨어를 건드리지 못하게 하는 장치
    • 정상 완료 시 STRTGYR2 경로로 나가면서 락 해제 → 문제없음
    • 하지만 케이징(caging) 중에 토크가 진행되면 BADEND 경로로 빠지는데, 여기서 락을 안 풀어줌
  • BADEND는 범용 종료 루틴이라 일반 리소스(MODECADR 등)는 제대로 정리함
    • 문제는 LGYRO가 자이로 토크 코드에서만 쓰는 특수 락이라 BADEND가 존재 자체를 모른다는 것
  • 한번 LGYRO가 걸리면? 이후 모든 자이로 조작이 영원히 블로킹됨
    • 정밀 정렬, 드리프트 보정, 수동 자이로 토크 전부 먹통
    • 알람도 안 뜨고, 프로그램 라이트도 안 들어옴 — 그냥 명령을 받고 아무것도 안 함

중요

> 하드 리셋하면 해결되지만, 이 버그의 증상은 하드웨어 고장처럼 보임. 명령은 받아들이는데 동작만 안 하니까 소프트웨어 문제를 의심할 단서가 전혀 없음

마이클 콜린스가 혼자 달 뒤를 돌 때

  • 1969년 7월 21일, 암스트롱과 올드린이 달 표면에 있는 동안 콜린스는 사령선 컬럼비아호에서 혼자 달 궤도를 돌고 있었음
    • 2시간마다 달 뒤로 사라지면서 지구와 통신 두절
    • 매 패스마다 Program 52(별 관측 정렬)를 실행해서 유도 플랫폼 방향을 유지해야 했음 — 이게 틀어지면 귀환 엔진 점화 방향이 빗나감
  • 만약 콜린스가 좁은 조종석에서 움직이다 팔꿈치로 케이지 스위치를 건드렸다면?
    • P52 실패 → 케이지 해제 후 재정렬 시도 → 두 번째 P52가 영원히 멈춤
    • 첫 번째 실패는 정상적인 상황이라 훈련받은 대로 대응하지만, 두 번째 행(hang)은 원인을 알 수 없음
    • "지난 6개월간 나의 비밀스런 공포는 그들을 달에 두고 혼자 지구로 돌아오는 것이었다" — 콜린스 자서전 Carrying the Fire

어떻게 찾았나

  • JUXT팀이 오픈소스 행동 명세 언어 AlliumClaude를 사용해서 발견
    • AGC 어셈블리 13만 줄을 1만 2,500줄의 행동 명세로 증류(distill)
    • 명세는 코드 자체에서 파생 — 공유 리소스의 생명주기를 모델링함 (획득 → 보유 → 해제)
  • 핵심 접근 차이: 기존 검증은 "코드가 작성된 대로 동작하는가"를 확인, 행동 명세는 "코드가 무엇을 위한 것인가"를 질문함
    • gyros_busy = true가 되면, 모든 경로에서 반드시 false로 돌려야 한다는 의무를 명시적으로 선언
    • Claude가 gyros_busy = true 이후의 모든 경로를 추적 → 정상 경로는 해제하지만 BADEND 경로는 해제 안 하는 걸 발견
sequenceDiagram
    participant 토크코드 as 토크 코드
    participant LGYRO as LGYRO 락
    participant 자이로 as 자이로 하드웨어
    participant 케이지 as 케이지 이벤트

    토크코드->>LGYRO: 락 획득 (gyros_busy = true)
    토크코드->>자이로: 축별 토크 펄스 전송
    케이지-->>토크코드: 케이지 감지 (CAGETEST)
    토크코드->>토크코드: BADEND로 분기
    Note over LGYRO: ⚠️ 락 해제 누락!
    토크코드->>토크코드: 다음 P52 시도
    토크코드->>LGYRO: 락 획득 시도 → 영원히 대기

왜 57년간 안 잡혔나

  • AGC 코드가 워낙 방어적으로 작성돼서 오히려 버그가 숨음
    • 재시작 로직이 전체 소거 메모리를 초기화하면서 LGYRO도 부수효과로 클리어함
    • 테스트 중 우연히 재시작이 발생하면 시스템이 매끄럽게 복구돼서 문제가 드러나지 않음
  • 기존 검증 방식의 한계가 명확히 드러남
    • 코드 리뷰: BADEND만 보면 모든 리소스를 올바르게 정리하는 것처럼 보임
    • 에뮬레이션: 특정 시나리오를 테스트하는 거라 "케이지 후 재시작 없이 다시 토크"라는 경로를 아무도 안 돌려봄
    • 형식 검증/정적 분석: AGC 비행 코드 대상으로 발표된 논문이 없음

현대 코드에 주는 교훈

  • 마가렛 해밀턴 팀이 '소프트웨어 엔지니어링'이라는 용어 자체를 만들었고, 우선순위 스케줄링/비동기 멀티태스킹/재시작 보호 같은 개념을 선도함
    • 아폴로 11호 착륙 중 1202 알람이 발생했을 때 저우선순위 태스크를 버리는 방식으로 대응 — 현대 시스템 대부분이 이만큼 우아하게 과부하를 처리하지 못함
  • 현대 언어들이 구조적으로 락 누수를 막으려 시도하지만 여전히 한계가 있음
    • Go의 defer, Java의 try-with-resources, Python의 with, Rust의 소유권 시스템
    • 하지만 DB 커넥션, 분산 락, 셸 스크립트의 파일 핸들, 인프라 해체 순서 등은 여전히 프로그래머 책임
    • MITRE는 이 패턴을 CWE-772("유효 수명 이후 리소스 미해제")로 분류하고 악용 가능성을 '높음'으로 평가

💡

> AGC에서 표면화된 가장 심각한 버그들은 코딩 실수가 아니라 명세 오류였음. 유명한 1202 알람도 랑데부 레이더 ICD에서 위상 동기화 언급을 빠뜨린 명세 문제가 원인. 테스트는 "코드가 맞는지"를 검증하지만, 행동 명세는 "코드가 뭘 해야 하는지"를 질문함


기술 맥락

  • 행동 명세(Behavioral Specification) 가 기존의 코드 리뷰나 에뮬레이션과 근본적으로 다른 이유가 있어요. 코드 리뷰는 "이 루틴이 제대로 정리하는가"를 확인하는데, 행동 명세는 반대 방향에서 "이 리소스가 획득된 후 모든 경로에서 해제되는가"를 질문하거든요. 관점의 차이가 57년간 숨어있던 버그를 찾아낸 핵심이에요.

  • Allium은 JUXT에서 만든 오픈소스 행동 명세 언어인데, AI 네이티브를 표방해요. 13만 줄의 어셈블리를 1만 2,500줄의 명세로 증류하는 과정에서 Claude가 코드를 읽고 리소스 생명주기를 추적하는 역할을 했거든요. 사람이 어셈블리를 한 줄씩 읽는 게 아니라 AI가 모든 경로를 체계적으로 훑는 방식이에요.

  • 리소스 락 누수(CWE-772) 는 현대 코드에서도 흔한 문제예요. 언어 런타임이 관리하는 락은 deferwith 같은 구문으로 구조적으로 막을 수 있지만, 분산 락이나 DB 커넥션풀처럼 프로그래머가 직접 해제해야 하는 리소스는 여전히 같은 패턴의 버그가 발생할 수 있어요. AGC의 LGYRO가 정확히 이 케이스였고요.

  • AGC의 방어적 코딩이 오히려 버그를 은폐한 것도 재밌는 포인트예요. 재시작 로직이 메모리를 초기화하면서 락도 같이 풀려버리니까, 테스트 중에 버그가 발현돼도 시스템이 알아서 복구한 것처럼 보였거든요. "테스트 통과 = 버그 없음"이 아니라는 걸 극적으로 보여주는 사례에요.

테스트와 코드 리뷰가 '코드가 올바르게 동작하는가'를 확인하는 반면, 행동 명세는 '코드가 무엇을 해야 하는가'를 질문한다는 근본적 차이를 보여주는 인상적인 사례. AI를 활용한 대규모 레거시 코드 분석의 실용적 가능성을 입증했다.

댓글

댓글

댓글을 불러오는 중...

general

Last.fm, 소유권 바뀌고 독립 회사로 새 출발

Last.fm이 소유권 변경을 거쳐 독립 회사로 운영된다고 밝혔다. 계정, 청취 기록, 스크로블, Pro 구독, API 기능은 그대로 유지되며 사용자 데이터 처리 방식도 바뀌지 않는다고 안내했다.

general

구글이 “사람들은 AI 모드를 좋아한다”고 하자 덕덕고 방문이 28% 가까이 늘어남

구글 검색이 AI 모드와 AI 개요를 전면에 밀어붙이는 사이, AI 없는 검색을 내세운 덕덕고 쪽 트래픽이 눈에 띄게 뛰었다. 덕덕고는 “사람들이 원하는 건 AI 자체의 찬반이 아니라 선택권”이라고 보고 있다.

general

경기도, 도민 15만 명 대상 AI·디지털 교육 시작

경기도가 2026년 AI디지털배움터를 열고 약 15만 명을 대상으로 스마트폰, 키오스크, 생성형 AI, 업무 자동화 교육을 운영해. 고령층과 정보취약지역 주민을 위한 찾아가는 교육, 청년·소상공인 대상 AI 활용 교육까지 범위를 넓힌 게 특징이야.

general

NIA “공공 AX 표준 만들고, 정책부터 현장 구현까지 직접 잇겠다”

한국지능정보사회진흥원(NIA)이 AI 기본법에 따른 인공지능정책센터로 지정되며 공공 부문의 AI 전환을 지원하겠다는 방향을 밝혔다. 핵심은 부처·지자체가 각자 따로 AI를 도입하다 생기는 중복 투자와 표준 부재를 줄이고, 일부 유스케이스는 정책 설계에서 구현까지 직접 밀어붙이겠다는 것.

general

최악의 면접은 코딩 테스트가 아니라 ‘무단 심리평가’였다

한 엔지니어가 정신건강 스타트업의 창업 엔지니어 면접에서 겪은 일을 공유했다. 기술 평가도 하기 전에 90분짜리 컬처핏 인터뷰에서 인생의 가장 힘든 날, 가족 문제, 실패한 관계 같은 사적인 이야기를 끌어냈고, 다음 날 한 줄짜리 탈락 메일을 받았다는 내용이다.