Es mag nur ein Zufall sein, aber ich habe festgestellt, dass die von mir verwendeten Mikrocontroller neu gestartet wurden, als ihnen der Arbeitsspeicher ausgegangen war (Atmega 328, wenn hardwarespezifisch). Ist es das, was Mikrocontroller tun, wenn ihnen der Speicher ausgeht? Wenn nicht, was passiert dann?
Warum wie? Der Stapelzeiger wird zwar blind auf einen nicht zugewiesenen Speicherbereich erhöht (oder überschrieben), aber was passiert dann: Gibt es einen Schutz, der einen Neustart bewirkt, oder ist dies (unter anderem) das Ergebnis des Überschreibens von Kritisch Daten (von denen ich annehme, dass sie sich von dem Code unterscheiden, von dem ich denke, dass er direkt von Flash ausgeführt wird)?
Ich bin mir nicht sicher, ob dies hier oder auf Stack Overflow sein soll. Bitte teilen Sie mir mit, ob dies verschoben werden soll, obwohl ich mir ziemlich sicher bin, dass Hardware eine Rolle dabei spielt.
Aktualisieren
Ich möchte darauf hinweisen, dass mich der eigentliche Mechanismus der Speicherbeschädigung besonders interessiert (ist er das Ergebnis des SP-Rollover -> hängt das von der Speicherzuordnung in den USA ab usw.).
quelle
Antworten:
In der Regel stoßen Stapel und Haufen zusammen. An diesem Punkt wird alles chaotisch.
Abhängig von der MCU kann (oder wird) eines von mehreren Dingen passieren.
Wenn etwas passiert, wird es merkwürdig - Dinge, die nicht das tun, was sie sollten. Wenn 2 passiert, bricht die Hölle los. Wenn die Rücksendeadresse auf dem Stapel (falls vorhanden) beschädigt ist, kann niemand raten, wohin der aktuelle Anruf zurückkehren wird. Zu diesem Zeitpunkt wird die MCU im Grunde genommen anfangen, zufällige Dinge zu tun. Wenn 3 wieder passiert, wer weiß schon, was passieren würde. Dies geschieht nur, wenn Sie Code außerhalb des Arbeitsspeichers ausführen.
Wenn der Stapel beschädigt wird, ist er im Allgemeinen vorbei. Was passiert, hängt von der MCU ab.
Möglicherweise schlägt der Versuch, den Speicher zuzuweisen, fehl, sodass die Beschädigung nicht auftritt. In diesem Fall kann die MCU eine Ausnahme auslösen. Wenn kein Ausnahmehandler installiert ist, wird die MCU in den meisten Fällen einfach angehalten (entspricht
while (1);
. Wenn ein Handler installiert ist, wird sie möglicherweise sauber neu gestartet.Wenn die Speicherzuweisung fortgesetzt wird oder wenn sie versucht, fehlschlägt und einfach ohne zugewiesenen Speicher fortgesetzt wird, befinden Sie sich im Bereich "Wer weiß?". Die MCU startet sich möglicherweise durch die richtige Kombination von Ereignissen neu (Unterbrechungen, die dazu geführt haben, dass der Chip zurückgesetzt wurde usw.), aber es gibt keine Garantie dafür, dass dies geschieht.
Normalerweise besteht eine hohe Wahrscheinlichkeit, dass ein Fehler auftritt. Ist dies jedoch aktiviert, läuft der interne Watchdog-Timer (sofern vorhanden) ab und startet den Chip neu. Wenn das Programm durch diese Art von Absturz vollständig ABGELAUFEN ist, werden die Anweisungen zum Zurücksetzen des Timers im Allgemeinen nicht ausgeführt, sodass eine Zeitüberschreitung und ein Zurücksetzen auftreten.
quelle
Eine alternative Sichtweise: Mikrocontrollern geht der Speicher nicht aus.
Zumindest nicht, wenn es richtig programmiert ist. Das Programmieren eines Mikrocontrollers ist nicht mit dem Programmieren für allgemeine Zwecke vergleichbar. Um dies richtig zu tun, müssen Sie sich seiner Einschränkungen bewusst sein und entsprechend programmieren. Dafür gibt es Tools. Suchen Sie sie heraus und lernen Sie sie - zumindest, wie Sie Linker-Skripte und Warnungen lesen.
Wie Majenko und andere sagen, kann ein schlecht programmierter Mikrocontroller zu wenig Speicher haben und dann irgendetwas tun, einschließlich einer Endlosschleife (die dem Watchdog-Timer zumindest die Möglichkeit gibt, ihn zurückzusetzen. Sie haben den Watchdog-Timer aktiviert, nicht wahr? )
Gemeinsame Programmierregeln für Mikrocontroller vermeiden dies: Beispielsweise wird der gesamte Speicher entweder auf dem Stapel oder statisch (global) zugewiesen. "new" oder "malloc" sind verboten. Dies gilt auch für die Rekursion, sodass die maximale Tiefe der Unterprogrammverschachtelung analysiert und so angezeigt werden kann, dass sie in den verfügbaren Stapel passt.
Auf diese Weise kann der maximal erforderliche Speicherplatz berechnet werden, wenn das Programm kompiliert oder verknüpft wird, und mit der Speichergröße (häufig im Linker-Skript codiert) für den bestimmten Prozessor verglichen werden, den Sie als Ziel festlegen.
Der Mikrocontroller verfügt dann möglicherweise nicht über genügend Arbeitsspeicher, Ihr Programm jedoch möglicherweise. Und in diesem Fall kommen Sie zu
Ein allgemeines Regelwerk für die Mikrocontroller-Programmierung ist MISRA-C , das von der Automobilindustrie übernommen wurde.
Aus meiner Sicht wird empfohlen, die Teilmenge SPARK-2014 von Ada zu verwenden. Ada zielt tatsächlich ziemlich gut auf kleine Steuerungen wie AVR, MSP430 und ARM Cortex ab und bietet von Natur aus ein besseres Modell für die Mikrocontroller-Programmierung als C. SPARK fügt dem Programm jedoch Anmerkungen in Form von Kommentaren hinzu, die beschreiben, was das Programm tut.
Jetzt analysieren die SPARK-Tools das Programm, einschließlich dieser Anmerkungen, und beweisen Eigenschaften darüber (oder melden potenzielle Fehler). Sie müssen weder Zeit noch Codeplatz für fehlerhafte Speicherzugriffe oder Integer-Überläufe verschwenden, da sich herausgestellt hat, dass dies niemals der Fall ist.
Obwohl SPARK mehr Vorarbeit leistet, kann es erfahrungsgemäß schneller und billiger zu einem Produkt kommen, da Sie keine Zeit damit verbringen, mysteriöse Neustarts und andere seltsame Verhaltensweisen zu verfolgen.
Ein Vergleich von MISRA-C und SPARK
quelle
malloc()
(und es ist C ++ - Begleiternew
) auf den AVR ist eines der schlimmsten Dinge, die die Arduino-Leute hätten tun können, und hat zu vielen, vielen sehr verwirrten Programmierern mit kaputten Codes sowohl in ihrem Forum als auch beim Austausch von Arduino-Stapeln geführt. Es gibt sehr, sehr wenige Situationen, in denen die Verwendungmalloc
eines ATmega von Vorteil ist.Majenkos Antwort gefällt mir sehr gut und ich habe sie selbst getippt. Aber ich möchte das auf den Punkt bringen:
Alles kann passieren, wenn ein Mikrocontroller keinen Speicher mehr hat.
Man kann sich wirklich nicht auf irgendetwas verlassen, wenn es passiert. Wenn der Stapelspeicher des Computers knapp wird, wird der Stapel höchstwahrscheinlich beschädigt. Und so kann alles passieren. Variable Werte, Überläufe und temporäre Register werden alle beschädigt und stören den Programmfluss. If / then / elses kann falsch auswerten. Rücksprungadressen sind verstümmelt und das Programm springt zu zufälligen Adressen. Jeder Code, den Sie in das Programm geschrieben haben, kann ausgeführt werden. (Betrachten Sie Code wie: "if [condition] then {fire_all_missiles ();}"). Auch eine ganze Reihe von Anweisungen, die Sie nicht geschrieben haben , können ausgeführt werden, wenn der Core an einen nicht verbundenen Speicherort springt. Alle Wetten sind aus.
quelle
AVR hat den Vektor auf die Adresse Null zurückgesetzt. Wenn Sie den Stapel mit zufälligem Müll überschreiben, werden Sie eventuell eine Schleife durchführen und eine Rücksprungadresse überschreiben, die auf "nirgendwo" verweist. Wenn Sie dann von einer Unterroutine zu diesem Nirgendwo zurückkehren, führt die Ausführung eine Schleife zur Adresse 0 durch, wo sich normalerweise ein Sprung zum Zurücksetzen des Handlers befindet.
quelle