NASAs 10 essenzielle Coding-Regeln für sicherheitskritische Software
Warum Coding-Standards?
Große, komplexe Softwareprojekte nutzen Coding-Standards. Diese legen Grundregeln fest:
- a) Code-Struktur
- b) Sprachfeatures (erlaubt/verboten)
Effektiv = kleine, spezifische, leicht verständliche & merkbare Regelwerk.
NASA-Top-Programmierer (Jet Propulsion Laboratory, JPL) folgen Sicherheitskritik-Regeln. Fokus auf C: umfangreiche Tool-Unterstützung (Logic Model Extractors, Debugger, stabile Compiler, starke Static Analyzer, Metrik-Tools).
Kritisch dort, wo Menschenleben von Korrektheit & Effizienz abhängen: Flugzeug-, Raumfahrt-, AKW-Steuerung.
NASAs 10 Regeln (Gerard J. Holzmann, JPL Lead Scientist)
Fokus: Sicherheitsparameter. Auf andere Sprachen übertragbar.
Regel 1 – Einfacher Kontrollfluss
Programme mit sehr einfachem Control Flow. Verboten: setjmp/longjmp, goto, direkte/indirekte Rekursion.
Grund: Klarheit, stärkere Verifizierbarkeit. Ohne Rekursion: kein zyklischer Call-Graph → alle Ausführungen, die begrenzt sein sollen, sind es auch.
Regel 2 – Feste Obergrenze für Schleifen
Alle Loops müssen statisch beweisbare feste Obergrenze haben. Verification-Tool muss beweisen können: Iterationszahl kann Preset-Bound nicht überschreiten.
Regelverletzung, wenn Loop-Bound nicht statisch beweisbar.
Grund: Loop-Bounds + No-Recursion → keine Runaway-Code. Ausnahme: nicht-terminierende Iterationen (z.B. Process Scheduler) → Reverse Rule: statisch beweisbar, dass Iteration NICHT terminieren kann.
Regel 3 – Keine dynamische Speicherallokation nach Initialisierung
Kein malloc etc. nach Init.
Grund: Allokatoren/GCs: unvorhersehbares Verhalten → Performance-Impact. Programmierfehler: Überallokation, Forget-to-free, Use-after-free, Buffer-Overrun. Fix: Fester, vorallozierter Speicherbereich pro Modul → Probleme eliminiert, Speichernutzung verifizierbar. Alternative: Stack-Memory.
Regel 4 – Keine großen Funktionen
Funktion ≤ 1 Seite Papier (Standard-Referenzformat, 1 Zeile/Declaration, 1 Zeile/Statement) → max. ~60 Zeilen.
Grund: Lange Funktionen = schlechte Struktur. Jede Funktion = logische Einheit, verständlich & verifizierbar. Mehrere Bildschirme = schwer erfassbar.
Regel 5 – Mindest-Assertion-Dichte
Ø ≥ 2 Assertions pro Funktion. Assertions = Boolean-Tests für Zustände, die in Realität nie auftreten dürfen. Fehlschlag → explizite Recovery-Aktion.
Static Checker beweist: Assertion kann nie fehlschlagen / nie gelten → Regelverletzung.
Grund: Industry Stats: Unit Tests fangen ≥1 Defekt pro 10–100 LOC. Höhere Assertion-Dichte → mehr Defekt-Abfang. Defensive Coding: Pre/Post-Conditions, Parameter/Return-Values, Loop-Invariants. Assertions nach Performance-Tests selektiv deaktivierbar.
Regel 6 – Datenobjekte auf kleinstmöglichem Scope deklarieren
Prinzip Data Hiding. Alle Objekte im kleinstmöglichen Scope deklarieren.
Grund: Außerhalb Scope: Wert nicht referenzierbar/korrumpierbar. Verhindert Wiederverwendung von Variablen für inkompatible Zwecke → komplizierte Fehlersuche.
Regel 7 – Parameter & Return Values prüfen
Return-Values non-void Functions: von jeder aufrufenden Funktion prüfen. Parameter-Validität: in jeder Funktion prüfen.
Streng: Selbst printf/close Return-Values prüfen.
Grund: Wenn Error-Response = Success-Response, muss Return-Value explizit geprüft werden (oft bei close/printf). Expliziter Cast zu void = bewusste Entscheidung, Return zu ignorieren (nicht versehentlich).
Regel 8 – Eingeschränkte Präprozessor-Nutzung
Präprozessor nur für: Header-Includes & Makro-Definitionen. Rekursive Makros, Token-Pasting, Variable-Argument-Listen verboten.
Mehr als 1–2 Conditional-Compilation-Directives (außer Standard-Boilerplate gegen Mehrfach-Include) müssen begründet & von Tool geflaggt werden.
Grund: C-Präprozessor = mächtig & mehrdeutig → zerstört Code-Klarheit, verwirrt Text-Checker. Unbounded Präprozessor-Code = extrem schwer zu entschlüsseln. Conditional Compilation: 10 Directives → 1024 (2¹⁰) Code-Versionen → Testaufwand explodiert.
Regel 9 – Eingeschränkte Zeiger-Nutzung
Max. 1 Ebene Dereferenzierung. Pointer-Dereferenzierung nicht in typedef oder Makros verstecken. Funktionszeiger verboten.
Grund: Zeiger leicht missbrauchbar (auch von Experten). Erschweren Data-Flow-Analyse (besonders Tool-based Static Analysis). Funktionszeiger beschränken Static-Analyzer-Checks. Nur bei starker Begründung. Wenn genutzt: Alternative Methoden für Rekursionsfreiheits-Beweis nötig.
Regel 10 – Allen Code kompilieren (ab Tag 1)
Ab Entwicklungstag 1: Kompilierung mit maximaler Compiler-Warnstufe. Ohne Warnungen durchlaufen.
Täglich Check mit ≥1 State-of-the-Art Static Source Code Analyzer. Zero Warnings.
Grund: Viele effektive Analyzer (teils Freeware). Keine Ausrede, sie nicht zu nutzen. Wenn Compiler/Analyzer verwirrt: Code umschreiben → trivial valid.
Quellen: NASA JPL, Gerard J. Holzmann
Industrietechnik
- Kritische Temperaturen elementarer und Hochtemperatur-Supraleiter (Kelvin)
- Wichtige Ableitungsregeln: Kurze Referenz
- Fundamentale Integrationsregeln: Konstanten, Summen und Differenzen
- BigStitcher: Präzise 3D-Gewebebildgebung für riesige Mikroskopie-Datensätze
- Eine sicherere Zukunft bauen: Fortschritt bei intelligenten Lebensmittelsicherheitslösungen
- Warum Flottenmodernisierung Kosten senkt und Nachhaltigkeit fördert
- Jenseits des Codings: Schlüsselkompetenzen für erfolgreiche Automatisierungsprojekte
- UID-Compliance meistern: 3 wesentliche Regeln für DoD-Lieferanten
- 4 bewährte Strategien für effektive Instandhaltungs-Checklisten
- Umfassende Sicherheitsprotokolle für Arbeiter und Techniker entwickeln