소프트웨어 공학 100 주제 시리즈의 10번째 글이다. (카테고리: 기초와 역사)

한 줄 요약

Therac-25 방사선 치료기(1985~1987)와 Ariane 5 501편(1996)은 모두 이전 시스템에서 잘 돌던 소프트웨어를 새 시스템에 재사용했고, 이전 시스템에서 그 소프트웨어를 지켜 주던 조건(하드웨어 인터록, 다른 비행 궤적)이 사라진 줄 몰랐다. 두 조사 보고서는 결함 하나보다 그 결함이 사고가 되도록 허용한 시스템과 조직을 지적한다.

왜 필요한가

장애 회고에서 가장 흔한 결론은 “코드에 버그가 있었고, 고쳤다” 다. 두 사례의 조사 보고서는 그 결론이 왜 위험한지 보여 준다.

  • Therac-25 조사자들은 하나의 오류를 고치면 미래의 사고가 막힐 것이라는 가정이 심각한 실수였고, “언제나 또 다른 소프트웨어 버그가 있다” 고 쓴다.
  • Ariane 5 조사 위원회는 오류의 직접 원인을 찾은 뒤에도 “그것 자체가 임무 실패를 일으킨 것은 아니다” 라고 덧붙이고, 예외 처리 명세와 시험 방식, 프로그램의 문화를 짚는다.

오늘의 서비스 장애에도 같은 패턴이 반복된다.

핵심 개념

사례 1: Therac-25 (1985~1987)

1차 자료는 Nancy Leveson 과 Clark Turner 의 An Investigation of the Therac-25 Accidents(IEEE Computer 26(7), 18–41, 1993)다. 저자들은 소송 자료와 미국·캐나다 규제 기관 문서 등 공개 자료로 사고를 재구성했다.

무엇이 일어났나. 1985년 6월부터 1987년 1월 사이, 알려진 사고 여섯 건에서 Therac-25 가 환자에게 대량 과다 조사를 했고 사망과 중상이 발생했다. 저자들은 이 사고들이 35년 의료용 가속기 역사에서 최악의 방사선 사고로 묘사되어 왔다고 쓴다.

계보. 캐나다 원자력공사(AECL)와 프랑스 CGR 의 협력으로 Therac-6, Therac-20 이 나왔고, Therac-25 는 AECL 이 설계했다.

  Therac-6 / Therac-20 Therac-25
컴퓨터의 역할 기존 하드웨어에 편의를 더한 정도. 기계는 단독으로도 동작 처음부터 컴퓨터 제어를 전제로 설계
안전 장치 업계 표준 하드웨어 안전 기능과 인터록 유지 안전 유지 책임을 소프트웨어에 더 많이 넘김. 하드웨어 인터록 상당수를 복제하지 않음
소프트웨어 — Therac-6 소프트웨어에서 “진화”. 일부 Therac-20 루틴도 사용

소프트웨어는 한 사람이 PDP-11 어셈블리로 개발했고 문서가 거의 없었으며, 시험은 대부분 통합 시스템 시험이었다.

타일러(Tyler) 사고: 입력 속도에 걸린 경합. 텍사스의 병원에서 두 번 과다 조사가 일어났고, 기계는 “Malfunction 54” 라는 의미를 알 수 없는 메시지만 띄웠다. 병원 물리학자가 운영자와 함께 끈질기게 재현한 끝에, 처방 데이터를 빠르게 편집하는 것이 핵심 요인임을 밝혔다. 같은 절차를 수없이 반복한 숙련 운영자일수록 편집이 빨랐다. AECL 은 처음에 재현하지 못했다.

Therac-20 의 증언. 시카고 대학의 Therac-20 에서는 학생들이 “창의적인” 편집을 하면 퓨즈가 끊기곤 했는데, 같은 소프트웨어 버그가 원인이었다. Therac-20 에는 독립적인 하드웨어 보호 회로가 있어서 같은 오류가 그냥 성가신 고장으로 끝났다. Therac-25 는 그 보호를 소프트웨어에 맡겼다.

야키마(Yakima) 사고: 1바이트 카운터. 두 번째 야키마 사고의 원인은 더 단순했다. 설정 점검 루틴이 지날 때마다 공유 변수 Class3 을 1씩 증가시켰는데, 이 변수는 1바이트라 255 다음에 0이 된다. 0이면 상부 콜리메이터 위치 점검을 건너뛴다. 운영자가 정확히 그 순간 “set” 을 누르자, 표적이 제자리에 없는 상태에서 전자빔이 켜졌다. AECL 의 수정은 “증가시키는 대신 고정된 0이 아닌 값을 넣는 것” 이었다.

/* 개념 재현: 증가하는 '플래그' 는 언젠가 넘친다 */
unsigned char class3 = 0;          /* 0 = 점검 불필요라는 의미로도 쓰인다 */

void setup_test_pass(void) {
    class3++;                      /* 256번째 통과마다 0으로 돌아간다 */
}
void housekeeper(void) {
    if (class3 != 0)               /* 0이면 콜리메이터 점검을 건너뛴다 */
        check_collimator();
}
/* 수정: class3 = 1;  — 플래그는 값을 '설정' 한다. 세지 않는다 */

보고서가 꼽은 기여 요인. 저자들은 사고가 단일 원인이 아니라 기술·인간·조직 요인이 얽힌 결과라고 강조하고 다음을 든다.

  • 관리 부실, 보고된 사고를 끝까지 추적하는 절차의 부재
  • 소프트웨어 과신, 하드웨어 인터록 제거(소프트웨어가 단일 실패 지점이 됨)
  • 수준 이하로 추정되는 소프트웨어 공학 실무
  • 비현실적인 위험 평가와 그 결과에 대한 과신

교훈으로는 문서화를 미루지 말 것, 설계를 단순하게 유지할 것, 감사 추적(audit trail)을 처음부터 설계에 넣을 것, 시스템 시험만이 아니라 모듈 수준 시험과 정형 분석을 할 것 등을 든다. 그리고 재사용에 대해 이렇게 경고한다. 소프트웨어 재사용이 안전을 보장하지 않는다. 안전은 소프트웨어가 쓰이는 시스템의 성질이지 소프트웨어 자체의 성질이 아니다.

사례 2: Ariane 5 501편 (1996)

1차 자료는 J. L. Lions 가 위원장을 맡은 조사 위원회의 ARIANE 5 Flight 501 Failure — Report by the Inquiry Board(1996년 7월 19일)와 ESA 의 보도자료(1996년 7월 23일)다.

무엇이 일어났나. 1996년 6월 4일 Ariane 5 의 첫 비행에서, 비행 시퀀스 시작 약 40초 뒤 고도 약 3,700m 에서 발사체가 경로를 이탈해 분해·폭발했다.

사건의 사슬 (보고서가 파괴 시점에서 거꾸로 추적한 것을 시간 순으로 다시 놓으면):

H0+36.7s  대기 중이던 백업 관성기준장치 SRI 1 이 소프트웨어 예외로 정지
+약 0.05s 활성 장치 SRI 2 도 같은 이유로 정지 → 고장을 선언하고 진단 비트 패턴을 송출
          탑재 컴퓨터(OBC)는 백업으로 전환할 수 없음 (SRI 1 은 직전 72ms 주기에 이미 정지)
          OBC 가 진단 비트 패턴을 비행 데이터로 해석 → 부스터·주 엔진 노즐을 끝까지 꺾음
H0+39s 경 받음각 20도 초과 → 공력 하중으로 분해 시작 → 부스터 분리 → 자폭 장치 작동

직접 원인. SRI 소프트웨어가 64비트 부동소수점 값을 16비트 부호 있는 정수로 변환하다가 값이 범위를 넘어 Operand Error 가 났다. 이 변환은 Ada 코드에서 보호되지 않았다. 같은 자리의 비슷한 변환 중 일부는 보호되어 있었다.

왜 그 코드가 비행 중에 돌았나. 오류가 난 부분은 관성 플랫폼 정렬(alignment) 기능으로, 발사 전에만 의미가 있다. 그런데 이 기능은 SRI 비행 모드 시작 후 50초간 동작하도록 되어 있었고 Ariane 5 에서는 이륙 후에도 약 40초를 더 돌았다. 이 시간 설정은 Ariane 4 의 요구사항이었고 Ariane 5 에는 필요 없었다. SRI 설계, 특히 소프트웨어는 Ariane 4 의 것과 사실상 같았다.

왜 값이 넘쳤나. 문제의 변수 BH(Horizontal Bias)는 수평 속도와 관련된 값인데, Ariane 5 의 초기 궤적이 Ariane 4 와 달라 수평 속도가 훨씬 컸다.

왜 보호하지 않았나. 보고서에 따르면 SRI 컴퓨터에 최대 작업 부하 80% 목표가 있어 모든 변환을 보호하지 않았다. 분석에서 위험한 변수 7개 중 4개에만 보호를 넣었고, 나머지 3개는 물리적으로 제한되거나 안전 여유가 크다는 추론으로 남겼다. BH 에 대해서는 그 추론이 틀렸다. 이 결정의 근거는 소스 코드에 남아 있지 않았고, 방대한 문서 속에 묻혀 외부 검토에서 보이지 않았다. 게다가 Ariane 5 궤적 데이터를 SRI 요구사항·명세에 넣지 않기로 관계자들이 합의했다.

왜 그것이 치명적이었나. 예외가 나면 고장을 표시하고, 상황을 EEPROM 에 저장하고, 프로세서를 정지하도록 명세되어 있었다. 위원회는 이 결정의 배경으로 Ariane 프로그램이 무작위 하드웨어 고장만 다루는 문화를 지적한다. 하드웨어 고장이라면 이중화된 백업이 처리하겠지만, 두 장치에 같은 소프트웨어가 있으니 같은 체계적 설계 오류로 둘 다 멈췄다.

권고 중 일부.

번호 권고 요지
R1 이륙 직후 정렬 기능을 끈다. 일반적으로, 필요 없는 소프트웨어 기능은 비행 중 실행하지 않는다
R2 실제 장비를 최대한 포함한 시험 시설에서 현실적 입력으로 완전한 폐루프 시스템 시험을 한다
R3 관성기준장치 같은 센서가 최선의 데이터를 보내는 것을 멈추지 않게 한다
R5 모든 비행 소프트웨어를 검토하고, 코드가 가진 암묵적 가정과 그 근거를 식별한다

실무 적용

두 사례에서 공통으로 뽑은 재사용·안전 점검표다.

## 재사용 컴포넌트 도입 점검
- [ ] 원래 시스템에서 이 코드를 보호하던 외부 장치(하드웨어, 상위 검증, 입력 범위)가 새 시스템에도 있는가?
- [ ] 새 환경의 입력 범위(궤적, 트래픽, 데이터 크기)로 가정을 다시 검증했는가?
- [ ] 새 시스템에서 필요 없는 기능이 켜진 채로 돌고 있지 않은가? (Ariane R1)
- [ ] 보호하지 않기로 한 경로가 있다면, 그 근거가 코드 옆(주석/ADR)에 남아 있는가?
- [ ] 예외 시 동작이 "정지" 라면, 정지가 정말 가장 안전한 상태인가? (Ariane R3)
- [ ] 이중화 구성 요소가 같은 소프트웨어를 쓴다면, 공통 원인 고장을 고려했는가?
- [ ] 오류 메시지를 운영자가 이해할 수 있는가? (Therac "Malfunction 54")
- [ ] 같은 증상의 사고 보고를 끝까지 추적하는가?

회고에서는 “근본 원인 하나” 대신 기여 요인 목록을 쓰자(장애 대응과 포스트모템).

흔한 오해와 함정

  • “Therac-25 는 코딩 실수 하나 때문이다.” 보고서는 특정 버그보다 소프트웨어에 안전을 맡긴 설계 전체를 문제 삼는다.
  • “Ariane 5 는 정수 오버플로 때문이다.” 직접 원인일 뿐이다. 불필요하게 돌던 기능, 예외 시 정지 명세, 새 궤적을 쓰지 않은 시험이 겹쳤다.
  • “검증된 코드를 재사용하면 안전하다.” Leveson·Turner 의 말대로 안전은 시스템의 성질이다. Ariane 4 에서 검증된 코드는 Ariane 4 의 궤적에서 검증된 것이었다.

확인 문제

  1. Therac-20 에도 같은 소프트웨어 버그가 있었는데 왜 사고로 이어지지 않았는가?
  2. 야키마 사고의 Class3 변수 문제를 한 문장으로 설명하고, 수정 방법을 말하라.
  3. Ariane 5 에서 오류가 난 정렬 기능이 비행 중에 돌고 있었던 이유는?
  4. 두 개의 SRI 가 거의 동시에 멈춘 것이 “이중화 실패” 인 이유는?
  5. 두 사례에서 공통으로 얻을 수 있는 재사용에 관한 교훈은?

풀이

  1. Therac-20 에는 독립적인 하드웨어 보호 회로와 인터록이 있어서, 버그가 퓨즈 단선 같은 고장으로 끝나고 과다 조사로 이어지지 않았다.
  2. 플래그로 쓰이던 1바이트 변수를 매번 증가시켜 256번째마다 0으로 넘치고, 0일 때 콜리메이터 점검이 생략되었다. 증가 대신 고정된 0이 아닌 값을 설정하도록 바꿨다.
  3. 정렬 기능이 비행 모드 시작 후 50초간 동작하도록 한 Ariane 4 의 요구사항이 그대로 남아 있었기 때문이다. Ariane 5 에는 필요 없었다.
  4. 두 장치가 같은 소프트웨어를 실행해 같은 입력에서 같은 체계적 오류로 정지했다. 무작위 하드웨어 고장을 가정한 이중화는 공통 원인 고장을 막지 못한다.
  5. 재사용 코드의 안전은 원래 환경의 조건(하드웨어 인터록, 입력 범위)에 의존한다. 새 시스템에서 그 조건이 유지되는지 다시 검증해야 하며, 안전은 시스템 수준의 성질이다.

더 읽을거리 (References)