Was ist der genaue Unterschied zwischen Stack und Heap? Im Bezug auf C und Pointer... ich habe den Unterschied immer noch nicht ganz verstanden, und Wikipedia verwirrt auch nur. Danke!
Das eine wird automatisch verwaltet und enthält alle die lokalen (pro Funktion) Daten, die nicht in Registern gehalten werden können. Außerdem werden bei Unterprogrammaufrufen dort Werte gesichert, die vom Unterprogramm zerstört werden könnten. Heap enthält die Datenbereiche, die mit malloc() angefordert wurden.
Um es einfach zu machen würde ich sagen man kann es so umschreiben: Der Stack enthält alles was der Linker an Speicher zuweist. Heap ist das was zur Laufzeit zugewiesen wird, z.B. siehe oben (malloc) Falls wer Einwende hat nur her damit :P
Kevin M. schrieb: > Der Stack enthält alles was der Linker an Speicher zuweist. Nein, das verwechselst Du mit BSS/DATA.
Kevin M. schrieb: > Heap ist das was zur Laufzeit zugewiesen wird, z.B. siehe oben (malloc) Stack wird auch "zur Laufzeit zugewiesen", nur eben implizit, nicht explizit wie bei malloc().
Stack und Heap sind streng genommen Implementationsdetails des Compilers. Auf C-Ebene haben die Begriffe erst mal keine Bedeutung. Dort gibt es drei Arten von Objektlebensdauer, nämlich statisch, automatisch und dynamisch. Statische Objekte existieren über die gesamte Programmlebensdauer, automatische Objekte bis zum Ende des Blocks, in dem sie definiert sind und dynamische so lange, bis man sie manuell wieder freigibt. Stack und Heap sind nun zwei Bereiche im Speicher. Ein weiterer ist das schon erwähnte BSS- und DATA-Segment. Üblicherweise werden die automatischen Objekte auf den Stack oder in Register gelegt und die dynamischen auf den Heap. Die statischen Objekte landen je nach Initialisierungswert in BSS oder DATA.
Im Heap wir der Speicher allokiert der mit malloc() angefordert wird. Dort wird also der dynamische Speicher angelegt. Das wurde bereits erwähnt. Auf den Stack landen z.B. Rücksprungadressen und werden Inhalte des Status Registers gesichert wenn eine Funktion aufgerufen oder ein Interrupt ausgelöst wird.
Der Stack ist ein Hardwarepointer im Prozessor und zeigt immer ins RAM. Jeder Prozessor hat min. einen. Er tritt z.B. bei IRQs in Aktion und speichert u.a. die Rücksprungadr. , damit am Ende der IRQSUB an der alten Stelle im Prog. weiter gemacht wird. Was der Heap ist und was er macht und wozu er gut ist habe ich auch nie verstanden.
Über den Stack können aber auch Funktionen Rückgabewert an den Aufrufenden zurückgeben. Oder es können der aufgerufen Funktion Parameter übergeben werden. Das hängt aber alles von der Implementation des Compilers ab. Gerade für Rückgabewerte ist es, je nach Plattform/Comppiler, auch üblich Register zu verwenden.
Das schöne am Stack ist, dass er nicht fragmentieren kann. Man packt Daten oben drauf, und nimmt sie in der selben Reihenfolge auch wieder davon weg. Das ist grossartig um Daten, die während eines Funktionsaufrufs gebraucht werden, zu speichern, weil wenn Funktion A Funktion B aufruft, muss Funktion B erst mal fertig sein, bevor Funktion A weiter machen und fertig werden kann, Funktion B kann also die Daten, die sie während ihrer Ausführung braucht auf den Stack legen, und wenn sie fertig ist, wieder wegnehmen (oder das Funktion A überlassen). Funktion B kann dabei vorher auch noch etwas für Funktion A auf dem Stack lassen. Nun gibt es aber halt Situationen, wo das nicht ausreicht. Konkret, wenn man grössere Datenmengen hat, die man nicht herumkopieren will, und man will die in Funktion B zurück geben, oder wenn sonstige Funktionen die Daten eventuell später noch brauchen, man die also nicht einfach vom Stack wegräumen oder darauf verschieben kann/will. Dafür braucht man dann eine Datenstruktur, wo man die Daten nicht gleich wieder wegräumen muss, sondern man die in beliebiger Reihenfolge reservieren und freigeben kann. Dafür nutzt man dann den Heap. Als Beispiel, wenn ich global eine Liste von Katzenbildern habe, und eine Funktion, die alle Anzeigt, dann kann ich in der Funktion, wo ich Katzenbilder erstelle & hinzufüge diese nicht auf den Stack legen, weil das ja noch da sein muss, wenn ich die Bilder später mit der anderen Funktion auflisten will. Die Parameter, die ich zum Erstellen der Bilder brauche (Katzenfarbe, Grösse, etc.), und alle temporären dafür angelegten Daten, brauche ich aber nur während dem Funktionsaufruf zum erstellen des Bildes, und nachher nicht mehr. Ich kann diese also einfach auf den Stack legen.
Im Normalfall muss man sich um die Verwaltung des Stacks/Stackinhalts nicht kümmern. Das sollte der Compiler allein können.
Walter L. schrieb: > Ich kenne keinen Prozessor, der keinen Stack als Hardwarepointer imple. > hat. Und was ist zum Beispiel mit einem Register welches "SP" heisst in manchen Prozessoren und auf den Stackbereich zeigt?
Walter L. schrieb: > Ich kenne keinen Prozessor, der keinen Stack als Hardwarepointer imple. > hat. Es gibt kleine Mikrocontroller, deren Return-Stack nicht im RAM liegt, sondern in wenigen speziellen und nicht anderweitig sichtbaren Registern. Wird Rekursion nicht zugelassen oder nicht genutzt, ist ein Stack im RAM unnötig. Andere Architekturen definieren per Hardware keinen Stack, sondern speichern die Return-Adresse in einem normalen sichtbaren Register. Es bleibt dann dem Programm überlassen, was es damit macht. Bei den AVRs gibt es mindestens eine Programmier-Umgebung, die Return- und Daten-Stack trennt. Der Hardware-SP ist dann nur für Return-Adressen zuständig, nicht für diesem Thread gemeinte Daten. Die Implementierung eines von C genutzten Stacks kann in solchen Umgebungen u.U. eine reine Konvention des ABI sein, u.U. ohne besonderem Support durch die Hardware auskommend.
:
Bearbeitet durch User
Ist es richtig, dass wenn ich "Heap" benutzen will, ich per Softwaere selber tätig werden muss (malloc();)? Oder, welche Standardprogramme in C (z. B. wie printf()) benutzen/legen einen Heap an?
Walter L. schrieb: > Ist es richtig, dass wenn ich "Heap" benutzen will, ich per Softwaere > selber tätig werden muss (malloc();)? Ja, was auch immer für dich "die Software" ist. ;-) > Oder, welche Standardprogramme in C (z. B. wie printf()) benutzen/legen > einen Heap an? printf() "legt" keinen "Heap an", aber übliche stdio-Implementierungen greifen ihrerseits selbst auf malloc() zurück, um Datenpuffer für die Ein-/Ausgabe zu bekommen.
(prx) A. K. schrieb: > Bei den AVRs gibt es mindestens eine Programmier-Umgebung, die Return- > und Daten-Stack trennt. IAR, wenn ich mich recht entsinne.
900ss D. schrieb: > Walter L. schrieb: >> Ich kenne keinen Prozessor, der keinen Stack als Hardwarepointer imple. >> hat. > > Und was ist zum Beispiel mit einem Register welches "SP" heisst in > manchen Prozessoren und auf den Stackbereich zeigt? upps, ich habe mich verlesen. Statt "keinen" hatte ich "einen" Stack als Hardwarepointer hat :)
Walter L. schrieb: > Was der Heap ist und was er macht und wozu er gut ist habe ich auch nie > verstanden. Der Heap ist ein spezieller Speicherbereich im RAM. Aus diesen kann man sich mit Hilfe der Funktion malloc() Speicher in verschiedener Größe ausborgen und ihn, wenn nicht mehr benötigt, mit der Funktion free() zurück geben.
1 | ptr = malloc(size); |
2 | .....
|
3 | ......
|
4 | free(ptr); |
Da nicht nur ein Speicher "gleichzeitig" ausgeborgt und freigegeben werden kann, kann sich der Heap fragmentieren. Das heißt, freier und benutzer Speicher sind nicht sauber voneinander getrennt, sondern freie und benutzte Stellen unterschiedlicher Größe wechseln sich am Heap ab, der Heap wird löchrig. Wenn keine speziellen Maßnahmen getroffen werden, nimmt die Größe des zusammen hängenden freien Speichers ab. Die Konsequenz, mit der Zeit nimmt die maximale Größe des, mit malloc(), ausborgbaren Speichers ab. Malloc liefer dann als Speicheradresse NULL zurück. Daher war die Benutzung des Heaps lange Zeit für sicherheitsrelevante Anwendungen nicht zulässig.
:
Bearbeitet durch User
Gerald K. schrieb: > Daher war die Benutzung des Heaps lange Zeit für sicherheitsrelevante > Anwendungen nicht zulässig. Dem steht aber die Philosophie fanatischer C-Jünger entgegen, JEDE Variable mit new anzulegen - Datensegmente müssen beim Programmstart leer sein. Georg
Georg schrieb: > Dem steht aber die Philosophie fanatischer C-Jünger entgegen, JEDE > Variable mit new anzulegen Wo hast du solche Leute denn je gesehen? Die sind mir noch nicht einmal theoretisch begegnet, praktisch gleich gar nicht.
Georg schrieb: > Dem steht aber die Philosophie fanatischer C-Jünger entgegen, JEDE > Variable mit new anzulegen Wohl kaum, denn "new" ist kein Schlüsselwort in C.
Nop schrieb: > Georg schrieb: > >> Dem steht aber die Philosophie fanatischer C-Jünger entgegen, JEDE >> Variable mit new anzulegen > > Wohl kaum, denn "new" ist kein Schlüsselwort in C. Und selbst in C++ kommt die direkte Verwendung von new ziemlich aus der Mode.
🐧 DPA 🐧 schrieb: > Das schöne am Stack ist, dass er nicht fragmentieren kann. Man packt > Daten oben drauf, und nimmt sie in der selben Reihenfolge auch wieder > davon weg. Das wäre ein Ringpuffer. Bei einem Stack nimmt man die Daten in umgekehrter Reihenfolge wieder weg (FIFO- vs. LIFO-Prinzip). Yalu X. schrieb: > Und selbst in C++ kommt die direkte Verwendung von new ziemlich aus der > Mode. Ob man es direkt oder indirekt verwendet, macht aber keinen Unterschied dafür, wo die Daten nachher liegen.
:
Bearbeitet durch User
Walter L. schrieb: > Was der Heap ist und was er macht und wozu er gut ist habe ich auch nie > verstanden. Beispiele: du musst 100 a 10MB Dateien parallel laden, dafür musst du den Speicherplatz dynamisch auf dem Heap reservieren, das passt niemals in den Stack du hast sehr viele Daten die kaum eine statische Größe Aufweisen - d.h. Anzahl ob es 0,10,1000 oder mehr Elemente sind weißt du nicht im voraus, dafür kannst du auch keinen Stack verwenden - die theoretische Menge an möglichen Daten überschreitet z.B. permanent deine maximale Stackgröße und die Daten lasse sich nicht stückchenweise verarbeiten und,und,und die 4 oder mehr GB in den heutigen Rechnern sind nicht nur dazu da besonders viele Programme gleichzeitig zu laden - was denkst du warum ein Programm 50, 100 oder 200MB Speicher braucht? der Stack ist fix fuer deine Threads oder main, der Rest ist auf dem Heap, das ist bei 98% der nicht ultra-klein-Embedded Programmen der Normalfall
cppbert3 schrieb: > das passt niemals in den Stack Kannst du so nicht sagen, hängt von der Plattform ab. Und nein, der Stack ist nicht "fix". Auf kleineren Plattformen wachsen oft Stack und Heap gegeneinander, es ist also recht egal, wer von den beiden den Speicher nimmt. Wenn er alle ist, hört's auf. Auf größeren Plattformen werden so lange neue Speicherseiten vom OS angefordert, bis ein bestimmtes (meist konfigurierbares) Maximum erreicht ist. Das trifft sowohl für Stack als auch Heap zu.
Jörg W. schrieb: > cppbert3 schrieb: >> das passt niemals in den Stack > > Kannst du so nicht sagen, hängt von der Plattform ab. Wollte ich auch schon schreiben. Die Stack-Größe hat ja (abgesehen von der Gesamt-Größe des RAM) keine technische Limitierung, sondern wurde von jemandem so gewählt. Die kann also nicht Grund dafür sein, warum man einen Heap braucht.
Jörg W. schrieb: > cppbert3 schrieb: >> das passt niemals in den Stack > > Kannst du so nicht sagen, hängt von der Plattform ab. > Und nein, der Stack ist nicht "fix". Auf kleineren Plattformen wachsen > oft Stack und Heap gegeneinander, es ist also recht egal, wer von den > beiden den Speicher nimmt. Wenn er alle ist, hört's auf. sorry, ich bezog mich auf x86 > Auf größeren Plattformen werden so lange neue Speicherseiten vom OS > angefordert, bis ein bestimmtes (meist konfigurierbares) Maximum > erreicht ist. Das trifft sowohl für Stack als auch Heap zu. der Stack wächst nicht dynamisch - dann wäre sein sinn als schneller Zwischenspeicher völlig dahin - oder was meinst du?
Rolf M. schrieb: > Jörg W. schrieb: >> cppbert3 schrieb: >>> das passt niemals in den Stack >> >> Kannst du so nicht sagen, hängt von der Plattform ab. > > Wollte ich auch schon schreiben. Die Stack-Größe hat ja (abgesehen von > der Gesamt-Größe des RAM) keine technische Limitierung, sondern wurde > von jemandem so gewählt. Die kann also nicht Grund dafür sein, warum man > einen Heap braucht. der Stack wird aber z.B. unter Windows/Linux pro Thread und Prozess zum Startzeitpunkt vor-definiert z.B. auf 2 oder 5MB, daran kannst du nicht rütteln sonst müssten man ja irgenein dynamisches wachstum erlaube was den Stack wieder (im Vergleich zu einer statischen Größe - d.h. ohne jegliches überwachendes Management) wieder zu langsam machen würde
cppbert3 schrieb: > der Stack wächst nicht dynamisch - dann wäre sein sinn als schneller > Zwischenspeicher völlig dahin Ich kenne das mit wählbarer Maximalgröße. Damit endlose Rekursion nicht den Speicher des Systems platzen lässt. Stack wird bei Systemen mit virtuellen Speicher automatisch und bedarfsgesteuert bis zu diesem Wert vergrößert. Vorher ist das nur Adressraum, ohne RAM dahinter.
:
Bearbeitet durch User
cppbert3 schrieb: >> Auf größeren Plattformen werden so lange neue Speicherseiten vom OS >> angefordert, bis ein bestimmtes (meist konfigurierbares) Maximum >> erreicht ist. Das trifft sowohl für Stack als auch Heap zu. > > der Stack wächst nicht dynamisch - dann wäre sein sinn als schneller > Zwischenspeicher völlig dahin - oder was meinst du? Der Stack selbst wächst schon dynamisch, sonst bräuchte man keinen Stackpointer, der auf das Ende zeigt. Ob der für den Stack reservierte Speicher (also die Maximalgröße für den Stack) auch dynamisch wachsen kann, hängt vom System ab. Unter Linux wächst diese Größe nicht von selbst, aber man kann sie per setrlimit ändern.
Rolf M. schrieb: > Der Stack selbst wächst schon dynamisch, sonst bräuchte man keinen > Stackpointer ich meinte der Stack vergroessert sich nicht wenn man an seine Grenze stosst
(prx) A. K. schrieb: > Stack wird bei Systemen mit virtuellen Speicher automatisch und > bedarfsgesteuert bis zu diesem Wert vergrößert. Vorher ist das nur > Adressraum, ohne RAM dahinter. wie gesagt die Stackgröße ist fix - und das vergrößern mit dem virtuellen Speicher läuft in Hardware? in Software wäre das doch viel zu langsam deswegen - wenn ich Daten habe die ich komplett im "Speicher" brauche sollte ich das nicht unbedingt versuchen in den Stack zu stopfen - wenn z.B. die Daten wissentlich die Stackgröße locker erreichen auch alloca ist da nicht ganz ungefährlich :)
Rolf M. schrieb: > Ob der für den Stack reservierte > Speicher (also die Maximalgröße für den Stack) auch dynamisch wachsen > kann, hängt vom System ab. kannst du mir ein System nennen das dynamisches Wachstum des Stack erlaubt? also das man ein min Größe angibt und dann der Stack so lange wachsen kann bis der RAM verbraucht ist das muss doch höchst langsam sein - wird da jedes mal im Code geprüft ob man an der Grenze ist oder jedes mal ein Page-Check gemacht, 100Mio mal...?
cppbert3 schrieb: > Rolf M. schrieb: >> Ob der für den Stack reservierte >> Speicher (also die Maximalgröße für den Stack) auch dynamisch wachsen >> kann, hängt vom System ab. > > kannst du mir ein System nennen das dynamisches Wachstum des Stack > erlaubt? > also das man ein min Größe angibt und dann der Stack so lange wachsen > kann bis der RAM verbraucht ist AVR? Der hat hardwaretechnisch gar nicht die Möglichkeit, das zu begrenzen. > das muss doch höchst langsam sein - wird da jedes mal im Code geprüft ob > man an der Grenze ist oder jedes mal ein Page-Check gemacht, 100Mio > mal...? Wieso "page-check"? Eine MMU checkt sowas von sich aus. Unter Linux gibt's z.B. einen Segmentation Fault, wenn das Maximum überschritten wird. Stattdessen könnte man im entsprechenden Handler genauso den Bereich einfach vergrößern. Da muss in Software nix dafür gecheckt werden. Auslagerung funktioniert ja auch genau auf diese Weise, und die Lazy Allocation beim Heap ebenfalls.
:
Bearbeitet durch User
cppbert3 schrieb: > wie gesagt die Stackgröße ist fix - und das vergrößern mit dem > virtuellen Speicher läuft in Hardware Wenn das System so wie beschrieben arbeitet, dann führt ein Zugriff auf eine Speicherseite im Stack, hinter der bisher kein RAM steht, automatisch dazu, dass ihr RAM zugeordnet wird. Voraussetzung ist dann nur, dass der Adressraum des Stacks ausreichend gross definiert wurde. cppbert3 schrieb: > das muss doch höchst langsam sein Virtueller Speicher ist eine Eigenschaft der MMU des Prozessors. Solche Kontrollen finden per Hardware bei jedem einzelnen Speicherzugriff statt, egal wohin. Zugriff auf nicht definierten Adressraum führt i.d.R. zum Abbruch des Programms. Geschieht das nicht in einer Anwendung, sondern im Kernel oder einem Treiber des Betriebssystem, führt das zum Bluescreen oder Ṕanic.
:
Bearbeitet durch User
cppbert3 schrieb: > also das man ein min Größe angibt und dann der Stack so lange wachsen > kann bis der RAM verbraucht ist Andersrum. Man gibt eine maximale Grösse an, aber es wird dafür nur Adressraum reserviert, kein RAM. Bei 64-Bit Programmen hat man ausreichend Gesamtadressraum um grosszügig zu sein. Dass man nicht immer sehr grosse Stacks reserviert ist eine Schutzmassnahme. Meist sind genutzte Stacks in GB Grösse nicht Absicht, sondern Amoklauf.
:
Bearbeitet durch User
Rolf M. schrieb: > AVR? Der hat hardwaretechnisch gar nicht die Möglichkeit, das zu > begrenzen. wie begrenzt denn x86 das hardwaretechnisch? dort kann man es nur erkennen ob es passiert, aber nicht wirklich "begrenzen" Fakt ist: Es gibt bei den meisten Systemen einen(oder mehrere) begrenzte Stacks die meistens eine Maximalgröße Aufweisen - ob das intern durch virtuellen Memory oder sonstwen gehandhabt wird war mir bei meine Aussage egal das der Stack sich dynamisch füllt(aka wächst) ist klar, aber das der Stack-Max sich automatisch vergrößert ist denke ich selten
cppbert3 schrieb: > das der Stack sich dynamisch füllt(aka wächst) ist klar, aber das der > Stack-Max sich automatisch vergrößert ist denke ich selten Das interpretierst du in die Antworten rein, steht dort aber nicht drin.
cppbert3 schrieb: > Fakt ist: Es gibt bei den meisten Systemen einen(oder mehrere) begrenzte > Stacks die meistens eine Maximalgröße Aufweisen Du kannst mit setrlimit sowohl für den Stack als auch für den Heap (Datensegment) nahezu beliebige Ressource Limits einstellen. Davon allein wird dort nichts alloziert. Alloziert wird erst, wenn es gebraucht wird (via page fault, wie A.K. beschrieben hat). Insofern verhalten sich bei einem VM-System diese beiden Bereiche komplett gleich mit der einzigen Ausnahme, dass das Datensegment von unten nach oben wächst, der Stack von oben nach unten. Das bezieht sich auf Prozess-Stacks. Mit Thread-Stacks verhält sich das u.U. anders, je nachdem, wie der Thread implementiert ist. Ist er (wie bei vielen Unixen) wie ein Prozess implementiert, kann man das dort natürlich genauso handhaben, ansonsten muss das Thread-System explizit vorab Speicher allozieren (dann wohl auf dem Heap).
Jörg W. schrieb: > ansonsten muss das Thread-System explizit > vorab Speicher allozieren (dann wohl auf dem Heap). Wenn der Allokator im Heap diesem Bereich vorsorglich komplett mit Nullen plättet, ist das RAM da, finito. Wer klug genug ist, das nicht zu tun, sondern es dem OS überlässt, kriegt erst einmal nur Adressraum, plus evtl. ein paar reale Bytes vom Heap-Management vorne und hinten. Auch allozierter aber nicht genutzter Heap kann locker ohne reale RAM-Zuordnung leben. Bis zum Zugriff, Seite für Seite.
:
Bearbeitet durch User
(prx) A. K. schrieb: > cppbert3 schrieb: >> wie begrenzt denn x86 das hardwaretechnisch? > > https://wiki.osdev.org/Paging das ist klar - Begrenzen kann man auch gar nicht - sonst gäbe es ja gar keine Stackoverflows :) - man kann eben sauber erkennen das es passiert und AVR hat das Feature eben nicht, oder?
Beitrag #6691286 wurde vom Autor gelöscht.
Mit setrlimit (oder ulimit in der Shell) kann man die Limitierung der Stackgröße auch komplett aufheben. Dann hat man quasi einen voll dynamischen Stack, der nur durch die Größe des physikalischen Speichers begrenzt wird. Ist dieser aufgebraucht, kommt der OOM-Killer und tötet den seiner Ansicht nach bösesten oder unwichtigsten Prozess, um wieder Speicher frei zu machen
cppbert3 schrieb: > Rolf M. schrieb: >> AVR? Der hat hardwaretechnisch gar nicht die Möglichkeit, das zu >> begrenzen. > > wie begrenzt denn x86 das hardwaretechnisch? Indem vor einem Überschreiten der Grenze im Prozessor eine Page-Fault-Exception ausgelöst wird und das Betriebssystem als Reaktion darauf den Prozess terminiert. Natürlich nur, wenn das Betriebssystem die MMU vorher passend konfiguriert hat. > dort kann man es nur erkennen ob es passiert, aber nicht wirklich > "begrenzen" Wenn man das nicht könnte, könnte ein Stacküberlauf eines Prozesses das ganze Betriebssystem zum Absturz bringen. > Fakt ist: Es gibt bei den meisten Systemen einen(oder mehrere) begrenzte > Stacks die meistens eine Maximalgröße Aufweisen - ob das intern durch > virtuellen Memory oder sonstwen gehandhabt wird war mir bei meine > Aussage egal Es ist eigentlich umgekehrt: Im einfachsten Fall gibt es keine Maximalgröße. Der Stack wächst einfach weiter, ggf. auch bis er andere Daten im RAM gnadenlos überschreibt. Bei kleinen Prozessoren wie AVR ist es nicht unüblich, dass Stack und Heap auf einander zu wachsen. Dann gibt es kein fixes Maximum. Es hängt einfach davon ab, wie viel Heap man schon benutzt. Der Prozessor kann eine Überschreitung aber sowieso nicht in Hardware prüfen oder darauf reagieren. Hat man dagegen eine MPU oder MMU, kann die genutzt werden, um eine Grenze einzustellen, auf deren Überschreiten man auch reagieren kann, ohne dass das bei jedem Zugriff erst softwareseitig geprüft werden müssten.
cppbert3 schrieb: > sonst gäbe es ja gar > keine Stackoverflows Ein Stackoverflow ist was ganz anderes: Man spricht von einem Stackoverflow, wenn der von einer Funktion auf dem Stack reservierte Speicherbereich für ihre lokalen Daten (Variablen) durch ein Programmfehler unerwartet überschritten wird. Problematisch an dieser Geschichte ist (bzw. war), dass auf dem Stack in der Regel Daten und die Rücksprungadresse dicht beieinander liegen. Dann konnte mitunter durch ein Stackoverflow boshafter Code auf den Stack abgelegt werden, und die Rücksprungadresse der Funktion manipuliert werden. Führt daraufhin die Funktionen einen Rücksprung aus, wird statt zu der ursprünglich aufrufenden Funktion in den boshaften Code gesprungen.
Experte schrieb: > Ein Stackoverflow ist was ganz anderes: > > Man spricht von einem Stackoverflow, wenn der von einer Funktion auf dem > Stack reservierte Speicherbereich für ihre lokalen Daten (Variablen) > durch ein Programmfehler unerwartet überschritten wird. Nein, das ist ein Buffer Overflow. Da überläuft nicht der Stack, sondern nur eine Variable, typischerweise ein Array.
Rolf M. schrieb: > Indem vor einem Überschreiten der Grenze im Prozessor eine > Page-Fault-Exception ausgelöst wird und das Betriebssystem als Reaktion > darauf den Prozess terminiert. Natürlich nur, wenn das Betriebssystem > die MMU vorher passend konfiguriert hat. Genau das meinte ich mit "erkennen", mir ist klar wie das realisiert wird
cppbert3 schrieb: > und AVR hat das Feature eben nicht, oder? Muss er ja auch nicht, man kann den Stack auch ohne spezielle Hardwarefunktion überwachen, per Software. Mein Pascal-Compiler für Z80 aus dem vorigen Jahrtausend hatte die Option zu überwachen, ob sich der von unten wachsende Heap und der von oben wachsende Stack (das übliche Memory-Modell) überschneiden. Ich kann nicht so recht glauben dass damals die Compiler mehr konnten als heute, aber wenn man hier so mitliest... Georg
Georg schrieb: > Muss er ja auch nicht, man kann den Stack auch ohne spezielle > Hardwarefunktion überwachen, per Software. Das geht heute auch noch mit Abstrichen, z.B. in Form von intensiveren Runtime Test bei Stacknutzung um Fehler aufzudecken, ist aber eben alles sehr sehr langsam
Beitrag #6691717 wurde von einem Moderator gelöscht.
cppbert3 schrieb: > das ist klar - Begrenzen kann man auch gar nicht - sonst gäbe es ja gar > keine Stackoverflows :) - man kann eben sauber erkennen das es passiert > > und AVR hat das Feature eben nicht, oder? Nicht in Hardware, aber man kann es in die Software einbauen. Kostet natürlich Rechenzeit und zwar nicht ganz unerheblich. Das Prinzip ist simpel: Du legst irgendwo im Speicher eine Variable an, in der die höchste benutzte statische Speicheradresse abgelegt wird oder (bei Verwendung dynamischen Speichers) halt der heap top. Und dann muss in jeder Funktion (insbesondere auch in jeder ISR) kontrolliert werden, dass der aktuelle SP halt noch größer ist als der Inhalt dieser Variablen. Blöderweise ist dazu ein 16Bit-Vergleich nötig. Das bedeutet (insbesondere für ISRs): es sind zwingend mindestens 2 Register zu sichern und auch das Flag-Register. Je nachdem, was die ISR sonst noch tut, kann das einen erheblichen Mehraufwand bedeuten. Ich würd's nicht machen. Denn eigentlich ist (mit zwei Ausnahmen) der maximale Stackbedarf zur Designzeit ermittelbar. Die zwei Ausnahmen sind auf Grund äußerer Daten berechnete Funktionszeiger und rekursive Unterprogramme. Man vermeidet einfach die Verwendung solcher Konstrukte und gut isses.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.