Am besten ist es natürlich, wenn Fehler gar nicht erst entstehen. Doch die Wirklichkeit sieht anders aus. Aber wenn man potenzielle Fehlerquellen kennt, lässt sich schon im Vorfeld das Auftreten der wichtigsten Software-Fehler verhindern. Hier sind fünf Fehlerszenarien beschrieben – und was man dagegen tun kann.
Firmware-Fehler – jeder Entwickler kennt sie. Sie lauern in den Systemen und können katastrophale Folgewirkungen haben – besonders in sicherheitskritischen Systemen wie etwa Automobilen und Medizintechnik. Sie aufzudecken und zu beseitigen kann immense Schwierigkeiten bereiten. Erschwerend kommt hinzu, dass diese Fehler derart subtile Schäden am Code oder den Daten hervorrufen, dass das betreffende System zunächst noch problemlos oder weitestgehend normal zu arbeiten scheint, bevor sich die Fehlfunktion manifestiert.
Aus diesem Grund ist es wichtig, die Ursprünge gängiger Fehler zu kennen und zu verstehen, denn mit diesem Wissen ist bereits der erste Schritt zu ihrer Eliminierung getan. Der vorliegende Beitrag widmet sich einigen häufigen Grundursachen schwierig reproduzierbarer Firmware Bugs und beschreibt erprobte Abhilfemaßnahmen.
Stack-Überläufe
Jeder Programmierer weiß, dass ein Stack-Überlauf ein sehr gravierender Vorfall ist. Das Ausmaß des daraus entstehenden Schadens und der zeitliche Ablauf der daraus resultierenden Fehlfunktion hängen jedoch ganz allein davon ab, welche Daten oder Befehle betroffen sind und wie diese verwendet werden. Leider kommen Stack-Überläufe in Embedded-Systemen weit häufiger vor als in Desktop-Computern. Das hat mehrere Gründe:
Auch mit noch so gründlichen Tests lässt sich nicht gewährleisten, dass ein bestimmter Stack genügend groß ist. Man kann ein System zwar unter verschiedenen Auslastungsbedingungen testen, aber der Testzeitraum ist in jedem Fall begrenzt. Unter Anwendung algorithmischer Restriktionen (z.B. Ausschluss von Rekursionen) lässt sich mit einer Top-Down-Analyse des Programmablaufs durchaus nachweisen, dass es niemals zu einem Stack-Überlauf kommt. Allerdings muss dieser Nachweis nach jeder am Code vorgenommenen Änderung erneut geführt werden.
Abhilfe: Legen Sie nach dem Hochfahren ein wahrscheinlich nicht zufällig vorkommendes Datenmuster in allen Stacks ab. Der Autor verwendet gern das Muster 23 3D 3D 23 (hex), das in einem ASCII-Dump wie ein Zaun aussieht (#==#). Zur Laufzeit prüft man mit einer Überwachungs-Task periodisch, dass keines dieser Muster oberhalb einer vorgegebenen „Hochwassermarke“ geändert wurde. Zeichnen Sie etwaige Fehler (also welcher Stack betroffen ist und wie weit die Hochwassermarke überschritten wurde) in einem nichtflüchtigen Speicher auf und implementieren Sie entsprechende Schutzvorkehrungen für die Anwender (z. B. ein kontrolliertes Abschalten oder einen Reset).