F-35’te kullanılan C++ standardı - Bir savaş uçağı neden C++ özelliklerinin %90’ını yasaklar
(youtube.com)- Mach 1 hızında tek satırlık bir hata ölümcül sonuçlara yol açabilen savaş uçağı ve roket yazılımlarında, neden C++ özelliklerinin çoğunun çıkarılıp yalnızca öngörülebilir kodun bırakıldığını anlatan bir video
- F-4’ün mekanik bombardıman bilgisayarından, kamuya açık olmayan F-14 mikroişlemcisine; Jovial·CMS-2·Ada ile süren askerî dil savaşlarına ve kod patlamasına kadar, neden tek bir güvenli dil ve katı standartların gerekli hâle geldiğinin tarihini özetliyor
- F-35 geliştirme sürecinde Lockheed’in Ada yerine C++ kullanımını kabul ettirmek için oluşturduğu JSF C++ standardının, istisnaları, özyinelemeyi ve dinamik bellek ayırmayı yasaklayıp bunların yerine dönüş kodları, döngüler ve önceden ayrılmış bellek kullanmasını gerçek kod örnekleriyle gösteriyor
- İlk F-35 görev bilgisayarlarının PowerPC ailesi mimarisi kullandığını da aktararak, X-Plane 12 ile kendi yaptığı MFD’yi bağlayıp JSF kurallarını ihlal eden kod ile kurallara uyan kodun uçuş sırasında pratikte nasıl farklı davrandığını karşılaştırıyor
- JSF standardının daha sonra NASA F-Prime·MISRA·AutoSAR gibi güvenlik standartlarına uzandığını, bugün ise bu mirasın üzerinde C++ Core Guidelines ve modern C++ kullanımının daha uygun bir yön olduğunu savunuyor
Konuşmacı hakkında
- Havacılık ve uzay sistemleri için C++ kodu yazarken hava kuvvetlerine yönelik demolar yapmış deneyime sahip bir geliştirici
- Açıklamayı, güvenlik gereksinimleri yüksek sistemlerde C++ kullanmış gerçek deneyimine dayanarak yapıyor
- Demo ortamı olarak X-Plane 12, web API’si, Python UI ve C++ backend’den oluşan kendi geliştirdiği MFD’yi (çok işlevli ekran) kullanıyor
Uçuş yazılımı ve hatanın kabul edilmediği ortamlar
- Genel uygulamalarda çökme yeniden başlatmayla atlatılabilirken, Mach 1 savaş uçakları ve roketlerde tek bir başarısızlık doğrudan felakete dönüşebilir
- “Mach 1’de çöp toplayıcıyı bekleyecek zaman yoktur” sözüyle gerçek zamanlılık gereksinimini vurguluyor
- Tek satırlık yanlış kodun ölümcül sonuca gidebildiği bir ortamda, dil özelliklerinin seçimi başlı başına bir güvenlik önlemi olmak zorunda
- Temel örnek olarak 1996’daki Ariane 5 patlaması veriliyor
- Yatay bias’a ait 64 bit kayan nokta değerinin 16 bit tam sayıya dönüştürülmesi sırasında bir istisna oluştu ve bu istisna işlenemedi
- Dil, tanımı gereği hatayı üretti; ancak sistem bu istisnayı ele alamayınca 500 milyon dolarlık roket anında imha oldu
- F-35 tasarım ekibi bu olayı referans alarak aynı hatayı tekrarlamamak için dil özelliklerini baştan kesip atma yaklaşımını benimsedi
Askerî yazılımın tarihi ve dil savaşları
- Erken dönem savaş uçaklarında, özellikle F-4 Phantom zamanında, fiilen yazılım yoktu
- Bombardıman bilgisayarı dişli ve kamlardan oluşan hassas bir mekanik düzeneğe daha yakındı; “kod” ise metal kamın şeklinin kendisiydi
- Gizli bir proje olan deniz kuvvetleri hava üstünlük uçağı VFX (F-14 Tomcat) ile tablo değişti
- Ders kitaplarında “ilk mikroişlemci” olarak bilinen Intel 4004’ten önce, Garrett AiResearch’ün F-14 için bir mikroişlemci tasarladığı gerçeği sonradan ortaya çıktı
- F-14’ün değişken geometrili kanadını en iyi şekilde kontrol etmek için yüksek performanslı bir mikroişlemci gerekiyordu; buna yaklaşık 2500 satırlık mikrokod yüklenerek polinom hesapları yaptırıldı
- Sonrasında her kuvvetin farklı diller benimsemesiyle dil karmaşası başladı
- Hava kuvvetleri, ALGOL ailesinden gelen Jovial (Jules Own Version of the International Algorithmic Language) dilini kullandı
- Deniz kuvvetleri, hava kuvvetlerinin dilini kullanmamak için F-18’de CMS-2yi seçti
- Farklı diller ve donanım mimarileri kullanıldığı için kodun yeniden kullanımı ve doğrulanması neredeyse imkânsız hâle geldi
- Aynı dönemde uçak başına yazılım boyutu üstel olarak arttı
- F-16A’da yaklaşık 125 bin satır, B-1’de yaklaşık 1 milyon satır, modern F-35’te ise yaklaşık 9 milyon satır seviyesine çıktığı örneklerle anlatılıyor
- Savunma Bakanlığı araştırmasında 450’den fazla programlama dili kullanıldığı ve bunların çok azının düzgün standarda sahip olduğu raporlandı
Ada zorunluluğu ve sınırları
- Bu dağınıklığı çözmek için Savunma Bakanlığı tek bir yüksek seviyeli dil olan Adayı oluşturdu ve güçlü bir kullanım zorunluluğu getirdi
- Yeni projede Ada kullanmamak isteyenlerin “neden Ada ile yapılamadığını” kanıtlaması gerekiyordu; aksi hâlde sözleşme almak mümkün değildi
- Ada, güvenlik ve güvenilirliğin kritik olduğu alanlar için son derece uygun bir dil olarak tanıtıldı
- Havacılık ve uzay gibi emniyet kritik sistemlerde bellek ve tür güvenliğini sağlama amacı öne çıkıyordu
- Ancak 1990’larda gerçek dünyadan kopukluk görünür olmaya başladı
- Bir yanda internet, Windows 95 ve C++ tabanlı ticari oyunlar ana akımı oluşturuyordu
- Öğrenciler ve geliştiriciler, pahalı Ada derleyicileri yerine doğal olarak ücretsiz GCC ve C++ tarafına yöneldi
- Ada derleyicileri binlerce dolara mal olduğu için bireysel erişim zordu; bunun sonucu olarak Ada uzmanı insan kaynağı da daraldı
F-35 ve JSF C++ standardının doğuşu
- F-35 (Joint Strike Fighter) en baştan itibaren yazılım ağırlığı çok yüksek bir platform olarak tasarlandı
- Sensör füzyonu gibi karmaşık hesaplamalar, platformun işletiminin merkezine yerleşti
- Lockheed Martin bu ihtiyaçlar için Savunma Bakanlığına C++ kullanımına izin verilmesini önerdi
- Bu, mevcut Ada zorunluluğunun fiilen gevşetilmesini istemek anlamına geliyordu; bunun kabulü için C++ risklerini kontrol etme yöntemi göstermek gerekiyordu
- Bu süreçte C++’ın yaratıcısı Bjarne Stroustrup da danışman olarak yer aldı ve JSF C++ kurallarının tasarımına katkıda bulundu
- JSF kurallarının yazımına doğrudan destek verdiğini söyleyerek, bu standart konusunda kendisinin de “önyargılı olabileceğini” belirtiyor
- Temel fikir, “remove before flight” etiketine benziyor
- Uçuştan önce sökülmesi gereken etiketler gibi, C++ içindeki riskli özellikler de dil seviyesinde çıkarılıyor ve yalnızca öngörülebilir bir alt küme kullanılıyor
- Böylece Ada düzeyinde güvenlik sağlanırken geliştiriciler de C++’ın ifade gücünden belirli ölçüde yararlanabiliyor
Gerçek donanım ve GameCube benzetmesi
- Erken dönem F-35 blokları, Motorola G4 PowerPC işlemci tabanlı görev bilgisayarları kullanıyordu
- Bu bilgi, 2003 tarihli Aviation Today makalesi gibi kaynaklarda yayımlanmıştı
- GameCube da PowerPC ailesinden bir işlemci kullandığı için, komut kümesi düzeyinde benzer nesil bir donanım olması bakımından ilginç bir karşılaştırma sunuyor
- Daha kesin nesil eşleşmesi için başka konsollar daha yakın olabilir; ancak prensibi anlamak için GameCube benzetmesi yeterli
JSF C++ demo ortamı: X-Plane 12 + MFD
- X-Plane 12 tabanında F-35B eklentisi (AOA Simulations) kullanılarak bir uçuş simülatörü ortamı kuruluyor
- X-Plane’in yeni web API’si üzerinden gerçek zamanlı uçuş verileri abone olunup MFD’de gösteriliyor
- Frontend Python ile kurulmuş, backend ise C++ eklentisi olarak yazılmış; böylece JSF kurallarına uyan ve uymayan kodlar karşılaştırmalı olarak gösteriliyor
- İrtifa, hız, rüzgâr, uçuş zarfı ve navigasyon verileri gibi çeşitli bilgiler C++ hesaplamalarının çıktıları olarak ekrana veriliyor
- Uçuş sırasında kasıtlı olarak istisna fırlatan standart dışı C++ kodu çalıştırılıp MFD’nin çökmesi ve uçuşta sorun çıkması gösteriliyor; ardından JSF kuralları uygulanarak bunun nasıl düzeltildiği adım adım anlatılıyor
JSF’nin üç temel kısıtı: istisna, özyineleme, dinamik bellek
- JSF C++ standardında vurgulanan üç ana kısıt istisna (Exception), özyineleme (Recursion) ve dinamik bellek ayırma
- Buna ek olarak fonksiyonlar için Cyclomatic Complexity (dallanma karmaşıklığı) üst sınırı da tanımlanıyor
1) İstisna yasağı – AV Rule 208
- JSF AV Rule 208: “İstisnalar kullanılmaz (exceptions shall not be used)”
try,catch,throwgibi istisna anahtar sözcükleri tamamen yasaklanıyor
- Temel gerekçe kontrol akışındaki belirlenimsizlik
- Ariane 5 örneğinde olduğu gibi, istisna oluştuğunda işleme eksik kalır ya da zamanlama kayarsa tüm sistem öngörülemez şekilde çökebilir
- Bjarne modern C++ istisna işleme modeline olumlu baksa da, JSF tasarlandığı dönemde araç olgunluğu ve gerçek zaman garantisi nedenleriyle istisna desteğinin uygun olmadığını açıklıyor
“JSF++, sert gerçek zamanlı ve emniyet kritik uygulamalar (uçuş kontrolü) içindir; hesaplama çok uzun sürerse insanlar ölebilir ve istisnalarla yanıt süresi garanti edilemez”
- JSF’de istisna yerine dönüş kodları (return code) kullanılıyor
- Yoğunluk irtifası hesaplama örneğinde, her hata durumu için farklı dönüş kodları atanıyor ve çağıran taraf bunları yorumlayıp işliyor
- Böylece hesap başarısız olsa ya da zaman aşımına uğrasa bile tüm program çökmeden, çağıran taraf güvenli biçimde bir “hata durumu” ifade edebiliyor
2) Özyineleme yasağı – AV Rule 119
- AV Rule 119, bir fonksiyonun doğrudan ya da dolaylı olarak kendini çağırmasını, yani özyinelemeyi yasaklıyor
- Her özyinelemeli çağrıda yeni bir stack frame oluştuğu ve azami derinliği bilmek zor olduğu için stack overflow riski büyüyor
- Örnek olarak, uçuş planındaki alternatif havaalanı hesabında kullanılan binom katsayısı (binomial coefficient) veriliyor
- Standart dışı sürümde
C(n, k) = C(n-1, k-1) + C(n-1, k)biçiminde özyinelemeli uygulama kullanılıyor - Bu yapı, çağrı derinliğinin girdiye göre değişmesine yol açtığı için bellek üst sınırını öngörmeyi zorlaştırıyor
- Standart dışı sürümde
- JSF uyumlu sürümde aynı hesap döngü temelli yinelemeli (iterative) bir uygulamaya çevriliyor
- Kod daha uzun ve daha az zarif olsa da, kendini çağırmadığı için özyineleme olmadan aynı sonucu veriyor
- Böylece fonksiyon çağrı derinliği ve bellek kullanım üst sınırı statik olarak daha kolay çıkarılabiliyor
3) Dinamik bellek ayırma yasağı – AV Rule 206
- AV Rule 206: Başlatmadan sonra bellek ayırma ve serbest bırakma yapılmaz
- Çalışma sırasında
new,deleteya da akıllı işaretçiler üzerinden yapılan dahilinewgibi heap ayırmaları yasak
- Çalışma sırasında
- Bunun iki temel nedeni var
- Heap ayırmada ne kadar süreceği bilinmeyen bir zaman belirlenimsizliği bulunur
- Heap parçalanırsa (fragmentation), toplam kapasite kalsa bile yeterince büyük bitişik blok bulunamadığı için ayırma başarısız olabilir
- Örnek olarak, rüzgâr hamlesi (gust) hesabı için IAS (gösterilen hava hızı) geçmiş tamponunu
std::unique_ptr+ dinamik diziyle kuran standart dışı kod gösteriliyor- Çalışma sırasında yeni dizi ayırdığı için JSF kurallarını ihlal ediyor
- JSF uyumlu sürümde ise azami boyutu sabitle tanımlanmış sabit boyutlu dizi kullanılıyor
MAX_IAS_HISTORYgibi bir sabit tanımlanıp başlatma sırasında bellek bir kez ayrılıyor, sonrasında yalnızca indeks döndürülerek kullanılıyor- Böylece çalışma anında ek ayırma yapılmadığından zaman ve bellek açısından öngörülebilirlik korunuyor
4) Cyclomatic Complexity üst sınırı – AV Rule 3
- AV Rule 3, bir fonksiyonun Cyclomatic Complexity’sinin (dallanma karmaşıklığı) 20’yi geçmemesini şart koşuyor
- Fonksiyon bildiriminin kendisi 1 puan,
if·while·for·switch·mantıksal AND/OR gibi yapılar ise karmaşıklığa birer puan ekliyor
- Fonksiyon bildiriminin kendisi 1 puan,
- Binom katsayısının yinelemeli uygulaması örneğinde, her
if, mantıksal işlem vefordöngüsünün karmaşıklık puanını nasıl artırdığı gösteriliyor- Karmaşıklık arttıkça test, doğrulama ve analiz zorlaştığı için standardın hedefi bunu belirli bir eşik altında tutmak
JSF mirası: NASA F-Prime, MISRA, AutoSAR
- JSF C++ standardının fikirleri daha sonra başka emniyet kritik alanlara yayıldı
- NASA’nın uçuş yazılımı çatısı F-Prime 2017’de açıklandı ve dinamik bellek ayırma yasağı, istisna yasağı, özyineleme yasağı gibi kuralları paylaşıyor
- Otomotiv sektöründe de benzer bir çizgi sürdü
- MISRA C++ ve AutoSAR (Automotive Open System Architecture) gibi standartlar ortaya çıkarak otomotiv yazılımı için güvenlik kuralları tanımladı
- AutoSAR C++14 kılavuzunun JSF’ye açıkça atıf yaptığı belirtiliyor; bu da JSF etkisinin otomotiv yazılımına kadar uzandığını gösteriyor
- Modern otomobiller fiilen “tekerlekli bilgisayarlar” hâline geldiği için, bu tür dil alt kümeleri ve kodlama kuralları güvenliğin temel dayanağı oluyor
Sonuç: Bugün C++ kullanacaksak neyi izlemeliyiz
- JSF C++ standardı, kendi döneminde karmaşık bir dili öngörülebilir bir alt kümeye indirerek savaş uçağı uçuş kontrolü seviyesinde güvenlik sağlayan bir mühendislik başarısı olarak sunuluyor
- Aynı zamanda Bjarne Stroustrup, günümüz geliştiricilerine C++ Core Guidelines ve modern C++ yaklaşımını izlemelerini öneriyor
- Çünkü C++ dili ve araç zinciri son on yıllarda gelişti; istisnalar ve akıllı işaretçiler gibi özelliklerin de güvenli kullanılabildiği pek çok ortam oluştu
- Buna rağmen JSF, hâlâ dili ekleme ile değil “çıkarma” yoluyla kontrol etme zihniyetinin önemli bir örneği olarak kalıyor
- Kapanış mesajı şu: güvenlik kritik sistem tasarımında asıl mesele neyi ekleyeceğinden çok, neleri remove before flight listesine koyacağındır
Henüz yorum yok.