Was passiert bei einem Laufzeitfehler?

17

Was passiert, wenn in einem Programm ein Laufzeitfehler auftritt? Wird die Ausführung des Programms einfach gestoppt? Kann ich das Arduino irgendwie dazu bringen, mir den Fehler zu erklären?

Der Typ mit dem Hut
quelle

Antworten:

21

Lassen Sie uns zunächst einige Beispiele dafür sehen, was schief gehen kann.

Nicht initialisierte lokale Variablen

void setup() {
  int status;
  pinMode(13, OUTPUT);
  digitalWrite(13, status);
} 

Wie von Edgar Bonet in den Kommentaren ausgeführt, werden lokale Variablen wie statusim obigen Code vom C ++ - Compiler nicht implizit initialisiert. Das Ergebnis des obigen Codes ist also unbestimmt. Um dies zu vermeiden, stellen Sie sicher, dass Sie Ihren lokalen Variablen immer Werte zuweisen.

Bei globalen und statischen Variablen sieht es etwas anders aus:

Globale und statische Variablen werden vom C-Standard garantiert auf 0 initialisiert.

Quelle: AVR Libc Referenzhandbuch - Häufig gestellte Fragen - Sollte ich nicht alle meine Variablen initialisieren?

Das heißt, Sie sollten sich keine Gedanken darüber machen, sie in Ihrem Code auf 0 zu initialisieren. In der Tat sollten Sie es wirklich vermeiden, da die Initialisierung Speicher verschwenden kann. Initialisieren Sie sie nur mit anderen Werten als 0.

Speicherüberlauf

int array[10];
int v = array[100];
array[-100] = 10;

Das erste Problem hier ist, dass Sie nicht wissen, was v zugewiesen wird, aber schlimmer ist, dass Sie nicht wissen, was Sie mit der Zuweisung zu Position -100 von falsch gemacht haben array.

Springe zu einer illegalen Anweisung

void doSomething( void ) { 
    for (int i = 0; i < 1000; i++); 
}

void setup () 
{
    void (*funcPtr)( void );

    funcPtr = &doSomething;
    funcPtr(); // calls doSomething();

    funcPtr = NULL;
    funcPtr(); // undefined behavior
}

Der erste Anruf an funcPtr()wird tatsächlich ein Anruf an sein doSomething(). Anrufe wie der zweite können zu undefiniertem Verhalten führen.

Andere schlechte Dinge, die passieren können

Zum Beispiel kann Ihnen der Arbeitsspeicher ausgehen. Was sonst. Ich denke auf jeden Fall, dass Ihr Programm weiterhin ausgeführt wird, wahrscheinlich nicht so, wie Sie es beabsichtigt haben.

Arten des Schutzes

In Computersystemen werden Probleme wie diese normalerweise auf verschiedenen Ebenen behandelt:

  1. Vom Compiler
  2. Durch die Programmiersprache Runtime (wie zum Beispiel in Java).
  3. Durch das Betriebssystem oder den Prozessor (wenn Ihr Speicher auf eine Position außerhalb der Grenzen des für Ihr Programm reservierten Adressraums zugreift, verfügt das Betriebssystem oder der Prozessor möglicherweise über Sicherheitsmechanismen, um dies zu verhindern)

Arduinos haben nur eingeschränkten Schutz für den Compiler und wahrscheinlich auch nichts anderes. Die gute Nachricht ist, dass sie nicht für mehrere Aufgaben eingesetzt werden. Das einzige betroffene Programm ist Ihr Programm. In jedem Fall führt einer dieser Fehler zu einem fehlerhaften Verhalten.

Die Antworten

Die Annahmen sind alle Probleme, die ich oben angegeben habe, sind Laufzeitprobleme.

Was passiert, wenn in einem Programm ein Laufzeitfehler auftritt?

Das Programm wird fortgesetzt und was passiert, hängt von den Nebenwirkungen des Laufzeitfehlers ab. Ein Aufruf des Nullfunktionszeigers lässt das Programm wahrscheinlich an eine unbekannte Stelle springen.

Wird die Ausführung des Programms einfach gestoppt?

Nein, es wird so weitergehen, als wäre nichts Außergewöhnliches passiert, wahrscheinlich tun, was Sie nicht beabsichtigt hatten. Es kann sich zurücksetzen oder unregelmäßig handeln. Es kann einige Eingänge in Ausgänge verwandeln und einen oder zwei Sensoren verbrennen (aber das ist höchst unwahrscheinlich ).

Gibt es eine Möglichkeit, dass der Arduino mir sagt, was der Fehler ist?

Ich glaube nicht. Wie ich bereits sagte, sind die Schutzmechanismen nicht vorhanden. Es gibt keine Laufzeitunterstützung durch die Sprache, kein Betriebssystem, keine Hardwareprüfungen auf Speicherzugriff außerhalb der Grenzen (der Bootloader zählt auch nicht dazu). Sie müssen nur vorsichtig mit Ihrem Programm sein und wahrscheinlich Ihre eigenen Sicherheitsnetze einrichten.

Der Grund für den fehlenden Schutz liegt wahrscheinlich darin, dass Arduino-Controller zu billig sind, zu wenig Arbeitsspeicher haben und nichts zu Wichtiges ausführen sollten (ja, es scheint einen Haftungsausschluss von AVR zu geben, damit Sie die normalerweise von AVR verwendeten MCUs nicht verwenden können Arduino in Lebenserhaltungssystemen).

Ricardo
quelle
1
Groß! Die beste Antwort, die ich bisher auf Arduino.SE gesehen habe!
Der Kerl mit dem Hut
1
Vielen Dank!! Ich denke, wir sollten uns bemühen, so viele gute Antworten wie möglich zu geben. Aber es beunruhigt mich ein wenig, dass wir nicht so viele REAL EE EXPERTS haben, die auf Antworten wie meine schauen und eklatante Fehler finden könnten. Eigentlich ist das der Grund, warum ich die Antwort gepostet habe, obwohl ich nicht so viel über AVR-MCUs weiß. Das ist zu sehen, ob wir jemanden dazu bringen, das zu korrigieren. Wir wollen sicher nicht, dass kluge Pents wie ich Dinge sagen, die nicht stimmen und damit durchkommen. Aber das ist wahrscheinlich eine Diskussion für die Meta-Site.
Ricardo
5
@ Ricardo - Ein Kommentar, den ich machen würde, ist, dass nicht explizit initialisierte Variablen nicht unbedingt nicht initialisiert sind . Variablen, die außerhalb von Funktionen definiert sind, haben im Allgemeinen die sogenannte "automatische Speicherdauer", die dann standardmäßig auf Null initialisiert wird. Weitere Informationen finden Sie unter de.cppreference.com/w/cpp/language/default_initialization . Das Initialisierungsverhalten ist so komplex, dass es wahrscheinlich gefährlich ist, sich darauf zu verlassen, aber es ist wahrscheinlich keine gute Idee , pauschale Aussagen zu treffen.
Connor Wolf
1
Darüber hinaus wird der SRAM auf 0 bei Reset oder Start initialisiert, so dass Sie machen können einige informierte Vermutungen über nicht initialisierten Variablen, wenn Sie gefährlich leben wollen. Sie sollten nicht vertrauen auf dieses Verhalten, aber es ist interessant.
Connor Wolf
1
Hier finden Sie ein interessantes Beispiel dafür, was passiert, wenn Sie keinen SRAM mehr haben: electronics.stackexchange.com/questions/42049/… . Grundsätzlich blockiert der Stapel einen Teil des Haufens oder umgekehrt. Dies kann interessante Dinge bewirken, z. B. einen Teil des Stack-Frames beschädigen (Rückgabewerte für Breaking-Funktionen usw.) oder ungültige Daten in Variablen schreiben.
Connor Wolf
9

Es gibt keine Laufzeitausnahmen. Es gibt nur undefiniertes Verhalten.

Wirklich, es gibt keine Ausnahmen überhaupt . Wenn Sie versuchen, einen ungültigen Vorgang auszuführen, sind die Ergebnisse unbekannt.

Es gibt überhaupt keine Laufzeitüberprüfung, außer dem, was Sie implementieren. Ihr Programm läuft auf Bare-Metal-Hardware. Es ist das Desktop-Äquivalent zu Ring-0 , da der ATmega keine Ringe hat .

Connor Wolf
quelle
6

Es gibt einen Mechanismus, mit dem die MCU aus dem fehlerhaften Zustand gebracht werden kann, und es handelt sich um den Watchdog-Timer . Wenn Sie Code implementieren, der wiederholt in einer Schleife ausgeführt wird und der nicht länger als eine festgelegte Zeit ausgeführt wird, können Sie diese Zeit als Überwachungszeitraum festlegen und den Timer aktivieren.

Dann müssen Sie den Timer in der Schleife wiederholt zurücksetzen. Wenn Ihr Code in einer Bedingungsschleife einfriert, die niemals endet, zählt der Watchdog auf Null und setzt schließlich die MCU zurück.

Auf diese Weise verlieren Sie Daten, aber wenn Sie den AVR WDT im Interrupt-Modus ausführen, können Sie einige Daten speichern, bevor Sie die MCU zurücksetzen.

So kann der Watchdog-Timer Ihren Code vor gelegentlichen unbeabsichtigten Endlosschleifen schützen.

Dokumentation: AVR132: Verwenden des erweiterten Watchdog-Timers

nio
quelle
5

Sie benötigen einen Hardware-Debugger für so etwas. In der Regel verhält sich das Programm jedoch nicht so, wie Sie es erwarten, und Sie müssen sich diesen Codeabschnitt ansehen, um das Problem zu identifizieren.

Eine übliche / schnelle / einfache Möglichkeit, dies zu tun, besteht darin, print-Anweisungen hinzuzufügen, um die Werte von Variablen oder irgendetwas anderem auszudrucken, damit Sie wissen, dass das Programm problemlos an diesen Punkt im Code gelangt. Auf diese Weise können Sie das Problem weiter eingrenzen.

Ich glaube, VisualMicro hat einige Debugging-Funktionen eingebaut.

Sachleen
quelle
3

Ich würde annehmen, dass die AVR-CPU keine Fehlererkennungs- oder Wiederherstellungstools hat. Es kann einfach aufhören oder den Fehler und die Konsequenzen ignorieren. Wie Sachleen sagte, sollten Sie einige Debug-Anweisungen in Ihr Programm einfügen, die Daten während eines Vorgangs ausdrucken, um zu testen, ob sie funktionieren. Wenn Sie ein Emulaor verwenden und Haltepunkte setzen, können Sie leicht ein Problem finden.

Der Doktor
quelle
-2

Das Arduino wird neu gestartet (dh es wird neu gestartet setup()und loop()).

user28739
quelle
1
Nicht unbedingt. Ein Laufzeitfehler kann dazu führen, dass das Programm ohne Neustart in eine Schleife übergeht.
Nick Gammon