Seltsamer Fehler bei vollem Speicher
-
Hallo,
mir ist heute eine kleine Anomalie aufgefallen. Und zwar habe ich folgende Funktion, die ich nach jedem new benutze, wobei ich new stets mit nothrow benutze.
inline void error_test (void *pointer, const char *error_message){ if (pointer == NULL){ std::cerr << "ERROR:" << error_message << std::endl; exit(EXIT_FAILURE); } return; }Das ist vielleicht nicht das Schlauste, was man machen kann, aber für mich erstmal genug. Nun ist es so: Wenn ich zum Start des Programms einen trivialen Aufruf mit dem Nullpointer mache (error_test(NULL, "test")), funktioniert alles, wie es soll. Wenn der Speicher allerdings mal WIRKLICH voll ist, d.h. new
gibt einen Nullpointer zurück, schreibt er die error_message nicht mehr hin, d.h. es kommt als Output nurERROR:, aber nicht mehr.
Gesagt sei dabei, dass mein Programm extrem viele kleine Speicherblöcke holt, d.h. bei einem fehlgeschlagenen new ist der Speicher wirklich richtig voll. Kann es sein, dass einfach nicht mehr genug Speicher da ist, um die error_message zu speichern (der Speicher für die error_message müsste wohl vom Heap geholt werden, nehme ich an?) oder wie ist dieses Verhalten zu erklären?
Vielen Dank schonmal im Voraus,
plizzz
-
(der Speicher für die error_message müsste wohl vom Heap geholt werden, nehme ich an?)
Nö, du übergibst ja nur einen Zeiger, dann ist es egal wo der Speicher herkommt.
error_test(0, "Hallo Welt"); // Static data char error[] = "Hallo Welt"; error_test(0, error); // Stack std::string msg("Hallo Welt"); error_test(0, msg.c_str()); // Heap, von std::string verwaltetKann mir das auch nicht ganz erklären.
-
Du kannst ja mal in die Implementierung deines Compilers von operator<<(ostream&, const char
schauen, vielleicht wird da irgendwo Speicher angefordert oder auch bei std::endl. Wenn du den Fehler verhindern willst, kannst du ja am Anfang einen Speicherblock anfordern (vielleicht 500 Byte) und diesen dann vor der Fehlerausgabe freigeben.
-
wxSkip schrieb:
Du kannst ja mal in die Implementierung deines Compilers von operator<<(ostream&, const char
schauen, vielleicht wird da irgendwo Speicher angefordert oder auch bei std::endl. Wenn du den Fehler verhindern willst, kannst du ja am Anfang einen Speicherblock anfordern (vielleicht 500 Byte) und diesen dann vor der Fehlerausgabe freigeben.Diese Methode hat funktioniert, auch wenn ich noch nicht exakt weiß, wieso. Werde mich mal bei Zeiten daran setzen und nachschauen, ob deine Vermutung richtig ist.
-
Könnte sein dass deine Implementierung den const char* in einen String konvertiert.
-
Denke eher nicht, denn wenn ich diesen Code habe
inline void new_test (void *pointer, const char *function_name, char *reserved_memory){ if (pointer == NULL){ delete[] reserved_memory; std::cerr << "ERROR: memory allocation failed in function " << function_name << std::endl; exit(EXIT_FAILURE); } return; }dann funktioniert es. D.h. wenn so eine Konversion stattfände, dürfte sie erst dann stattfinden, wenn function_name in cerr benutzt wird.
-
Ich meinte dass bei der Ausgabe konvertiert wird.

Könnte a.) an einer affigen Implementierung liegen oder b.) daran, dass aus irgendeinem Grund kein operator<< für const char* verfügbar ist und der für std::string genommen wird, inklusive Konvertierung.
Versuch mal das hier:
inline void mem_test(void *pointer, const char *function_name) { if(!pointer) { char const* msg = "ERROR: memory allocation failed in function "; std::cerr.write(msg, strlen(msg)); std::cerr.write(function_name, strlen(function_name)); std::cerr.put('\n'); std::cerr.flush(); exit(EXIT_FAILURE); } }
-
inline void new_test (void *pointer, const char *function_name, char *reserved_memory){ if (pointer == NULL){ std::cerr << "ERROR: memory allocation failed in function " << function_name << std::endl; delete[] reserved_memory; exit(EXIT_FAILURE); } return; }das sollte aber genauso nicht klappen, oder?!
-
genau.
Ich finde es eigentlich total gruselig, dass cerr überhaupt alokiert. Das heißt, dass es mit dieser Implementierung des C++ Standards keine ausfallsichere Fehlerausgabe gibt. ätzend. Würde ich fast unte rdie Kategorie "bug" einordnen.
-
otze schrieb:
genau.
Ich finde es eigentlich total gruselig, dass cerr überhaupt alokiert. Das heißt, dass es mit dieser Implementierung des C++ Standards keine ausfallsichere Fehlerausgabe gibt. ätzend. Würde ich fast unte rdie Kategorie "bug" einordnen.
Afaik gibt es sogar bool operator==(char const*) für std::string, die den char* erst einen String kopieren anstatt direkt strcmp aufzurufen. Keine Ahnung wie man auf so ne Idee kommt.
-
otze schrieb:
genau.
Ich finde es eigentlich total gruselig, dass cerr überhaupt alokiert. Das heißt, dass es mit dieser Implementierung des C++ Standards keine ausfallsichere Fehlerausgabe gibt. ätzend. Würde ich fast unte rdie Kategorie "bug" einordnen.
Das scheint nicht das cerr-Objekt zu sein, sondern der Operator <<.
-
Ethon schrieb:
Ich meinte dass bei der Ausgabe konvertiert wird.

Könnte a.) an einer affigen Implementierung liegen oder b.) daran, dass aus irgendeinem Grund kein operator<< für const char* verfügbar ist und der für std::string genommen wird, inklusive Konvertierung.
Versuch mal das hier:
inline void mem_test(void *pointer, const char *function_name) { if(!pointer) { char const* msg = "ERROR: memory allocation failed in function "; std::cerr.write(msg, strlen(msg)); std::cerr.write(function_name, strlen(function_name)); std::cerr.put('\n'); std::cerr.flush(); exit(EXIT_FAILURE); } }Das funktioniert leider auch nicht. Ist auch nicht allzu wichtig an sich (die Methode mit dem reservierten Speicher funktioniert, auch wenn sie nicht allzu schön ist), aber irgendwie schon interessant zu wissen, was da genau passiert.
-
SeppJ schrieb:
otze schrieb:
genau.
Ich finde es eigentlich total gruselig, dass cerr überhaupt alokiert. Das heißt, dass es mit dieser Implementierung des C++ Standards keine ausfallsichere Fehlerausgabe gibt. ätzend. Würde ich fast unte rdie Kategorie "bug" einordnen.
Das scheint nicht das cerr-Objekt zu sein, sondern der Operator <<.
mit dem letzten Post hätten wir das jetzt ausgeschlossen.
-
vlt das char const * str = "ERROR: ...." ? Allokiert das Speicher?
-
pyhax schrieb:
vlt das char const * str = "ERROR: ...." ? Allokiert das Speicher?
So ungefähr sizeof(char*). Auf dem Stack. Außerdem noch zwei weitere Zeiger für die Funktionsparameter und ein paar weitere Verwaltungsdaten. Wenn auf dem Stack nicht mal mehr 50-100 Byte frei sind, hat man natürlich ein Problem. Ich weiß jetzt nicht genau, was der Threadersteller für ein System hat und selbst wenn, dann wüsste ich nicht, wie dieses genau arbeitet. Aber da der Heap von Unten wächst und der Stack von Oben, kann durchaus sein, dass dies nicht mehr funktioniert, sofern wirklich alles bis auf's letzte Byte voll ist. Oder gibt es Systeme, in denen Speicher für den Stack im Voraus reserviert ist?
-
SeppJ schrieb:
Oder gibt es Systeme, in denen Speicher für den Stack im Voraus reserviert ist?
Ich kenne eigentlich nur solche Systeme.
Bzw. zumindest der Adressraum ist reserviert.
Und wenn der Adressraum des Stack nicht mehr mit Speicher hinterlegt werden kann, dann bekommt man keinen std::bad_alloc. Was auch immer dann passiert, das OS behandelt den Fall selbst.
-
Es ist nicht davon auszugehen, dass ganz zu Programmbeginn angelegter Speicher in der Nähe des Stacks liegt, und die Freigabe dürfte ja hier nur dann passieren, wenn der Speicher bereits voll ist.
Ich habe den Streambuffer von std::cerr im Verdacht, möchte aber nicht ausschließen, dass die Ursache noch tiefer liegt - wo kein Speicher mehr ist, kann viel daneben gehen. Vielleicht wäre es einen Versuch wert, statt std::cerr mal puts bzw. fputs zu bemühen.
-
Ich würde auch eher auf den Streambuffer tippen, als auf den Ausgabeoperator.
Mit dem Debugger Reinsteppen könnte Klarheit bringen.Wenn man ganz sicher gehen will: selbst Ausgabefunktionen mit der native OS API (win32, ...) programmieren.