戦闘機はなぜC++の機能の9割を「禁止」するのか。F-35の安全プログラミング哲学。
こんにちは。エンジニアの直也です。
YouTube「直也テック」でプログラミング教育、Webセキュリティ動画を作っています。
たった一つの未処理の例外が、わずか数秒で5億ドルのロケットを消し飛ばしました。F-35の開発者たちは同じ過ちを繰り返さないと決め、強力な言語であるC++から特定の機能を「外科手術のように」削り取ることで、より安全なソフトウェアを作り上げました。
この記事ではセキュリティリサーチャーとして知られるLaurieWiredさんの動画をもとに、航空宇宙ソフトウェアの歴史と、戦闘機F-35が採用したC++コーディング標準「JSF++」の核心を追っていきます。実際にフライトシミュレーターとC++コードを使った実演を交えながら「飛行前に取り外すべきもの(remove before flight)」という考え方を解説していきます。AIによるコード生成が当たり前になりつつある今だからこそ、安全が絶対の領域でどんな規律が求められるのかを知る手がかりになるはずです。
飛行ソフトウェアの歴史と、5億ドルを消した一行

動画は強烈な一言から始まります。
(約0:00)"At Mach 1, you don't have time for a garbage collector."
マッハ1の世界では、ガベージコレクタを待っている時間などない。
ほとんどのプログラムにとってバグは単なる不便であり、クラッシュしてもアプリを再起動すれば済みます。しかし失敗が許されない世界、たった一行の不具合が大惨事につながる世界では話がまったく変わってきます。

その象徴として紹介されるのが1996年6月4日、欧州の新型ロケット「アリアン5」の事故です。打ち上げ後36秒間は完璧でした。しかしフライト制御ソフトウェアの奥深くで一つの未処理例外が発生します。64ビットの浮動小数点数(horizontal biasの値)を16ビット整数へ変換しようとしたことが引き金でした。言語は許された通りに振る舞ってエラーを発生させましたが、システムはそのエラーを処理できず、5億ドルが一瞬で失われました。
(約1:24)"In this particular situation, an exception was detected, but it wasn't properly handled."
この事故では例外そのものは検出されていたものの、適切に処理されていなかった。

なお、このアリアン5の事故については視聴者からより詳細な背景の補足も寄せられています。
"In the case of the crash of Ariane 5, the exception was not unhandled. It was assumed that after the extensive testing... no exception could happen, so if any occured, it was assumed that it is due to hardware malfunction... But this second one was doing exactly the same computation, triggering exactly the same exception."
アリアン5では例外が無視されていたわけではなく、入念なテストを経た以上もう例外は起こらないと想定され、もし起きたらハードウェア故障とみなして冗長系へ切り替える設計だった。ところが切り替えた2台目もまったく同じ計算をして同じ例外を出した――という指摘です。(@robert.ehrlich8942)
F-35の設計者たちはこうした失敗を二度と起こさないと決めました。JSF(Joint Strike Fighter)のC++標準には「AVルール208:例外を使用してはならない(exceptions shall not be used)」と明記されています。これこそが「remove before flight」の好例で、対象言語から特定の機能を切り出すことで、より安全なものを作れるという発想です。
ここで語り手は「戦闘機パイロットのようにプログラムする」とはどういう意味なのか、なぜそれが重要なのか、そしてなぜ目の前にゲームキューブが置いてあるのか(理由は後ほど明かされます)を予告します。単なる歴史解説ではなく、JSF標準に厳密に従ったC++コードをフライトシミュレーター内のF-35に接続して実演していく構成です。
ペンタゴンで戦われた「言語戦争」とC++への道

現代の軍用機は、ハードウェアよりもむしろソフトウェアの塊だと語り手は強調します。
(約2:56)"It's much more like you're flying a computer that happens to also be a plane."
それは「たまたまコンピュータを積んだ飛行機」ではなく「たまたま飛行機でもあるコンピュータ」を操縦している感覚に近い。
1970年代初頭のF-4ファントムにはほとんどソフトウェアがなく、爆撃コンピュータは歯車とカムの箱、いわば精密時計のようなものでした。コードと呼べるものは金属製カムの形そのものでした。
これが変わり始めたのが、後にF-14トムキャットとして知られる極秘の海軍プロジェクトです。実は世界初のマイクロプロセッサはIntelではなく、Garrett AiResearch社がF-14のために作っていました。可変翼(スイングウイング)の制御を手動で行うのは負荷が大きすぎたためで、この事実はソ連に知られないよう1998年まで機密扱いでした。多項式を処理する約2500行相当のマイクロコードが物理的に焼き込まれており、これが飛行機に載った最初の本格的ソフトウェアでした。
初期のソフトウェア時代は混沌としていました。陸軍・空軍・海軍がそれぞれ異なるコーディング標準を持っていたのです。空軍は「Jovial」を好み、海軍はF/A-18とともに独自の「CMS-2」を採用しました。二つの言語、二つのハードウェアアーキテクチャ、そして互換性ゼロという状態でした。

搭載ソフトウェアの量は指数関数的に増えていきます。F-16Aの約12万5000行から、B-1の100万行へ、そして現代のF-35では実に900万行へと跳ね上がりました。ある時点では450種類以上のプログラミング言語が使われ、しかもそれぞれにきちんとした標準がなかったと報告されています。
そこで国防総省はこれらを置き換える高水準言語として「ADA」を打ち出しました。その推進ぶりは徹底していて、ADAを使わないなら「使えないことを物理的に証明しなければならない」という事実上の義務化でした。ADAを使わなければ契約も取れないという世界です。ADAは安全性が重視されるアプリケーションに非常に適しており、航空宇宙では不可欠でした。
このADA義務化は約15年続きましたが、やがて問題が表面化します。1990年代、航空宇宙はADA一色だった一方で、世間ではインターネット、Windows 95、そして良質なゲームの数々がC++で動いていました。高給なソフトウェア職を狙う学生はADAではなくC++を学びます。さらに当時のコンパイラは有料で、ADAのコンパイラは数千ドルもしました。学生たちがC++とGCCという「無料ソフトウェアの特急列車」に飛び乗ったのも当然でした。
"@7:50 This!!! One of the many wonderful gifts of open source is that young folks interested in writing programs will never again have to pay for a compiler 👨🏾💻"
「これだよ! オープンソースの素晴らしい贈り物の一つは、プログラムを書きたい若者が二度とコンパイラにお金を払わなくていいことだ」とコンパイラ有料時代を懐かしむ声もありました。(@theycallmeken)
ちなみにADAは無駄にはなりません。視聴者からはこんな実体験も寄せられています。
"My friend took ADA as a throw away elective in college. He then spent 15 years bouncing around military contractors making very decent money."
「友人は大学で捨て科目のつもりでADAを取った。その後15年間、軍需請負企業を渡り歩いてかなりの稼ぎを得ていた」(@digitalranger4259)
C++を「飼いならす」――JSF標準の誕生

ロッキード・マーティンがF-35開発に取り組む頃、この機体がセンサーフュージョンをはじめ極めてソフトウェア依存度の高い航空機になることは明らかでした。そこで彼らは不可能に挑みます。国防総省を説得し、ADAではなくC++の使用を認めさせようとしたのです。
(約9:05)"Please let us break the law and do it with your approval. Please let us use this new unsafe language and ignore every single other software mandate you've made up until this point."
「どうか、あなた方の承認のもとで掟破りをさせてください。この新しくて安全でない言語を使い、これまでのあらゆるソフトウェア義務を無視させてください」――ペンタゴンでの提案はそんな交渉だったと表現されています。
ただし生のC++をそのまま使うつもりはなく、言語を飼いならす計画がありました。その助言を仰いだ相手は、C++の生みの親ビャーネ・ストロヴストルップ本人です。語り手は実際に会って質問したこともあると明かしつつ、ストロヴストルップ自身もJSFルールの策定に関与したことを認めていると紹介します。

C++という強力な言語から特定の部分を外科的に取り除くことで、ADAのような旧来の言語に縛られることなく、ミッション認証や安全認証を通しやすいコードを書ける――これがJSF C++標準化の核心です。しかも驚くべきことに、このJSF標準は誰でもオンラインで公開されており、理論上は誰でも数十億ドル規模の航空機プロジェクトに準拠コードで貢献できるのです。Joint Strike Fighterという名の通り、ロッキードだけでなく多数の防衛企業・政府・国々が協働したプロジェクトでした。
C++の二面性については、視聴者からストロヴストルップの有名な言葉も引かれています。
"Yes and Bjarne was also the same person who said, 'C makes it easy to shoot yourself in the foot; C++ makes it harder, but when you do it blows your whole leg off.'"
「Cは自分の足を撃ち抜きやすい。C++ではそれが難しくなるが、やってしまうと足ごと吹き飛ばす」――そんな言葉を残した人物でもある、と。(@chuckbatson595)
シミュレーターでF-35を飛ばす

語り手はかつて航空宇宙システム向けのC++を書き、空軍向けにデモを行う仕事をしていたと明かします。実演では人気のフライトシミュレーター「X-Plane 12」とAOA Simulations製のF-35Bを使用します。X-Planeは業界でもソフトウェアの統合テストや飛行デモにしばしば使われています。
画面にはF-16スタイルの多機能ディスプレイ(MFD)が用意され、X-Planeが最近公開したWeb API経由でライブの飛行データを購読し続けています。フロントエンドのUIはPython、そして実際にJSF標準を実演するバックエンドの計算部分がC++という構成です。位置データ、風のデータ、エンベロープデータ、ナビゲーションデータなどがリアルタイムで更新されていきます。

そして実際の離陸とフライトが始まります。トップガン風のサングラスのせいで視界はほとんどないと笑いを交えつつ、スムーズな離陸、バレルロール、そして何度も「Pull up(引き起こせ)」と叫ぶ操縦が続きます。このドタバタぶりは視聴者にも大いに刺さったようで、独立した反応として後述します。
実演用のコードはGitHubで公開されています。
"Follow along with my compliant...and not so compliant F-35 C++ code here! Github: https://github.com/LaurieWired/XplaneFlightData"
「準拠版・非準拠版のF-35 C++コードはここから追えます」と本人がリポジトリを案内しています。(@lauriewired)
リポジトリには「compliant(準拠)」と「non-compliant(非準拠)」のフォルダがあり、密度高度計算機、旋回計算機、垂直ナビゲーションデータ、風の計算機といったミッションクリティカル/セーフティクリティカルな計算がC++で書かれています。これらのコードは100%の時間、100%信頼できなければならない――だからこそ厳しい標準に従う必要があるのです。
JSF標準そのものは膨大で、目次だけでも多くの項目に及びます。なかでも「戦闘機のためにプログラムする」うえで押さえるべき三本柱が、メモリ割り当て・例外・再帰です。安全性の本質は、言語に何かを足すことではなく、言語から何かを取り除くことで予測可能な振る舞いを得ることにある、と語り手はまとめます。
なお余談として、初期ブロックのF-35のミッションコンピュータはMotorola G4 PowerPCプロセッサをベースにしていたと紹介されます。これは公開情報で、2003年頃のAviation Today誌でも議論されているとのこと。だからこそ目の前にゲームキューブ(同じPowerPC系)が置いてあった、というわけです。耐環境化やベクトル拡張などは加わっているものの、命令セットアーキテクチャの根幹はよく似ているといいます。
三本柱その1――例外を使わない

最初の柱は、すでに触れたAVルール208「例外を使用してはならない」です。実演中、語り手は飛行データを確認している最中にC++の例外に遭遇し、プログラムが処理を放棄して「墜落」してしまう様子を見せます。
なぜ例外がこれほど嫌われるのか。核心は制御フローが予測不能になることにあります。アリアン5の事故も、値がオーバーフローしたこと自体ではなく、誰も計画していなかった未処理例外が発生したことが問題でした。安全が絶対のコードにとって、これは最悪の事態です。
興味深いのは、ストロヴストルップ自身は現代C++の例外処理を強く支持しており、例外のコストも十分に安いと考えている点です。それでもJSF標準が例外を排除した理由は、当時のツールの「成熟度」にありました。
(約20:46)"JSF++ is for hard real time and safety critical applications flight control software... if a computation takes too long somebody may die and for that reason we have to guarantee response times and we can't with the current level of tool support do that for exceptions."
JSF++はハードリアルタイムかつ安全が絶対のアプリケーション向けであり、計算が長引けば人が死ぬかもしれない。だから応答時間を保証する必要があるが、当時のツール支援のレベルでは例外についてそれを保証できなかった――というストロヴストルップ自身の説明です。
そのためJSF標準は、ツールが対応できる日に備えて例外を「シミュレート」する形を取っています。具体的な修正方法はリターンコードの利用です。非準拠版のコードにはtry/catchブロックやthrow文がありますが、これらはJSF標準では一切許されません。準拠版では計算結果に応じて異なる値を返すリターンコードを用い、その処理を呼び出し側の関数に委ねます。呼び出し側は受け取ったコードを見て対応を決められるため、プログラム全体が突然崩壊することがなくなります。計算が時間内に終わらなかったり空の値になったりしても、例外でクラッシュする代わりにエラーコードを返すだけで済むのです。
この「例外を書かない」という考え方は、現場のエンジニアにも妙な共感を呼んだようです。
"Wait so when I haven't bothered to implement any exception handling for the past 20 years I was actually correct?"
「待って、つまり20年間まともに例外処理を書いてこなかった俺は、実は正しかったってこと?」(@StuJohnsonNZ)
"turns out I've been writing JSF++ without realizing"
「知らないうちにJSF++を書いていたらしい」(@user-sb5vt8iy5q)
三本柱その2――再帰の禁止と循環的複雑度

次の柱はAVルール119で、関数が直接的にも間接的にも自分自身を呼び出してはならない、つまり再帰の禁止です。
再帰の問題はスタックオーバーフローの危険にあります。関数を呼び出すたびに新しいスタックフレームが積まれ、再帰ではフレームが次々と重なっていきます。しかも再帰は最大の深さの上限が分からないことが多く、どれだけメモリを使うかの上限を把握しなければならない安全クリティカルな領域では致命的です。
実演では、代替空港を計算する飛行計算の中で二項係数を求める関数が登場します。非準拠版では `binomialCoefficient(n-1, k-1)` と `binomialCoefficient(n, k-1)` のように自分自身を二度呼び出しており、最大深さが読めません。準拠版ではこれを反復(イテレーティブ)な実装に書き換えます。コードは長くなり見た目の美しさは失われますが、関数が自分自身を一切呼ばないためJSF準拠となります。
あわせてボーナスとして紹介されるのがAVルール3、関数の循環的複雑度(cyclomatic complexity)は20を超えてはならないという規則です。循環的複雑度とは関数内の判断経路の数で、if文・while/forループ・and/orといった論理演算・switch文などがすべてカウント対象になります。先ほどの反復版二項係数関数を例に、関数宣言で1、if文ごとに1、or演算で1、forループで1……と数えていき、その合計を20未満に収める必要がある、と実演します。
三本柱その3――メモリの「事前」割り当て

最後にして最も重要とされる柱が、AVルール206「初期化後にメモリの割り当ても解放も行ってはならない」です。プログラムが実行されている最中に動的にメモリを確保してはならない、ということです。
理由は二つあります。一つは予測不能性で、メモリマネージャが利用可能なメモリを見つけるのにどれだけ時間がかかるか分からないこと。もう一つはそもそも十分なメモリが残っているか分からないことです。さらにヒープへの割り当てを繰り返すと断片化(フラグメンテーション)が起き、小さく使えない領域が散らばって、大きな新規データが入らなくなる恐れもあります。
実演では、突風(gust)の計算に使う対気速度(IAS)の履歴データが題材になります。非準拠版ではユニークポインタを作って履歴バッファに返しており、これがヒープへ動的にメモリを確保してしまいます。準拠版での修正方法は複数ありますが、ここではIAS履歴配列の最大サイズをハードコードする方法が選ばれます。あらかじめ取り得る最大サイズが分かっているため、配列の全インデックスを使いつつ、動的な割り当てを一切行わずに計算を完結できます。動的な「未知」を完全に排除できるわけです。
安全クリティカルなソフトウェアの未来

JSF標準の原則は、この標準だけにとどまりませんでした。そのDNAはさまざまな分野・標準へと広がっています。
例えばNASAの飛行ソフトウェア標準「F-Prime」は2017年に公開され、メモリ割り当てなし・例外処理なし・再帰なしと、JSF標準の姉妹版とも言える内容になっています。航空宇宙以外でも、自動車業界には「MISRA」や「AutoSAR(automotive open system architecture)」があり、AutoSARはそのC++14標準の影響源としてJSFを名指しで挙げています。より新しいC++をベースとするAutoSARでは、スマートポインタのように旧JSF標準にはなかった機能も許容されています。車は今や車輪のついたコンピュータであり、BMW、フォード、トヨタといった主要メーカーがAutoSARに依存しています。つまりこうした言語の安全性は、数十年前にペンタゴンが下した決定の上に成り立っているのです。
業界をまたいだ広がりは視聴者の実体験とも響き合います。
"When I was lead programmer for a game studio in the early 2000's, our code rules for our PS2, GameCube and Xbox games were very similar to these. No exceptions, no memory allocation or deallocation after initialisation, and minimal recursion."
「2000年代初頭にゲームスタジオのリードプログラマだった頃、PS2・ゲームキューブ・Xbox向けのコード規約はこれとそっくりだった。例外なし、初期化後のメモリ割り当て/解放なし、再帰は最小限」――家庭用ゲーム機の世界でも同種の規律があったという証言です。(@slygamer01)
最後に語り手は大きな問いを投げかけます。あなたは自分のC++コードでJSF標準に従うべきなのか。ここでひねりが効いていて、C++の生みの親ストロヴストルップ自身は、JSF標準の策定に関わったにもかかわらず、今日では「C++ Core Guidelines」を使うべきだと言うだろう、と紹介されます。現代のC++はこの20年で進化し続けているからです。JSF標準は当時としては素晴らしい工学的偉業でしたが、今ならより新しく安全なC++を使うべきだということです。

それでもJSF標準は、歴史としても非常に重要で興味深く、C++という複雑な言語を、重要インフラに使えるほど予測可能で安全なものへと変えた点で一見の価値がある、と締めくくられます。
(約33:18)"It's not always just about being the smartest programmer in the room. It's about having the discipline of knowing what aspects to remove before flight."
大切なのは常に部屋で一番賢いプログラマであることではなく、何を「飛行前に取り外す」べきかを見極める規律を持つことだ。
視聴者の反応
本論とは直接関係しないものの、動画を盛り上げたコメントも数多く寄せられました。いずれも一般的な視聴者反応の一例です。
"If fighter jets ran everything in Javascript, they would need an extra engine just to power the CPU. 🤣"
「もし戦闘機が何もかもJavaScriptで動いていたら、CPUを回すためだけにエンジンをもう一基積む必要があるな」(@hgbugalou)
"The F-14's secret processor is what allowed it to enter the DANGER ZONE"
「F-14の秘密のプロセッサがあったからこそ、あの『デンジャー・ゾーン』へ入れたんだ」とトップガンになぞらえる声。(@badphoton)
"'I wonder if I could dip my wing in the water just, like, a little bit.' — Audio recovered from black box"
「『翼をちょっとだけ水に浸せないかな』――ブラックボックスから回収された音声」と、操縦実演をいじるジョーク。(@_zoid)
"9 million lines of code, all in main()"
「900万行のコード、全部 main() の中にあるんだろ」(@Kolor-Kode)
"Sentences like 'I am going to write flight certified code' and 'I have some weird multithread issues in Python' were not sentences I expected to come together."
「『飛行認証コードを書くぞ』と『Pythonでなんか変なマルチスレッド問題が出てる』が同じ動画で並ぶとは思わなかった」(@57thorns)
このほか、航空宇宙やADAの現場経験を語るベテランエンジニアたちのコメントや、語り手の知的で楽しげな語り口を称賛する声も目立ちました。
まとめ
この動画はアリアン5の事故という痛烈な教訓から出発し、F-4ファントムからF-35に至る飛行ソフトウェアの歴史、ペンタゴンでの言語戦争、そしてADAからC++への転換をたどりました。その核心にあるのが、C++から例外・再帰・実行時のメモリ割り当てを取り除き、循環的複雑度まで抑え込むことで予測可能性を確保するJSF++という考え方です。フライトシミュレーターと実コードを使った実演を通じて、準拠版と非準拠版の違いが具体的に示されました。
そしてその原則はNASAのF-Prime、自動車のMISRAやAutoSARへと受け継がれ、私たちの身近な技術の安全性を静かに支えています。安全クリティカルなソフトウェアで問われるのは、機能を足す賢さよりも「飛行前に何を取り外すか」を見極める規律である――それがこの動画を貫くメッセージです。
PR: エンジニア転職エージェント「テックゴー」

エンジニア転職エージェント「テックゴー」さんからのPRです。
こちらのリンクから無料の転職相談ができます。
テックゴーさんの特徴は三つあって
①面接対策を何度も実施できます!
普通のエージェントはそもそも模擬面接がなかったり回数が1回だけに制限されていたりしますが何度も練習できます。面接慣れしていると実績アピールしやすいのでいいですね。
②忙しい方向けに1Day選考会もやっています。
人気企業を集めた独占選考会をやっています。特に土曜日1日ですべての面接を完了できる1Day選考会が好評です。平日忙しいエンジニアの方におすすめです。
③高年収ポジションが豊富です。
コンサル業界・ハイクラス求人専門の転職エージェント「MyVision」と同じ運営会社なので高収入求人が豊富です。大きな案件に関わってみたい方・メガベンチャーのポジションを狙いたい方にもおすすめです。
まずはこちらのリンクから無料の転職相談をぜひやってみてください。
以上です。ではまた。
いいなと思ったら応援しよう!
サポートは動画制作費に使わせて頂きます。