30 points par GN⁺ 2025-12-09 | Aucun commentaire pour le moment. | Partager sur WhatsApp
  • Une vidéo expliquant pourquoi les logiciels de chasse et de fusées, où une seule ligne de bug peut avoir des conséquences fatales à Mach 1, éliminent la plupart des fonctionnalités du C++ pour ne conserver qu’un code prévisible
  • Un retour sur l’histoire qui a conduit à exiger un langage de sûreté unique et des normes strictes : calculateur de bombardement mécanique du F-4, microprocesseur non public du F-14, guerre des langages militaires allant de Jovial·CMS-2·Ada, et explosion du volume de code
  • Une démonstration, avec du vrai code, de la manière dont la norme JSF C++ créée lorsque Lockheed a convaincu d’utiliser le C++ au lieu d’Ada pendant le développement du F-35 interdit les exceptions, la récursion et l’allocation mémoire dynamique, et les remplace par des codes de retour, des boucles itératives et de la mémoire préallouée
  • Une comparaison, en connectant X-Plane 12 à un MFD maison, entre du code qui enfreint les règles JSF et du code conforme, afin de montrer comment le comportement diffère réellement en vol, avec en toile de fond le fait que les premiers calculateurs de mission du F-35 utilisaient une architecture de la famille PowerPC
  • Une conclusion selon laquelle l’héritage de la norme JSF s’est prolongé dans des standards de sûreté comme NASA F-Prime·MISRA·AutoSAR, mais qu’aujourd’hui il serait plus approprié de s’appuyer sur les C++ Core Guidelines et le C++ moderne

Présentation de l’intervenant

  • Un développeur ayant écrit du code C++ pour des systèmes aérospatiaux et réalisé des démonstrations pour l’armée de l’air
    • L’explication s’appuie sur une expérience concrète de l’usage du C++ dans des systèmes aux exigences de sûreté élevées
    • L’environnement de démonstration repose sur un MFD (écran multifonction) fabriqué maison, composé de X-Plane 12, d’une API web, d’une interface Python et d’un backend C++

Logiciels de vol et environnements où l’échec n’est pas permis

  • Dans une application classique, un crash se résout par un redémarrage, mais pour un avion de combat à Mach 1 ou une fusée, un seul échec peut devenir une catastrophe
    • La formule « À Mach 1, on n’a pas le temps d’attendre le garbage collector » illustre l’exigence de temps réel
    • Quand une seule ligne de code erronée peut avoir des conséquences fatales, le simple choix des fonctionnalités du langage doit lui-même servir de dispositif de sûreté
  • L’explosion d’Ariane 5 en 1996 est présentée comme cas emblématique
    • Une exception s’est produite lors de la conversion d’une valeur en virgule flottante 64 bits représentant un biais horizontal en entier 16 bits, et cette exception n’a pas pu être traitée
    • Le langage a bien signalé l’erreur conformément à la spécification, mais le système n’a pas pu la gérer, ce qui a conduit à la destruction immédiate d’une fusée de 500 millions de dollars
  • À partir de ce cas, l’équipe de conception du F-35 a choisi une approche consistant à retrancher directement des fonctionnalités du langage afin d’éviter de répéter la même erreur

Histoire du logiciel militaire et guerre des langages

  • À l’époque des premiers chasseurs comme le F-4 Phantom, il n’y avait pratiquement pas de logiciel
    • Le calculateur de bombardement ressemblait davantage à un mécanisme de précision composé d’engrenages et de cames, et le « code » était en réalité la forme même des cames métalliques
  • La situation change avec le projet secret d’avion de supériorité aérienne de la Navy, le VFX (F-14 Tomcat)
    • On a révélé bien plus tard que Garrett AiResearch avait conçu un microprocesseur pour le F-14 avant même l’Intel 4004, souvent présenté dans les manuels comme le « premier microprocesseur »
    • Pour contrôler de façon optimale l’aile à géométrie variable du F-14, un microprocesseur haute performance était nécessaire, avec environ 2 500 lignes de microcode chargées pour effectuer des calculs polynomiaux
  • Ensuite, chaque armée a adopté son propre langage, lançant une prolifération des langages
    • L’armée de l’air utilisait Jovial (Jules Own Version of the International Algorithmic Language), de la famille ALGOL
    • La Navy, refusant d’utiliser le langage de l’Air Force, a adopté CMS-2 pour le F-18
    • Avec des langages et des architectures matérielles différents, la réutilisation du code et sa vérification devenaient presque impossibles
  • Parallèlement, la taille des logiciels embarqués par avion a augmenté de façon exponentielle
    • Des chiffres sont cités : environ 125 000 lignes pour le F-16A, environ 1 million pour le B-1, et environ 9 millions pour le F-35 moderne
    • Une enquête du département de la Défense indiquait que plus de 450 langages de programmation étaient utilisés, et que très peu disposaient de véritables standards

L’imposition d’Ada et ses limites

  • Pour résoudre cette dispersion, le département de la Défense a créé un langage unique de haut niveau, Ada, et en a imposé fortement l’usage
    • Pour ne pas utiliser Ada dans un nouveau projet, il fallait prouver pourquoi c’était impossible avec Ada ; sans cela, il était impossible de remporter le contrat
  • Ada est présenté comme un langage très adapté aux domaines où la sûreté et la fiabilité sont essentielles
    • Sa conception mettait l’accent sur les garanties de sûreté mémoire et de sûreté des types, cruciales dans des systèmes critiques comme l’aérospatial
  • Mais dans les années 1990, un décalage avec la réalité a commencé à apparaître
    • Dans le même temps, Internet, Windows 95 et les jeux commerciaux basés sur C++ s’imposaient
    • Les étudiants et développeurs se sont naturellement tournés vers GCC gratuit et le C++, plutôt que vers des compilateurs Ada coûteux
    • Les compilateurs Ada coûtaient plusieurs milliers de dollars et restaient difficiles d’accès pour les particuliers, ce qui a réduit le vivier de spécialistes Ada

Le F-35 et la naissance de la norme JSF C++

  • Le F-35 (Joint Strike Fighter) a été conçu dès le départ comme un appareil où le logiciel occupe une place majeure
    • Des calculs complexes comme la fusion de capteurs (sensor fusion) sont devenus centraux dans l’exploitation de l’appareil
  • Lockheed Martin a proposé au département de la Défense d’autoriser l’usage du C++ pour répondre à ces besoins
    • Cela revenait de fait à demander un assouplissement de la politique imposant Ada, et il fallait pour cela montrer comment maîtriser les risques du C++
  • Il est mentionné que le créateur du C++, Bjarne Stroustrup, a lui aussi participé comme conseiller à la conception des règles JSF C++
    • Il a déclaré avoir directement contribué à la rédaction des règles JSF, tout en reconnaissant lui-même qu’il pouvait donc avoir un certain biais à l’égard de cette norme
  • L’idée centrale rappelle les étiquettes « remove before flight »
    • De la même façon que ces étiquettes doivent être retirées avant le vol, il s’agit ici de retirer au niveau du langage les fonctionnalités jugées dangereuses afin de ne conserver qu’un sous-ensemble prévisible
    • Cela permettait de viser un niveau de sûreté comparable à Ada tout en laissant aux développeurs une partie de la puissance expressive du C++

Matériel réel et analogie avec la GameCube

  • Les premiers blocs du F-35 utilisaient un calculateur de mission basé sur un processeur Motorola G4 PowerPC
    • Cette information a notamment été rendue publique dans un article d’Aviation Today de 2003
  • La GameCube utilisant elle aussi un processeur de la famille PowerPC, l’analogie est intéressante : il s’agit de matériels d’une génération comparable au niveau du jeu d’instructions
    • Pour une correspondance générationnelle plus précise, une autre console serait plus proche, mais l’analogie avec la GameCube suffit pour comprendre le principe

Environnement de démonstration JSF C++ : X-Plane 12 + MFD

  • Un environnement de simulation de vol est mis en place à partir de X-Plane 12 avec l’addon F-35B d’AOA Simulations
    • La nouvelle API web de X-Plane permet de s’abonner aux données de vol en temps réel pour les afficher sur le MFD
  • Le frontend est réalisé en Python, tandis que le backend est un plugin C++, utilisé pour comparer en démonstration du code conforme ou non aux règles JSF
    • L’altitude, la vitesse, le vent, l’enveloppe de vol, les données de navigation et d’autres informations sont affichées à partir des calculs effectués en C++
  • En vol, l’intervenant exécute volontairement du code C++ non standard qui lance une exception, montre que le MFD tombe et que cela perturbe le vol, puis illustre étape par étape comment l’application des règles JSF corrige la situation

Les trois contraintes clés de JSF : exceptions, récursion, mémoire dynamique

  • Les trois contraintes majeures mises en avant par la norme JSF C++ sont les exceptions, la récursion et l’allocation mémoire dynamique
    • À cela s’ajoute une limite supérieure sur la complexité cyclomatique (Cyclomatic Complexity) des fonctions

1) Interdiction des exceptions – AV Rule 208

  • JSF AV Rule 208 : « les exceptions ne doivent pas être utilisées (exceptions shall not be used) »
    • Les mots-clés liés aux exceptions, comme try, catch et throw, sont totalement interdits
  • La raison principale tient à la non-déterminisme du flux de contrôle
    • Comme avec Ariane 5, si une exception survient et que son traitement est omis ou mal synchronisé, l’ensemble du système peut s’effondrer de manière imprévisible
  • Bjarne est favorable à la gestion des exceptions en C++ moderne, mais explique qu’au moment de la conception de JSF, la maturité des outils et les garanties de temps réel ne permettaient pas de les prendre en charge

    « JSF++ est destiné aux applications hard real-time et safety-critical (contrôle de vol) ; si un calcul prend trop de temps, quelqu’un peut mourir, et les exceptions ne permettent pas de garantir les temps de réponse. »

  • Dans JSF, on utilise à la place des exceptions des codes de retour (return code)
    • Dans l’exemple de calcul de l’altitude-densité (density altitude), un code de retour distinct est défini pour chaque situation d’erreur, puis interprété par l’appelant
    • Même en cas d’échec du calcul ou de dépassement de temps, le programme entier ne s’arrête pas, et l’appelant peut représenter l’« état d’erreur » de manière sûre

2) Interdiction de la récursion – AV Rule 119

  • L’AV Rule 119 interdit à une fonction de s’appeler elle-même directement ou indirectement, autrement dit la récursion
    • Chaque appel récursif ajoute une nouvelle frame de pile, et comme la profondeur maximale est difficile à borner, le risque de stack overflow augmente
  • L’exemple donné est celui du coefficient binomial (binomial coefficient) utilisé lors du calcul d’un aéroport de dégagement dans la planification de vol
    • La version non conforme utilise une implémentation récursive de la forme C(n, k) = C(n-1, k-1) + C(n-1, k)
    • Comme la profondeur d’appel varie selon les entrées, il devient difficile de prédire la borne supérieure de mémoire
  • La version conforme JSF remplace ce calcul par une implémentation itérative basée sur des boucles
    • Le code est plus long et moins élégant, mais comme il ne s’appelle pas lui-même, il fournit le même résultat sans récursion
    • Il devient alors beaucoup plus simple de raisonner statiquement sur la profondeur d’appel et la borne supérieure d’utilisation mémoire

3) Interdiction de l’allocation mémoire dynamique – AV Rule 206

  • AV Rule 206 : après l’initialisation, aucune allocation ni libération mémoire n’est autorisée
    • Les allocations sur le tas en cours d’exécution, via new, delete ou même un new interne déclenché par des smart pointers, sont interdites
  • Deux problèmes principaux motivent cette règle
    • Les allocations sur le tas introduisent un non-déterminisme temporel : on ne sait pas combien de temps elles prendront
    • Si le tas se fragmente (fragmentation), une allocation peut échouer faute de bloc contigu suffisamment grand, même si la capacité totale restante est suffisante
  • Comme exemple, l’intervenant montre du code non conforme qui crée un buffer d’historique IAS (vitesse indiquée) pour le calcul des rafales à l’aide de std::unique_ptr et d’un tableau dynamique
    • Le code alloue un nouveau tableau à l’exécution, ce qui viole les règles JSF
  • La version conforme JSF utilise à la place un tableau de taille fixe, dont la taille maximale est définie comme constante
    • Une constante telle que MAX_IAS_HISTORY est définie, la mémoire n’est réservée qu’une seule fois à l’initialisation, puis seuls les index tournent
    • Ainsi, aucune allocation supplémentaire ne se produit pendant l’exécution, ce qui garantit une meilleure prévisibilité temporelle et mémoire

4) Limite de complexité cyclomatique – AV Rule 3

  • L’AV Rule 3 impose que la complexité cyclomatique (Cyclomatic Complexity) d’une fonction ne dépasse pas 20
    • La déclaration de la fonction vaut 1 point, puis chaque if, while, for, switch, ainsi que les opérateurs logiques AND/OR, ajoute 1 point de complexité
  • Avec l’implémentation itérative du coefficient binomial, il est montré comment chaque if, opération logique ou boucle for fait augmenter ce score
    • Plus la complexité est élevée, plus les tests, la vérification et l’analyse deviennent difficiles ; l’objectif de la norme est donc de la maintenir sous une certaine limite

Héritage JSF : NASA F-Prime, MISRA, AutoSAR

  • Les idées de la norme JSF C++ se sont ensuite diffusées dans d’autres domaines critiques pour la sûreté
    • Le framework logiciel de vol de la NASA, F-Prime, publié en 2017, reprend des règles comme l’interdiction de l’allocation mémoire dynamique, des exceptions et de la récursion
  • Une évolution comparable s’est produite dans l’industrie automobile
    • Des standards comme MISRA C++ et AutoSAR (Automotive Open System Architecture) ont défini des règles de sûreté pour le logiciel automobile
    • Il est indiqué que le guide AutoSAR C++14 cite explicitement JSF comme référence, montrant que son influence s’est étendue jusqu’au logiciel automobile
  • La voiture moderne étant pratiquement un « ordinateur sur roues », ces sous-ensembles de langage et règles de codage constituent un socle essentiel de la sûreté

Conclusion : quelle référence suivre si l’on utilise C++ aujourd’hui ?

  • La norme JSF C++ est présentée, pour son époque, comme une réussite d’ingénierie ayant réduit un langage complexe à un sous-ensemble prévisible afin d’atteindre un niveau de sûreté compatible avec le contrôle de vol d’un avion de combat
  • En parallèle, Bjarne Stroustrup recommande aujourd’hui aux développeurs de suivre les C++ Core Guidelines et le C++ moderne
    • Le langage C++ et sa toolchain ont considérablement progressé au fil des décennies, et il existe désormais bien davantage de conditions permettant d’utiliser en sécurité des fonctionnalités comme les exceptions ou les smart pointers
  • Malgré cela, JSF reste un exemple important d’une manière de contrôler un langage non pas en ajoutant, mais en retirant
    • Le message final est que, dans la conception de systèmes critiques pour la sûreté, l’essentiel n’est pas seulement de décider quoi ajouter, mais de déterminer quoi inscrire sur la liste remove before flight

Aucun commentaire pour le moment.

Aucun commentaire pour le moment.