Friedrich-Alexander-Universität Erlangen-Nürnberg  /   Technische Fakultät  /   Department Informatik

Übungen zu BS - Typische Fehler (WS 2015/16)


Warum stürzt der Rechner immer ab?

Zu große Variabelen (Stacks!)

Symptome

Euer Programm stürzt irgendwann ab, liefert einen “unexpected interrupt”, bootet den Rechner oder erzeugt andere unerwünschte Ergebnisse. Möglicherweise tritt der Fehler nicht auf, wenn ihr irgendwo scheinbar belanglose Anweisungen einfügt, einen Anwendungsprozess mehr oder weniger erzeugt usw.

Ursache

Ihr legt zu große lokale Variablen in main () oder in einem eurer Anwendungsprozesse an.

Erläterung

Das Hauptprogramm main () von OOStuBS bekommt von uns bei der Systeminitialisierung einen Stack der Größe 4 KB zugewiesen (siehe Startup-Code in startup.asm). Zum Anlegen kleiner lokaler Variablen ist das vollkommen ausreichend, nicht aber, um die Anwendungsprozesse mit eigenen Stacks zu versorgen.

Das folgende Stück Code ist also falsch!

int main () {
    char stack [4096];
    Application appl (stack+4096);
    ...
}

Hier werden auf dem initialen Stack ein 4 KB großes Feld und ein Application-Objekt angelegt, was zusammengenommen bereits größer als die verfügbaren 4 KB ist. Da aber OOStuBS keine Überprüfun der Stackgrenzen vornimmt und auch sonst keine Schutzkonzepte implementiert1, wird mit den lokalen Variablen Speicher überschrieben, der main() überhaupt nicht zur Verfügung steht. Das Ergebnis ist, dass globale Variablen wie z. B. die Interrupt-Vektortabelle überschrieben werden. Das kann unbemerkt bleiben, z. B. wenn nur Interruptvektoren zerstört werden, die nie benötigt werden, es kann aber auch zu Abstürzen oder anderen Fehlern führen. Das passiert insbesondere dann, wenn ihr entweder euren eigenen Code überschreibt oder wenn durch den Fehler unsinnige Werte als Adressen von Funktionen interpretiert werden.

Lösung

Legt große Variablen wie die Stacks der Anwendungsprozesse immer global an. Dann sorgt nämlich der Compiler dafür, dass der Speicherplatz für sie zur Verfügung steht. Wer will, kann das Schlüsselwort static verwenden, um anzuzeigen, dass die entsprechende Variable nur in der Datei referenziert werden soll, in der sie deklariert wurde.

static char stack [4096];

int main () {
    Application appl (stack+4096);
    ...
}

Außerdem müsst ihr aufpassen, dass ihr den Zeiger auf das obere Ende des Stacks (“top of stack”) übergebt, ansonsten wird es wieder zu ungewünschtem Verhalten kommen.


  1. In der Veranstaltung Betriebssystemtechnik werden dann räumliche Schutzkonzepte und Privilegienumschaltung erläutert und implementiert.