3P by GN⁺ 12시간전 | ★ favorite | 댓글 2개
  • 마하 1의 속도에서 한 줄 버그가 치명적 결과로 이어지는 전투기·로켓 소프트웨어가 왜 C++ 기능의 대부분을 제거해 예측 가능한 코드만 남기는지 설명하는 영상
  • F-4의 기계식 폭격 컴퓨터, 비공개 F-14 마이크로프로세서, Jovial·CMS-2·Ada로 이어지는 군용 언어 전쟁과 코드 폭증이 단일 안전 언어와 엄격한 표준을 요구하게 된 역사를 정리
  • F-35 개발 과정에서 Lockheed가 Ada 대신 C++ 사용을 설득하며 만든 JSF C++ 표준이 예외, 재귀, 동적 메모리 할당을 금지하고, 반환 코드·반복 루프·사전 메모리 예약 등으로 대체하는 방식등을 실제 코드로 시연
  • 초기 F-35 미션 컴퓨터가 PowerPC 계열 아키텍처를 사용했다는 점과 함께, X-Plane 12와 자체 제작 MFD를 연결해 JSF 규칙을 어기는 코드와 준수 코드가 실제로 비행 중 어떻게 다른지 비교함
  • JSF 표준이 이후 NASA F-Prime·MISRA·AutoSAR 같은 안전성 표준으로 이어졌고, 지금은 그 유산 위에서 C++ Core Guidelines와 현대 C++ 를 사용하는 방향이 더 적합하다는 결론을 제시

발표자 소개

  • 항공우주 시스템용 C++ 코드를 작성하며 공군 대상 시연을 하던 경험이 있는 개발자
    • 실제로 안전성 요구가 높은 시스템에서 C++를 사용한 경험을 바탕으로 설명 진행
    • X-Plane 12와 웹 API, Python UI, C++ 백엔드로 구성된 직접 제작 MFD(다기능 디스플레이) 를 데모 환경으로 사용함

비행 소프트웨어와 실패가 허용되지 않는 환경

  • 일반 애플리케이션에서 크래시는 재시작으로 끝나지만, 마하 1 전투기·로켓에서는 한 번의 실패가 곧 재난이 되는 환경임
    • “마하 1에서는 가비지 컬렉터를 기다릴 시간이 없다” 는 문장으로 실시간성 요구를 강조
    • 한 줄의 잘못된 코드가 치명적 결과로 이어지는 상황에서 언어 기능 선택 자체가 안전 장치가 되어야 함
  • 1996년 Ariane 5 폭발 사고를 대표 사례로 제시
    • 수평 바이어스 64비트 부동소수점 값을 16비트 정수로 변환하는 과정에서 예외가 발생했고, 이 예외가 처리되지 못함
    • 언어는 규격대로 오류를 발생시켰지만, 시스템이 이 예외를 처리하지 못해 5억 달러에 달하는 로켓이 즉시 파괴되는 결과로 이어짐
  • 이 사례를 기준점으로 F-35 설계팀은 같은 실수를 반복하지 않기 위해 언어 기능 자체를 잘라내는 접근을 택함

군용 소프트웨어의 역사와 언어 전쟁

  • 초기 전투기인 F-4 Phantom 시절에는 사실상 소프트웨어가 없었음
    • 폭격 컴퓨터는 기어와 캠으로 구성된 정밀 기계장치에 가까웠고, “코드”는 금속 캠의 형태 자체였음
  • 기밀 프로젝트였던 해군 공중우세기 VFX(F-14 Tomcat) 에서 상황이 바뀜
    • 교과서에서 “최초의 마이크로프로세서”로 알려진 Intel 4004보다 앞서, Garrett AiResearch가 F-14용 마이크로프로세서를 설계했다는 사실이 뒤늦게 공개됨
    • F-14의 가변익(swing wing)을 최적 제어하기 위해 고성능 마이크로프로세서가 필요했고, 여기에 약 2500줄 수준의 마이크로코드가 태워져 다항식 계산을 수행함
  • 이후 각 군이 서로 다른 언어를 채택하며 언어 난립이 시작됨
    • 공군은 ALGOL 계열인 Jovial(Jules Own Version of the International Algorithmic Language) 를 사용함
    • 해군은 공군 언어를 쓰지 않겠다며 F-18에 CMS-2를 채택함
    • 서로 다른 언어·하드웨어 아키텍처를 쓰면서 코드 재사용과 검증이 거의 불가능한 상태가 됨
  • 동시에 항공기당 소프트웨어 규모가 지수적으로 증가
    • F-16A 약 12.5만 라인, B-1 약 100만 라인, 현대 F-35는 약 900만 라인 수준으로 증가했다고 수치 예시를 제시함
    • 국방부 조사에서 450개가 넘는 프로그래밍 언어가 사용 중이고, 제대로 된 표준을 가진 언어는 거의 없었다는 보고가 나옴

Ada 강제와 그 한계

  • 이런 난립을 해결하기 위해 국방부는 단일 고급 언어 Ada를 만들고 강력한 사용 의무를 부과함
    • 새 프로젝트에서 Ada를 쓰지 않으려면 “왜 Ada로는 불가능한지”를 입증해야 했고, 그렇지 않으면 계약을 따낼 수 없는 구조였음
  • Ada는 안전·신뢰성이 중요한 분야에는 매우 적합한 언어로 소개됨
    • 항공우주 같은 안전 중요 시스템에서 메모리·타입 안정성을 보장하기 위한 설계가 강조됨
  • 하지만 90년대에 들어 현실과 괴리가 드러나기 시작함
    • 한편에서는 인터넷, Windows 95, C++ 기반 상용 게임들이 주류를 형성함
    • 학생·개발자들은 비싼 Ada 컴파일러 대신, 무료 GCC와 C++ 에 자연스럽게 몰림
    • Ada 컴파일러는 수천 달러에 달해 개인이 접하기 어려웠고, 결과적으로 Ada 전문 인력 풀도 줄어드는 흐름을 보임

F-35와 JSF C++ 표준의 탄생

  • F-35(공동타격전투기, Joint Strike Fighter) 는 처음부터 소프트웨어 비중이 매우 큰 기체로 설계됨
    • 센서 융합(sensor fusion) 같은 복잡한 계산이 기체 운용 핵심으로 자리 잡음
  • Lockheed Martin은 이런 요구를 위해 C++ 사용 허용을 국방부에 제안함
    • 기존 Ada 강제 정책을 사실상 “깨달라”는 요청이었고, 이를 설득하려면 C++의 위험을 통제할 방법이 필요했음
  • 이 과정에서 C++ 창시자 Bjarne Stroustrup도 조언자로 참여해 JSF C++ 규칙 설계에 관여했다고 언급함
    • 직접적으로 JSF 규칙 작성에 손을 보탰다고 밝혔고, 그만큼 이 표준에 대해 “편향이 있을 수 있다”고 스스로 언급함
  • 핵심 아이디어는 “remove before flight” 태그와 같은 발상임
    • 비행 전 제거해야 하는 태그처럼, C++에서 위험한 기능들을 언어 차원에서 제거해 예측 가능한 서브셋만 사용하는 방식임
    • 이로써 Ada 수준의 안전성을 확보하면서도, 개발자는 C++의 표현력을 일정 부분 활용할 수 있게 됨

실제 하드웨어와 GameCube 비유

  • 초기 F-35 블록은 Motorola G4 PowerPC 프로세서 기반 미션 컴퓨터를 사용했음
    • 이 정보는 2003년 Aviation Today 기사 등에서 공개된 내용
  • GameCube 역시 PowerPC 계열 프로세서를 사용하기 때문에, 명령어 집합 수준에서 유사한 세대의 하드웨어라는 점에서 재미있음
    • 보다 정확한 세대 일치를 위해서는 다른 콘솔이 더 가깝지만, 원리를 이해하는 데에는 GameCube 비유로 충분

JSF C++ 데모 환경: X-Plane 12 + MFD

  • X-Plane 12를 기반으로 F-35B 애드온(AOA Simulations)을 사용해 비행 시뮬레이터 환경을 구성함
    • X-Plane의 새로운 웹 API로 실시간 비행 데이터를 구독하고, 이를 MFD에 표시하는 구조
  • 프런트엔드는 Python으로 구성되고, 백엔드는 C++ 플러그인으로 작성되어 JSF 규칙을 따르거나 위반하는 코드들을 비교 시연
    • 고도, 속도, 바람, 비행 엔벨로프, 네비게이션 데이터 등 각종 정보를 C++ 계산 결과로 표시함
  • 비행 중 의도적으로 예외를 던지는 비표준 C++ 코드를 실행해 MFD가 죽고, 비행에 문제가 생기는 상황을 보여준 뒤, JSF 규칙을 적용해 이를 해결하는 과정을 단계적으로 보여줌

JSF의 세 핵심 제약: 예외, 재귀, 동적 메모리

  • JSF C++ 표준에서 강조하는 세 가지 핵심 제약은 예외(Exception), 재귀(Recursion), 동적 메모리 할당
    • 여기에 더해 함수의 Cyclomatic Complexity(분기 복잡도) 상한도 명시됨

1) 예외 금지 – AV Rule 208

  • JSF AV Rule 208: “예외는 사용하지 않는다(exceptions shall not be used)”
    • try, catch, throw 등 예외 관련 키워드를 전면 금지함
  • 핵심 이유는 제어 흐름의 비결정성 때문임
    • Ariane 5처럼 예외가 발생했을 때, 핸들링이 누락되거나 타이밍이 어긋나면 시스템 전체가 예측 불가능하게 무너질 수 있음
  • Bjarne는 현대 C++ 예외 처리에 우호적이지만, JSF가 설계될 당시에는 도구 성숙도와 실시간성 보장 문제 때문에 예외를 지원할 수 없는 상황이었다고 설명함

    “JSF++는 하드 실시간·안전 중요 애플리케이션(비행 제어)용이기 때문에, 계산이 너무 오래 걸리면 사람이 죽을 수 있고, 예외로는 응답 시간을 보장할 수 없다”

  • JSF에서는 예외 대신 반환 코드(return code) 를 활용함
    • 밀도고도(density altitude) 계산 예시에서, 오류 상황마다 서로 다른 반환 코드를 설정하고 호출자가 이를 해석해 처리하게 구성함
    • 계산 실패나 시간 초과가 발생해도, 프로그램 전체가 죽지 않고 호출 측에서 “에러 상태”를 안전하게 표현할 수 있음

2) 재귀 금지 – AV Rule 119

  • AV Rule 119는 함수가 직접·간접으로 자기 자신을 호출하는 것, 즉 재귀를 금지함
    • 재귀 호출마다 새로운 스택 프레임이 쌓이고, 최대 깊이 상한을 알기 어려워 스택 오버플로 위험이 커지기 때문
  • 비행 계획 중 대체 공항 계산에 쓰는 이항계수(binomial coefficient) 를 예시로 듬
    • 비표준 버전에서는 C(n, k) = C(n-1, k-1) + C(n-1, k) 형태의 재귀 구현을 사용함
    • 이는 호출 깊이가 입력에 따라 달라져, 메모리 상한을 예측하기 어렵다는 문제가 있음
  • JSF 준수 버전에서는 같은 계산을 반복문 기반의 반복적(iterative) 구현으로 변경함
    • 코드는 길고 덜 우아하지만, 자기 자신을 호출하지 않기 때문에 재귀 없이 동일한 결과를 제공함
    • 이렇게 하면 함수 호출 깊이와 메모리 사용 상한을 정적으로 추론하기 쉬워짐

3) 동적 메모리 할당 금지 – AV Rule 206

  • AV Rule 206: 초기화 이후에는 메모리 할당·해제를 하지 않는다
    • 실행 중 new, delete, 스마트 포인터를 통한 내부 new 등 힙 할당을 금지함
  • 이유는 두 가지 주요 문제 때문임
    • 힙 할당에는 얼마가 걸릴지 모르는 시간 비결정성이 존재함
    • 힙이 조각화(fragmentation)되면, 총 용량이 남아 있어도 큰 연속 블록을 찾지 못해 할당 실패가 발생할 수 있음
  • 예시로, 돌풍(gust) 계산을 위해 IAS(지시대기속도) 이력 버퍼std::unique_ptr + 동적 배열로 만드는 비표준 코드를 보여줌
    • 실행 중 새로운 배열을 할당해 JSF 규칙을 어기는 형태임
  • JSF 준수 버전에서는 최대 크기를 상수로 정의한 고정 크기 배열을 사용함
    • MAX_IAS_HISTORY와 같이 상수를 정의하고, 초기화 시 한 번만 메모리를 잡은 뒤 인덱스만 회전시키는 방식으로 운용함
    • 이렇게 하면 실행 중에는 어떤 추가 할당도 일어나지 않아 시간·메모리 측면에서 예측 가능성이 확보됨

4) Cyclomatic Complexity 상한 – AV Rule 3

  • AV Rule 3은 함수의 Cyclomatic Complexity(분기 복잡도) 가 20을 넘지 않아야 한다고 규정함
    • 함수 선언 자체 1점, if·while·for·switch·논리 AND/OR 등이 모두 복잡도에 1씩 더해짐
  • 이항계수 반복 구현을 예시로, 각 if·논리 연산·for 루프가 복잡도 포인트를 어떻게 증가시키는지 보여줌
    • 복잡도가 높아질수록 테스트·검증·분석이 어려워지기 때문에, 일정 상한 이하로 유지하는 것이 표준 목표임

JSF 유산: NASA F-Prime, MISRA, AutoSAR

  • JSF C++ 표준의 아이디어는 이후 다른 안전 중요 분야로 퍼져 나감
    • NASA의 비행 소프트웨어 프레임워크 F-Prime은 2017년에 공개되었고, 동적 메모리 할당 금지, 예외 금지, 재귀 금지 같은 규칙을 공유함
  • 자동차 산업에서도 비슷한 흐름이 이어짐
    • MISRA C++, AutoSAR(Automotive Open System Architecture) 같은 표준이 등장해 자동차 소프트웨어 안전 규칙을 제시함
    • AutoSAR C++14 가이드는 JSF를 명시적으로 참고했다고 언급되며, JSF의 영향력이 자동차 소프트웨어까지 이어졌음을 보여줌
  • 현대 자동차는 사실상 “바퀴 달린 컴퓨터” 에 가까운 만큼, 이런 언어 서브셋·코딩 규칙이 안전을 지탱하는 핵심 기반이 됨

결론: 오늘 C++를 쓴다면 무엇을 따라야 하는가

  • JSF C++ 표준은 당시 기준으로 복잡한 언어를 예측 가능한 서브셋으로 축소해, 전투기 비행 제어 수준의 안전성을 확보한 엔지니어링 성과로 제시됨
  • 동시에 Bjarne Stroustrup는 오늘날 개발자에게 C++ Core Guidelines와 현대 C++를 따를 것을 권장함
    • C++ 언어와 툴체인이 지난 수십 년간 발전했고, 예외·스마트 포인터 같은 기능도 안전하게 쓸 수 있는 환경이 많이 마련되었기 때문임
  • 그럼에도 JSF는 여전히 언어를 추가가 아니라 “제거”로 통제하는 사고방식의 중요한 사례로 남음
    • 무엇을 넣을지보다, 무엇을 remove before flight 리스트에 올릴지가 안전 중요 시스템 설계의 핵심이라는 메시지로 마무리

RUST 문법을 STRICT 하게 쓰자!

Hacker News 의견
  • F-35의 C++ 코딩 표준 문서가 여기에 있음
    142페이지짜리로, 실제 항공기 소프트웨어 개발에서 어떤 제약이 있는지 볼 수 있음
    • 몇 장 훑어봤는데 꽤 합리적인 규칙들로 보임
      다만 “shall” 규칙의 예외가 궁금함. 이런 대규모 프로젝트에서는 예외 케이스가 표준의 실효성을 보여줌
    • 실시간 시스템에서는 운영 중 동적 메모리 할당 금지 규칙이 있음
      2005년 당시에는 괜찮았겠지만, 요즘 AI 기반 드론 같은 환경에서는 어떻게 적용될지 궁금함
    • 이런 규칙을 정적 분석 도구로 강제하는지, 아니면 개발자들이 직접 숙지해야 하는지 궁금함
    • 임베디드나 저사양 기기용 소프트웨어에도 이런 규칙이 유효한지 고민됨
      특히 stdio.h 금지 같은 부분은 낯설지만, 읽다 보면 “그래, 맞는 말이네” 싶음
    • 이 문서를 처음 봤을 때, 누군가가 “Arduino Uno용 C++도 여전히 C++이다”는 예시로 들었음
  • 실제 MISRA 코드에서 본 적 있는 a = a; 같은 구문이 떠오름
    사용되지 않는 파라미터를 제거하지 않기 위한 꼼수인데, 이런 규칙이 좋은 코드 품질을 보장하는지는 의문임
    • MISRA 관련 연구를 보면 일부 규칙은 결함을 줄이지만, 일부는 오히려 결함을 늘림
      JSF 가이드라인은 2005년 문서라 시대적 한계가 있음
      Bjarne Stroustrup이 최근 “C++ 프로파일” 개념을 제시한 것도 흥미로움
      결국 이런 스타일 가이드는 미적 취향의 문제일 수도 있음
    • C에서는 변수를 참조만 할 때 (void)a;로 처리하는 게 표준적인 방식임
    • 실제로 안전 필수 코드를 많이 작성해봤는데, 코딩 규칙이 전체 품질을 떨어뜨리는 경우도 많았음
      진짜 안전을 보장하는 건 설계 품질과 페일세이프 구조
    • Zig에서는 _ = a;로 명시적으로 처리함
      관련 이슈도 있음
    • 이런 표준은 코드 리뷰를 대체하지 않음
      오히려 리뷰 시 참고할 공통 기준을 제공하는 역할임
  • 위성 소프트웨어도 비슷하게 STL 사용이 금지되어 있음
    핵심은 미션 보증(mission assurance)
    스택이나 힙을 쓰면 변수의 메모리 주소가 바뀌는데, 특정 셀이 고장 나면 문제가 생김
    모든 변수가 고정 주소를 가지면, 고장난 셀만 패치로 옮겨서 임무를 계속할 수 있음
    • 하지만 C++에서 스택을 완전히 안 쓰는 건 불가능함
      지역 변수, 매개변수, 반환 주소 등은 결국 스택에 필요함
      재귀도 불가능해지고, 임시 변수도 제한됨
      그래서 이 주장은 현실적이지 않음
    • 이런 수동적 접근보다는 ECC 메모리Reed-Solomon 코딩 같은 자동화된 방법이 더 효율적임
    • 그렇다면 변수는 전역으로 두는 건가? 그리고 메모리 셀 오류 감지는 어떻게 하는지 궁금함
    • 실제로는 스택을 사용함. 힙은 제한되지만 메모리 풀을 사용함
      스택과 힙의 주소 범위를 고정할 수는 있지만, 이게 설득력 있는 이유인지는 의문임
    • 그렇다면 함수의 in/out 파라미터는 어떻게 처리하는지도 궁금함
  • “모든 if, else if에는 반드시 else나 주석이 있어야 한다”는 규칙이 있음
    나도 비슷하게 “이 경우는 절대 발생하지 않아야 함” 같은 로그를 남김
    대규모 시스템에서는 이런 예외 상황 로깅이 디버깅에 매우 유용함
    • Rust의 match 문이 이런 점에서 좋음
      모든 경우를 명시적으로 처리해야 해서, enum 값이 추가되면 컴파일러가 경고해줌
    • 나는 여기에 _STOP이나 _CRASH 매크로를 추가해서 즉시 디버그 중단시키기도 함
      문제를 바로 수정하도록 강제하는 효과가 있음
  • Ada 대신 C++을 선택한 이유를 설명한 엔지니어링 리드의 글이 있음
    요약하면 “Ada 개발자와 툴체인이 부족했다”는 이유였음
    하지만 지금은 언어 다양성에 대한 개방성이 커져서 Ada가 더 받아들여질 수 있을 것 같음
    NVidia가 SPARK를 채택한 것도 Ada의 부활 조짐으로 보임
    • “Ada 개발자가 부족하다”는 논리는 싫어함
      DoD가 Ada를 강제했다면, 대학과 기업이 따라왔을 것임
      결국 언어 학습은 가능하고, Ada를 썼다면 F-35의 신뢰성도 더 높았을 것임
    • 지금도 Ada 컴파일러를 파는 업체가 7곳이나 있음
      AdaCore, GHS, PTC ApexAda, DDC-I, Irvine, OC Systems, RR Software 등임
      과거에는 Ada 컴파일러가 유료 옵션이었고, C/C++은 기본 제공이라 학교나 기업이 C++을 택했음
      AdaCore가 ISO 표준화와 오픈소스 확산에 큰 기여를 했음
    • 나도 Ada가 다시 부흥하길 바람
      예전엔 과도하게 비판받았지만, 지금은 오히려 매력적으로 느껴짐
    • 하지만 실제로 Ada를 써보니 문법이 마음에 들지 않았음
      파일 구조나 빌드 플래그가 복잡했고, RedMonk 언어 순위에도 Ada가 없었음
      일부 기능은 흥미로웠지만, Rust처럼 현대적인 언어 경험은 아니었음
  • 항공전자 분야가 MISRA C/C++을 따르는지 궁금했음
    • 코딩 표준은 일부일 뿐이고, 핵심은 감사 가능한 프로세스 문서화
      DO-178C 같은 인증 체계가 중요함
    • 회사마다 다름. 어떤 곳은 Matlab/Simulink 오토코드로 생성된 C를 그대로 씀
      오히려 이게 고신뢰성 코드 작성의 올바른 방식일 수도 있음
    • 지역별로도 다름. 미국은 MIL 표준, 유럽은 ECSS, 항공은 DO-178C, 그리고 MISRA가 널리 쓰임
  • LaurieWired의 유튜브 채널이 정말 훌륭함
    • 특히 ARM 어셈블리 튜토리얼 시리즈가 뛰어남
  • Laurie의 다른 영상들도 추천함
    리버스 엔지니어링, 난독화, 컴파일러 등 다양한 주제를 다룸
  • “널 포인터를 역참조하지 말라”는 규칙(AV Rule 174, MISRA Rule 107)을 보고
    이런 것도 굳이 명시해야 하나 싶었음
  • 실제 F-35 코드 빌드에 어떤 컴파일러를 쓰는지도 궁금함
    LM이 직접 만든 건지, 상용 제품인지 알고 싶음