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
8 yorum
Askerî amaçlı olduğu için, düşük donanım özellikleri ile gelişmiş özellikler arasında denge kurmanın sonucu olarak C++ seçilmiş olabilir diye düşünüyorum.
gnat-llvmda mevcut. Açık kaynaklı IDE de sunuluyor.Öğrenciler ve geliştiriciler bunu Savunma Bakanlığı dili olduğu ve talebi az olduğu için öğrenmedi; araçlar pahalı olduğu için değil diye düşünüyorum.
Genel olarak öngörülebilir kod yazma teknikleriyle ilgili bir içerik gibi görünüyor.
C++ sadece örnek olarak ele alınmış olsa da, GC gibi diğer dillerde daha da sorunlu olabilen kısımlar da aynı şekilde geçerli; bu noktanın sanki C++’ın sınırlarını tartışıyormuş gibi anlaşılabilmesi üzücü.
Eğer C++’ın dinamik bellek tahsisi ya da istisna işleme teknikleri kullanılmayacaksa, o zaman C kullanarak yukarıdaki ilkelerle yazmanın çok daha kolay ve hızlı olup olmayacağı sorusu akılda kalıyor.
Aynen, neden C yerine C++ kullanıldığını ben de bilmiyorum.
Modern C++ gerçekten oldukça güvenli, ancak ille de C++ olmak zorunda değilse daha güvenli başka bir dili değerlendirmek mantıklı olabilir diye düşünüyorum.
RUST sözdizimini STRICT şekilde kullanalım!
Hacker News görüşü
142 sayfalık bu belge, gerçek uçak yazılımı geliştirmede ne tür kısıtlar olduğunu gösteriyor
Yine de “shall” kurallarının istisnaları merak uyandırıyor. Bu ölçekte projelerde istisna durumları, standardın ne kadar işe yaradığını gösterir
2005 için makul olabilir ama bugün yapay zeka tabanlı dronlar gibi ortamlarda bunun nasıl uygulandığını merak ediyorum
Özellikle
stdio.hyasağı ilk başta garip geliyor ama okuyunca “evet, mantıklı” dedirtiyora = a;gibi ifadeleri hatırlatıyorKullanılmayan parametreleri kaldırmamak için yapılan bir numara ama bu tür kuralların iyi kod kalitesini gerçekten garanti edip etmediği tartışmalı
JSF yönergeleri 2005 tarihli olduğu için dönemin sınırlarını taşıyor
Bjarne Stroustrup'un yakın zamanda “C++ profilleri” kavramını ortaya atmış olması da ilginç
Sonuçta bu tür stil kılavuzları bir ölçüde estetik tercih meselesi olabilir
(void)a;kullanmaktırAsıl güvenliği sağlayan şey tasarım kalitesi ve fail-safe yapıdır
_ = a;ile açıkça ifade ediliyorİlgili issue da var
Daha çok inceleme sırasında başvurulacak ortak bir ölçüt sağlarlar
Buradaki temel konu görev güvencesi (mission assurance)
Stack veya heap kullanılırsa değişkenlerin bellekteki adresleri değişebilir; belirli bir hücre arızalanırsa bu sorun yaratır
Tüm değişkenlerin sabit adresleri olursa, arızalı hücreyi yalnızca yamayla taşıyıp görevi sürdürmek mümkün olabilir
Yerel değişkenler, parametreler, dönüş adresleri sonuçta stack gerektirir
Özyineleme de imkânsız hâle gelir, geçici değişkenler de kısıtlanır
Bu yüzden bu iddia gerçekçi görünmüyor
Stack ve heap'in adres aralıkları sabitlenebilir ama bunun gerçekten ikna edici bir gerekçe olup olmadığından emin değilim
Ben de benzer şekilde “bu durum asla yaşanmamalı” gibi log kayıtları bırakıyorum
Büyük sistemlerde bu tür istisna durum kaydı, hata ayıklamada çok faydalı oluyor
Tüm durumların açıkça ele alınmasını zorunlu kılıyor; enum'a yeni bir değer eklenirse derleyici uyarı veriyor
_STOPveya_CRASHmakroları da ekleyip anında debug kesmesi yaptırıyorumSorunu hemen düzeltmeye zorlaması açısından etkili oluyor
Özeti, “Ada geliştiricisi ve toolchain azdı” şeklindeydi
Ama bugün dil çeşitliliğine açıklık daha fazla olduğu için Ada'nın daha çok kabul görebileceğini düşünüyorum
NVidia'nın SPARK'ı benimsemesi de Ada'nın yeniden canlanmasının işareti gibi görünüyor
DoD Ada'yı zorunlu kılsaydı üniversiteler ve şirketler de buna uyum sağlardı
Sonuçta dil öğrenilebilir ve Ada kullanılsaydı F-35'in güvenilirliği de daha yüksek olabilirdi
AdaCore, GHS, PTC ApexAda, DDC-I, Irvine, OC Systems, RR Software
Geçmişte Ada derleyicileri ücretli bir seçenekti ve C/C++ varsayılan olarak geliyordu; bu yüzden okullar ve şirketler C++'ı seçti
AdaCore, ISO standardizasyonuna ve açık kaynağın yaygınlaşmasına büyük katkı sağladı
Eskiden gereğinden fazla eleştiriliyordu ama bugün daha cazip görünüyor
Dosya yapısı ve build flag'leri karmaşıktı, ayrıca RedMonk dil sıralamasında da Ada yoktu
Bazı özellikleri ilginçti ama Rust gibi modern bir dil deneyimi sunmuyordu
DO-178C gibi sertifikasyon çerçeveleri önemli
Hatta bu, yüksek güvenilirlikli kod üretmenin doğru yolu bile olabilir
Tersine mühendislik, obfuscation, compiler gibi çeşitli konuları işliyor
insan bunun bile ayrıca yazılması gerekiyor mu diye düşünüyor
LM'nin kendi geliştirdiği bir şey mi, yoksa ticari bir ürün mü bilmek isterdim