Kann auf den Speicher einer lokalen Variablen außerhalb seines Gültigkeitsbereichs zugegriffen werden?
Ich habe den folgenden code.
int * foo()
{
int a = 5;
return &a;
}
int main()
{
int* p = foo();
cout << *p;
*p = 8;
cout << *p;
}
Und der code ist nur im Betrieb mit keine runtime-Ausnahmen!!!
Wurde die Ausgabe 58
Wie kann es sein? Ist nicht die Erinnerung an eine lokale variable unzugänglich außerhalb seiner Funktion?
InformationsquelleAutor der Frage |
Du musst angemeldet sein, um einen Kommentar abzugeben.
Ihnen ein Hotelzimmer mieten. Sie legte ein Buch in der obersten Schublade des Nachttisch und schlafen gehen. Beim check out am nächsten morgen, aber "vergessen" zurück zu geben, Ihre Schlüssel. Sie stehlen den Schlüssel!
Eine Woche später, kehren Sie zurück zum hotel, check das nicht, schleichen sich in Ihre alten Zimmer, die mit Ihren gestohlenen Schlüssel, und suchen Sie in der Schublade. Ihr Buch ist immer noch da. Erstaunlich!
Wie kann das sein? Nicht der Inhalt eines Hotelzimmers Schublade unzugänglich, wenn Sie nicht vermietet Zimmer?
Gut, dass offensichtlich Szenario kann passieren in der realen Welt kein problem. Es gibt keine geheimnisvolle Kraft, die bewirkt, dass Ihr Buch zu verschwinden, wenn Sie nicht mehr berechtigt, in das Zimmer. Es gibt eine geheimnisvolle Kraft, die Sie daran hindert, Sie betreten einen Raum mit einem gestohlenen Schlüssel.
Das hotel-management ist nicht erforderlich zu entfernen Ihrem Buch. Sie nicht machen einen Vertrag mit Ihnen, sagte, dass, wenn Sie verlassen Sachen hinter sich, die Sie zerreißen es für Sie. Wenn Sie illegal re-geben Sie Ihr Zimmer mit einem gestohlenen Schlüssel, um es zu bekommen zurück, die hotel-security-Personal ist nicht erforderlich zu fangen, Sie schleichen in. Sie nicht machen einen Vertrag mit Ihnen, der sagte: "wenn ich versuche zu schleichen zurück in mein Zimmer später, Sie sind verpflichtet, mich zu stoppen." Vielmehr haben Sie einen Vertrag mit Ihnen, der sagte: "ich verspreche nicht, zu schleichen zurück in mein Zimmer später", ein Vertrag, der Sie brach.
In dieser situation alles passieren kann. Das Buch ist da-haben Sie Glück gehabt. Jemand anderes Buch kann da sein, und Ihnen könnte in der hotel-Ofen. Jemand könnte es Recht, wenn Sie kommen, reißen Sie Ihr Buch in Stücke. Das hotel haben könnte, entfernt die Tabelle aus und buchen Sie ganz und ersetzt es mit einem Kleiderschrank. Das gesamte hotel könnte genau das sein, werden abgerissen und ersetzt durch ein Fußball-Stadion, und du stirbst in einer explosion, während Sie schleicht herum.
Wissen Sie nicht, was geschehen wird; wenn Sie aus dem hotel ausgecheckt und Stahlen einen Schlüssel, um die gesetzwidrige Verwendung später, Sie gab das Recht auf Leben in einem vorhersagbaren, sicheren Welt, weil Sie wählte zu brechen, die Regeln des Systems.
C++ ist keine sichere Sprache. Es wird fröhlich erlauben, Sie zu brechen, die Regeln des Systems. Wenn Sie versuchen, etwas illegales zu tun und dumm wie eine Reise in ein Zimmer, Sie sind nicht autorisiert, in und durchstöbern ein Schreibtisch, der vielleicht gar nicht mehr da sein, C++ ist nicht, Sie zu stoppen. Sicherer Sprachen als C++ lösen dieses problem durch die Beschränkung Ihrer macht-indem er viel strengere Kontrolle über Ihre Schlüssel, zum Beispiel.
UPDATE
Heilige Güte, diese Antwort ist immer eine Menge Aufmerksamkeit. (Ich bin mir nicht sicher, warum-ich hielt es nur ein "Spaß" - kleine Analogie, aber egal.)
Ich dachte, es wäre angemessen zu aktualisieren, dies ein bisschen mit ein paar mehr technischen Gedanken.
Compiler sind in das Geschäft der Generierung von code verwaltet die Speicherung der Daten manipuliert durch das Programm. Es gibt viele verschiedene Möglichkeiten der Generierung von code, um Speicher zu verwalten, aber im Laufe der Zeit zwei grundlegende Techniken haben sich verschanzt.
Die erste ist, um irgendeine Art von "lange gelebt" - storage-Bereich, wo die "Lebensdauer" jedes byte in den Speicher-das ist die Zeit, wenn es ist gültig in Zusammenhang mit manchen Programm-variable -- nicht leicht vorhergesagt vor der Zeit. Die compiler-Aufrufe zu einer "heap-manager", der weiß, wie dynamisch reservieren Speicher, wenn es nötig ist, und Sie es zurückfordern, wenn es nicht mehr benötigt wird.
Das zweite ist, um irgendeine Art von "kurzer Dauer" - storage-Bereich, wo die Lebensdauer jedes byte im Speicher bekannt ist, und, insbesondere, die Lebensdauer von Speicher Folgen ein "nesting" - Muster. Das heißt, die Verteilung der am längsten lebte, der kurzlebigen Variablen streng überlappungen der Verteilungen der kürzer Variablen, die nach ihm kommen.
Lokale Variablen Folgen Sie dieser, Muster; wenn eine Methode eingegeben wird, dessen lokale Variablen lebendig. Wenn diese Methode ruft eine andere Methode, die neue Methode lokale Variablen lebendig. Sie werden tot sein, bevor die erste Methode lokale Variablen tot sind. Die relative Reihenfolge der Anfänge und enden der Lebensdauer der Speicher im Zusammenhang mit lokalen Variablen gearbeitet werden kann vor der Zeit.
Aus diesem Grund werden die lokalen Variablen sind in der Regel generiert, als die Speicherung auf einem "Stapel" von Daten-Struktur, weil ein stack hat die Eigenschaft, dass das erste, was bewegt auf es ist das Letzte Ding tauchte ab.
Es ist wie das hotel entscheidet, zu vermieten nur die Zimmer nummeriert, und man kann nicht check-out bis jeder mit einem Zimmer-Anzahl höher, als Sie ausgecheckt hat.
Denken wir also über den stack. In vielen Betriebssystemen erhalten Sie einen Stapel pro thread und stack zugeordnet ist, um eine bestimmte Feste Größe. Wenn Sie eine Methode aufrufen, Sachen auf dem Stapel abgelegt. Wenn Sie dann übergeben Sie einen Zeiger auf den stack wieder aus der Methode, wie der ursprüngliche poster nicht hier, das ist nur ein Zeiger auf die Mitte ein paar ganz gültig Mio-byte-Speicher-block. In unserer Analogie, checken Sie aus dem hotel; wenn Sie das tun, werden Sie nur Check-out der höchsten Nummerierung besetzten Raum. Wenn sonst niemand prüft nach, und gehen Sie zurück zu Ihrem Zimmer, illegal, alle Ihre Sachen, ist garantiert noch da sein in diesem hotel.
Verwenden wir stapeln für temporary stores, denn Sie sind wirklich Billig und einfach. Eine Umsetzung von C++ ist nicht erforderlich, um einen Stapel für Lagerung die einheimischen; es könnte heap. Tut es nicht, weil das würde das Programm langsamer.
Eine Implementierung von C++ ist nicht erforderlich, zu verlassen, den Müll, den Sie Links auf dem Stapel unberührt, so dass Sie kommen zurück für ihn später illegal; es ist völlig legal für den compiler, um code zu generieren, stellt sich zurück auf null, alles, was in den "Raum", den Sie gerade geräumt. Es nicht, weil wieder, das wäre teuer.
Eine Implementierung von C++ ist nicht erforderlich, um sicherzustellen, dass, wenn der stack logischerweise schrumpft, die Adressen, die verwendet werden, um gültig zu sein, sind immer noch in den Speicher gemappt. Die Umsetzung ist erlaubt zu sagen, das Betriebssystem "sind wir fertig mit dieser Seite der Stapel ist jetzt. Bis ich etwas anderes sagen, Frage eine Ausnahme, zerstört den Prozess, wenn jemand berührt, die zuvor gültigen stack-Seite". Wieder, Implementierungen, die eigentlich nicht tun, weil es ist langsam und unnötig.
Statt, Implementierungen lassen Sie Sie Fehler machen und Weg mit ihm. Die meisten der Zeit. Bis eines Tages etwas wirklich schrecklich schief geht und der Prozess platzt.
Dies ist problematisch. Es gibt eine Menge von Regeln und es ist sehr leicht zu brechen Sie versehentlich. Ich habe natürlich viele Male. Und schlimmer noch, oft das problem, dass nur die Flächen, wenn der Speicher erkannt wird beschädigt Milliarden von Nanosekunden nach der Korruption ist passiert, Wann ist es sehr schwer, herauszufinden, wer es versaut.
Mehr Speicher-sichere Sprachen lösen dieses problem durch die Beschränkung Ihrer macht. In "normalen" C# gibt es einfach keine Möglichkeit zu nehmen, die Adresse einer lokalen und senden Sie es oder speichern Sie es für später. Sie können die Adresse einer lokalen, aber die Sprache ist geschickt so konzipiert, dass es unmöglich ist, es zu benutzen, nachdem die Lebensdauer der lokalen endet. Um die Adresse einer lokalen und übergeben Sie es zurück, Sie haben, um den compiler in einem speziellen "unsafe" - Modus, und setzen Sie das Wort "unsicher" in Ihrem Programm, um Aufmerksamkeit auf die Tatsache, dass Sie wahrscheinlich etwas tun, die gefährlich werden könnte, brechen die Regeln.
Zur weiteren Lektüre:
Was ist, wenn C# habe ermöglichen die RÜCKFÜHRUNG Referenzen? Zufällig, das ist das Thema des heutigen blog-post:
http://blogs.msdn.com/b/ericlippert/archive/2011/06/23/ref-returns-and-ref-locals.aspx
Warum verwenden wir stapeln, um Speicher zu verwalten? Sind Werttypen in C# immer auf dem stack gespeichert werden? Wie funktioniert der virtuelle Speicher? Und viele weitere Themen, wie die C# - memory-manager arbeitet. Viele dieser Artikel sind auch relevant für C++ - Programmierer:
https://blogs.msdn.microsoft.com/ericlippert/tag/memory-management/
InformationsquelleAutor der Antwort Eric Lippert
Was du hier tust ist einfach nur Lesen und in den Speicher geschrieben wird, dass benutzt die Adresse des
a
. Du bist jetzt außerhalb derfoo
es ist nur ein Zeiger auf einen zufälligen Speicherbereich. Es ist einfach so passiert, dass in Ihrem Beispiel, dass der Speicherbereich nicht existiert und nichts anderes im moment. Sie nicht etwas zu brechen, indem Sie fortfahren, es zu benutzen, und nichts anderes hat, überschrieben es noch nicht. Daher die5
ist immer noch da. In einem echten Programm, dass der Speicher wäre wieder fast sofort, und Sie würde brechen etwas durch, dies zu tun (obwohl die Symptome treten möglicherweise erst viel später!)Zurückkehren, wenn Sie von
foo
Sie sagen, die OS, die Sie nicht mehr verwenden, Speicher und es kann neu zugewiesen werden, um etwas anderes. Wenn Sie Glück haben und es nie bekommen hat neu zugewiesen, und das OS nicht fangen Sie erneut zu verwenden, dann erhalten Sie Weg mit der Lüge. Chancen sind, wenn Sie am Ende schreiben, über was auch sonst, endet mit dieser Adresse.Nun, wenn Sie sich Fragen, warum der compiler nicht meckern, es ist wahrscheinlich, weil
foo
habe beseitigt-Optimierung. Es wird in der Regel warnen Sie über diese Art der Sache. C setzt Voraus, Sie wissen, was Sie tun, obwohl, und technisch Sie noch nicht verletzt Rahmen hier (es gibt keine Referenz zua
sich außerhalb derfoo
), nur die memory-access-Regeln, die nur löst eine Warnung statt einem Fehler.Kurz: diese in der Regel nicht arbeiten, aber manchmal durch Zufall.
InformationsquelleAutor der Antwort Rena
Weil der Speicherplatz nicht stampfte auf nur noch. Zählen Sie nicht auf dieses Verhalten.
InformationsquelleAutor der Antwort msw
Eine kleine Ergänzung für alle die Antworten:
wenn Sie so etwas tun:
die Ausgabe wird wahrscheinlich sein: 7
Ist, weil nach der Rückkehr von foo() der Stapel ist befreit und dann wiederverwendet von boo().
Wenn Sie deassemble die ausführbare Datei werden Sie es deutlich sehen.
InformationsquelleAutor der Antwort
In C++, Sie kann Zugriff auf eine Adresse, aber es bedeutet nicht, dass Sie sollte. Die Adresse, auf die Sie zugreifen, ist nicht mehr gültig. Es funktioniert weil nichts anderes verschlüsselt den Speicher nach foo zurückgegeben, aber es könnte Abstürzen unter vielen Umständen ab. Versuchen Sie, analysieren Sie Ihr Programm mit Valgrindoder auch nur kompiliert, optimiert und sehen...
InformationsquelleAutor der Antwort Charles Brunet
Sie werfen eine C++ - Ausnahme durch den Zugriff auf ungültigen Speicher zu. Sie geben ein Beispiel für die Allgemeine Idee der Verweis auf eine beliebige memory location. Ich könnte das gleiche zu tun wie diese:
Hier bin ich einfach der Behandlung von 123456, wie die Adresse, ein Doppel-und schreiben. Eine beliebige Anzahl von Dingen könnte passieren:
q
könnte in der Tat wirklich eine gültige Adresse von einem double, z.B.double p; q = &p;
.q
könnte Punkt irgendwo im inneren Speicher zugewiesen, und ich einfach überschreiben 8 bytes drin.q
Punkte außerhalb der reservierten Arbeitsspeicher und das Betriebssystem Speicher-manager sendet ein segmentation-fault-signal zu meinem Programm, wodurch die Laufzeit zu kündigen.Die Weise, die Sie es einrichten, ist es ein wenig mehr angemessen, dass die Adresse zurückgegeben Punkte in einem gültigen Bereich von Speicher, wie es wahrscheinlich nur ein wenig weiter unten auf dem Stapel, aber es ist immer noch eine ungültige Position, dass Sie nicht in einer deterministischen Weise.
Niemand wird automatisch überprüfen Sie die semantische Gültigkeit der Speicher-Adressen so für Sie während der normalen Ausführung des Programms. Aber ein Speicher-debugger wie
valgrind
gerne tun Sie dies, so führen Sie Ihr Programm durch und werden Sie Zeuge der Fehler.InformationsquelleAutor der Antwort Kerrek SB
Hast du kompilieren Sie das Programm mit dem Optimierungstool aktiviert ?
Die foo () - Funktion ist Recht einfach und hätte inlined/ersetzt in dem resultierenden code.
Aber ich aggree mit B markiert, dass der daraus resultierende Verhalten nicht definiert ist.
InformationsquelleAutor der Antwort gastush
Dein problem hat nichts zu tun mit Umfang. In dem code, den Sie zeigen, ist die Funktion
main
nicht sehen, die Namen in der Funktionfoo
so dass Sie nicht zugreifen könnena
foo direkt mit diese Namen außerhalbfoo
.Das problem, das Sie haben ist, warum das Programm nicht das signal zu einem Fehler beim verweisen auf illegalen Speicher. Dies ist, weil C++ - standards nicht angeben, in eine sehr klare Grenze zwischen illegalen Speicher und rechtliche Speicher. Verweisen auf etwas in herausgesprungen stack verursacht manchmal Fehler, und manchmal nicht. Es hängt davon ab. Zählen Sie nicht auf dieses Verhalten. Nehme an, es wird immer Fehler beim Programm, sondern davon ausgehen, es wird niemals das signal error beim Debuggen.
InformationsquelleAutor der Antwort Chang Peng
Sind Sie einfach wieder eine Speicheradresse, es ist erlaubt, wird aber wahrscheinlich ein Fehler.
Ja, wenn Sie versuchen, Sie zu dereferenzieren, die Speicher-Adresse, die Sie haben Undefiniertes Verhalten.
InformationsquelleAutor der Antwort Brian R. Bondy
Dass die klassischen Undefiniertes Verhalten das ist diskutiert worden, hier nicht vor zwei Tagen -- Suche rund um die Website für ein bisschen. Kurz gesagt, Sie waren glücklich, aber alles, was hätte geschehen können, und der code macht Ungültiger Zugriff auf den Speicher.
InformationsquelleAutor der Antwort Kerrek SB
Dieses Verhalten ist nicht definiert, wie Alex darauf hingewiesen-in der Tat, die meisten Compiler warnen vor dies zu tun, weil es eine einfache Möglichkeit, um Abstürze.
Ein Beispiel für die Art von Spuk Verhalten Sie wahrscheinlich zu bekommen, versuchen Sie dieses Beispiel:
Dieser druckt "y=123", aber Ihre Ergebnisse können variieren (wirklich!). Ihr Zeiger ist Stress für andere, die unabhängig von lokalen Variablen.
InformationsquelleAutor der Antwort AHelps
Es funktioniert, weil der stack nicht verändert wurde (noch) nicht, da eine war dort.
Rufen ein paar andere Funktionen (die auch den Aufruf von anderen Funktionen) vor dem Zugriff auf
a
wieder und Sie werden wahrscheinlich nicht so glücklich mehr... 😉InformationsquelleAutor der Antwort Adrian Grigore
Sie tatsächlich aufgerufen wird, Undefiniertes Verhalten.
Rückgabe der Adresse einer temporären funktioniert, aber als Provisorien sind zerstört am Ende einer Funktion die Ergebnisse der Zugriff auf Sie nicht definiert wird.
Also bist du auch nicht ändern
a
sondern den Speicherort, woa
einmal war. Dieser Unterschied ist sehr ähnlich zu dem Unterschied zwischen Absturz und nicht Absturz.InformationsquelleAutor der Antwort Alexander Gessler
In typische compiler-Implementierungen, kann man sich den code als "drucken Sie den Wert des Speicherblocks mit der Adresse, die verwendet werden besetzt". Auch, wenn Sie fügen Sie eine neue Funktion Aufruf einer Funktion, die constains eine lokale
int
es ist eine gute chance, dass der Wert vona
(oder die Speicher-Adresse, diea
verwendet, um Punkt-zu -) änderungen. Dies geschieht, weil der stack wird überschrieben mit einem neuen Rahmen mit verschiedenen Daten.Dies ist jedoch undefined Verhalten, und Sie sollten sich nicht darauf verlassen, dass es funktioniert!
InformationsquelleAutor der Antwort larsmoa
Achten Sie auf alle Warnungen . Nicht nur lösen, Fehler.
GCC zeigt diese Warnung
Dies ist die Stärke von C++. Sie sollten darauf achten, über Speicher. Mit der
-Werror
Flagge, diese Warnung immer ein Fehler und jetzt haben Sie, um zu Debuggen.InformationsquelleAutor der Antwort
Kann es, weil
a
ist eine variable zugeordnet, die vorübergehend für die Lebensdauer Ihres Anwendungsbereichs (foo
- Funktion). Nach Ihrer Rückkehr ausfoo
den Speicher frei und kann überschrieben werden.Was du machst, ist wie beschrieben Undefiniertes Verhalten. Das Ergebnis kann nicht vorhergesagt werden.
InformationsquelleAutor der Antwort littleadv
Die Dinge, mit richtigen (?) die Ausgabe in der Konsole kann sich dramatisch ändern, wenn Sie ::printf aber nicht cout.
Sie können spielen, um mit debugger in folgenden code (getestet auf x86, 32-bit, MSVisual Studio):
InformationsquelleAutor der Antwort
Nach der Rückkehr aus der Funktion werden alle Bezeichner werden zerstört, stattdessen gehalten, der Werte in einem Speicher-Ort und die wir nicht lokalisieren können, die Werte ohne Bezeichner.Aber, dass die Lage weiterhin enthält der gespeicherte Wert von der vorherigen Funktion.
So, hier die Funktion
foo()
ist die Rücksendung die Adresse vona
unda
ist zerstört, nach der Rückkehr seine Adresse. Und Sie können auf die geänderten Wertes durch, der Adresse zurückgegeben.Lassen Sie mich ein praktisches Beispiel:
Angenommen, ein Mann versteckt sich Geld an einem Ort und erzählt Ihnen die Lage. Nach einiger Zeit, der Mann, der gesagt hatte, daß Sie das Geld Ort stirbt. Aber noch immer haben Sie den Zugriff, die Geld verborgen.
InformationsquelleAutor der Antwort
Es "Schmutziger" Art und Weise der Verwendung von Speicher-Adressen. Wenn Sie wieder eine Adresse (Zeiger) Sie nicht wissen, ob es gehört zu den lokalen Gültigkeitsbereich einer Funktion. Es ist nur eine Adresse. Nun, da Sie aufgerufen wird, die " foo "Funktion), die Adresse (Speicherstelle) des" a " war bereits zugewiesen die es in die (sicher, zumindest für den Moment) adressierbaren Speicher der Anwendung (Prozess). Nach der 'foo' - Funktion zurückgegeben, die Adresse von 'a' werden als 'dirty', aber das ist es nicht aufgeräumt, noch gestört/verändert durch die Ausdrücke in den anderen Teil des Programms (in diesem speziellen Fall zumindest). Ein C/C++ - compiler bedeutet nicht aufhören Sie von solchen "dirty" - Zugang (vielleicht warnen Sie aber, wenn Sie Pflege). Sie können sicher verwenden (update) jeden Speicherbereich, in dem Daten-segment des Programms Instanz (Prozess), es sei denn, Sie schützen Sie die Adresse durch einige Mittel.
InformationsquelleAutor der Antwort
Dies ist definitiv ein timing-Problem! Das Objekt, das die
p
- Zeiger ist "geplant" werden zerstört, wenn, wenn geht ausfoo
's scope. Dieser Vorgang ist jedoch nicht sofort geschehen, sondern eher eine Zahl von CPU-Zyklen später. Ob dies zu undefiniertem Verhalten, oder C++ ist schon eine pre-cleanup-Zeug im hintergrund, das weiß ich nicht.Wenn Sie einen Anruf Ihres Betriebssystems
sleep
Funktion zwischen dem Aufruffoo
und diecout
Aussagen, dass das Programm warten Sie eine Sekunde oder so, bevor dereferenzieren Sie die Zeiger, Sie werden feststellen, dass die Daten Weg durch die Zeit, die Sie wollen, es zu Lesen! Blick auf mein Beispiel:(Beachten Sie, dass ich verwendet die
sleep
Funktion vonunistd.h
die ist nur auf Unix-ähnliche Systeme, so dass Sie brauchen, um zu ersetzen, die mitSleep(1000)
undWindows.h
wenn Sie auf Windows.)Ersetzte ich Ihre
int
mit einer Klasse, so kann ich genau sehen, Wann der Destruktor aufgerufen wird.Die Ausgabe dieses Codes ist die folgende:
Jedoch, wenn Sie ändern
doSleep
zutrue
:Wie Sie sehen können, ist das Objekt, soll zerstört werden tatsächlich zerstört, aber ich vermute, dass es einige pre-cleanup-Anweisungen, die ausgeführt werden müssen, bevor ein Objekt (oder einfach nur variable) zerstört wird, so lange, bis diese fertig sind, werden die Daten immer noch zugänglich für eine kurze Zeit (aber es gibt keine Garantie, für, die natürlich, also bitte nicht schreiben code, der abhängig von diesem).
Dies ist sehr seltsam, da der Destruktor aufgerufen wird sofort nach verlassen des Geltungsbereichs, jedoch die tatsächliche Zerstörung ist etwas verzögert.
Habe ich nie wirklich gelesen, die Teil des offiziellen ISO-C++ - standard, der angibt, dieses Verhalten, aber es könnte sehr gut sein, dass der standard nur Versprechen, dass Ihre Daten vernichtet werden, sobald es geht out of scope, aber es sagt nichts darüber, dass dies geschieht unmittelbar, bevor irgendeine andere Anweisung ausgeführt wird. Wenn dies der Fall ist, als dieses Verhalten ist völlig in Ordnung, und die Menschen sind einfach nur Missverständnisse die Norm.
Oder eine andere Ursache könnte sein, frech Compiler, Folgen Sie nicht den standard richtig. Eigentlich wäre dies nicht der einzige Fall, wo der Compiler den Handel ein wenig von der standard-Konformität-für mehr Leistung!
Was auch immer die Ursache ist, ist es klar, dass die Daten zerstört werden, nur nicht sofort.
InformationsquelleAutor der Antwort