Segmentation fault
-
Mit n = 1200000 läuft mein Programm fehlerfrei, mit n = 1400000 kommt ein Segmentation fault.
Woran könnte sowas liegen? Da der Quellcode ziemlich lang ist, möchte ich ihn hier nicht posten. Meine Vermutung wäre jetzt, dass es Probleme macht, große Arrays der Größe n (mit new) zu erstellen, obwohl genug Speicher frei ist. Kann sowas sein?
Wie überprüfe ich, ob ein Aufruf von new fehlschlägt?
-
Ramanujan schrieb:
Wie überprüfe ich, ob ein Aufruf von new fehlschlägt?
Dann fliegt 'ne Exception. Der Fehler, der bei einer ungefangenen Exception vom LZS ausgespuckt wird, ist aber eigentlich nie ein Segfault. Du hast ein anderes Problem. Ich tippe auf viel Low-Level-Gefrickel mit C-In-KlassenTM
-
Ramanujan schrieb:
Woran könnte sowas liegen?
vermutlich an n. Direkt oder indirekt.
Da der Quellcode ziemlich lang ist, möchte ich ihn hier nicht posten.
Dann wirf ein paar Teile raus, die deiner Meinung nach nicht zum Fehler beitragen, kompilier es und schau ob der Fehler immernoch auftritt (Wenn nicht, hast du die Ursache rausgeworfen). Mach das Ganze ein paarmal, so oft bis du nichts unwesentliches mehr drin hast. Dann dürften es nicht mehr allzu viele Zeilen sein und du kannst es posten.
Meine Vermutung wäre jetzt, dass es Probleme macht, große Arrays der Größe n (mit new) zu erstellen, obwohl genug Speicher frei ist. Kann sowas sein?
Kann sein, ja. Wenn der Speicher nur in kleinen Stücken frei ist und du ein großes Array (= großes, zusammenhängendes Stück) anforderst, könnte das probleme geben.
Wie überprüfe ich, ob ein Aufruf von new fehlschlägt?
Indem du die Exception fängst, die new wirft. Sollte alles im Lehrbuch deiner Wahl im passenden Kapitel stehen.
-
Du kannst ja jetzt aus Spaß mal das hier machen:
#include <new> //Edit:Hier ist ein SH-Bug void AllocationError () { cout << "Failed to allocate memory with 'new'!\n"; std::exit (255); } int main() { //... set_new_handler(AllocationError); }Oder gleich mit Lambdas.
Dasch geht auch:#include <iostream> #include <exception> int main() { long double *ptr; try { ptr = new long double[1000 * 1000 * 1000]; delete [] ptr; } catch(std::bad_alloc& b) { std::cerr << "Error allocating memory with new!\n" << b.what() << '\n';//Edit: Danke an Tyrroxx return 255; } }untegestet
-
Hacker schrieb:
#include <iostream> #include <exception> int main() { long double *ptr; try { ptr = new long double[1000 * 1000 * 1000]; delete [] ptr; } catch(std::bad_alloc& b) { std::cerr << "Error allocating memory with new!\n" << b.what() << '\n'; delete [] ptr; return 255; } }untegestet
gcc schrieb:
Warnung: »ptr« könnte in dieser Funktion uninitialisiert verwendet werden [-Wuninitialized]
-
TyRoXx schrieb:
gcc schrieb:
Warnung: »ptr« könnte in dieser Funktion uninitialisiert verwendet werden [-Wuninitialized]
Das delete im catch-Handler ist ja auch überflüssig. Wenns ein bad_alloc gibt, dann aus dem new, und dann hat erstens ptr noch nichts zugewiesen bekommen (daher die Warnung), und zweitens gibts dann auch nichts zu deleten.
-
War ja auch ungetestet, meine Güte. Hätte dann ja auch die Warnung gesehen.

Andererseits funktioniert es bei mir trotzdem prima.
-
Hacker schrieb:
War ja auch ungetestet,
Nö, es war untegestet, und das ist was ganz anderes.
-
Hacker schrieb:
War ja auch ungetestet, meine Güte. Hätte dann ja auch die Warnung gesehen.

Andererseits funktioniert es bei mir trotzdem prima.Bei mir rumst es, weil ich delete[] auf 'nem uninitialisierten Pointer ausführe.
-
Tachyon schrieb:
Hacker schrieb:
War ja auch ungetestet, meine Güte. Hätte dann ja auch die Warnung gesehen.

Andererseits funktioniert es bei mir trotzdem prima.Bei mir rumst es, weil ich delete[] auf 'nem uninitialisierten Pointer ausführe.
Komisch.. Ich führe es aus:
Codeblocks console runner schrieb:
Error allocating memory with new!
std::bad_allocProcess returned 255 (0xFF) execution time : 0.013 s
Press any key to continue.Danach presse ich einfach was, und das Ding verschwindet.
Ist das vielleicht IB (auch wenn ich mir verdammt sicher bin, dass der Standard das berücksichtigt)? Und was heißt bei dir rumsen?@arghonaut: Hör auf mit der Scheiße.
-
Es ist UB, und so obv.
-
314159265358979 schrieb:
und so obv.
Was?
Ich hab übrigens den Stanard-Teil gefunden:
3.7.4.1, Klausel 3:
C++-Standard schrieb:
An allocation function that fails to allocate storage can invoke the currently installed new-handler function, if any. [...(note)] If an allocation
function declared with a non-throwing exception-specification fails to allocate storage, it shall return
a null pointer. Any other allocation function that fails to allocate storage shall indicate failure only by
throwing an exception of a type that would match a handler (15.3) of type std::bad_alloc (18.6.2.1).Klausel 2 von 3.7.4 sagt, diese Funktionen sind die globalen:
void* operator new(std::size_t); void* operator new[](std::size_t);//Keine exception-specification void operator delete(void*); void operator delete[](void*);Also ist das kein UB.
-
Hacker schrieb:
Ich hab übrigens den Stanard-Teil gefunden:
Nee, das ist nicth der richtige Standard-Teil:
Ich schreib mal was dein Code macht:
long double *ptr; // = 0xirgendwas try { ptr = new long double[1000 * 1000 * 1000]; //heißt: //1) rufe operator new auf (wirft exception) //2) weise das Ergebnis ptr zu. HIER KOMMST DU NIE HIN } catch(std::bad_alloc& b) { //ptr hat hier immernoch den Wert 0xirgendwas std::cerr << "Error allocating memory with new!\n" << b.what() << '\n';//Edit: Danke an Tyrroxx delete[] ptr; // also delete 0xirgendwas - AUTSCH return 255; } }Dass es bei dir nicht kracht, ist vielleicht darauf zurückzuführen, dass dein Compiler im Debug-Build Variablen pauschal mit 0 initialisiert - delete NULL ist dann harmlos. Versuchs mal im Release-Build, oder weise ptr bei der Initialisierung explizit irgendeinen Müll zu.
-
314159265358979 schrieb:
Dein delete im catch-Block ist UB du Pflaume.
the behavior is undefined if the value supplied to operator
delete[](void*) in the standard library is not one of the values returned by a previous invocation of
either operator new[](std::size_t) or operator new[](std::size_t, const std::nothrow_t&) in the
standard library.Na gut, hast Recht.

Edit: @pumuckl: Immer noch alles gut... :p
#include <iostream> #include <exception> int main() { long double *ptr(0x16848486); try { ptr = new long double[1000 * 1000 * 1000]; delete [] ptr; } catch(std::bad_alloc& b) { std::cerr << "Error allocating memory with new!\n" << b.what() << '\n'; delete [] ptr; return 255; } }
-
Ich habe den Fehler gefunden:
Es war noch relativ alter Code und damals wusste ich nicht, dass man sowas hier nicht machen sollte:double b[n];Ich hab es jetzt durch
vector<double> b(n)ersetzt.
-
O.O du bist ja auch noch da.
-
Ramanujan schrieb:
Ich habe den Fehler gefunden:
Es war noch relativ alter Code und damals wusste ich nicht, dass man sowas hier nicht machen sollte:double b[n];Ich hab es jetzt durch
vector<double> b(n)ersetzt.
Gute Idee

Das war übrigens nicht nur alt, sondern auch falsch, da, wenn n keine Compilezeitkonstante ist, du da eine spezielle Compilererweiterung benutzt, die, soweit ich weiß, nur der GCC kennt. Der Fehler ist übrigens, dass du vorher das Array auf dem Stack (d.h. dem automatischen Speicher) angelegt hast. Normalerweise hat der eine recht restriktive Obergröße (meistens im einstelligen oder niedrigen zweistelligen Megabytebereich), sofern man nichts dagegen unternimmt (aber da sollte man gute Gründe für haben). Bei 1400000 double, das sind auf den meisten Systemen gut 10 MB, war dann einfach Schluss. vector legt die Daten im dynamischen Speicher (dem Heap) ab, da bist du normalerweise nur durch die vorhandene Hardware und/oder die Fähigkeiten des Betriebssystems beschränkt.
P.S.: Da ich die Begriffe etwas unklar benutzt habe eine Erläuterung: Der C++-Standard beschreibt drei (seit C++11 vier) verschiedenen Speicherarten von Variablen: statisch, automatisch und dynamisch. Stack (automatisch), Heap (dynamisch) und Datensegment (statisch) sind eine, aber nicht die einzige, mögliche Umsetzung dieser Konzepte, die von vielen C++-Implementierungen (und so ziemlich allen anderen Compilern für andere Sprachen auch) benutzt wird.
-
SeppJ schrieb:
Normalerweise hat der eine recht restriktive Obergröße (meistens im einstelligen oder niedrigen zweistelligen Megabytebereich)
AFAIR ca. 1 MB.
-
Hacker schrieb:
AFAIR ca. 1 MB.
Ist ganz plattformabhängig. Ich kann mich auf älteren Krücken an Stackoverflows bei 128MB erinnern...
-
Hacker schrieb:
SeppJ schrieb:
Normalerweise hat der eine recht restriktive Obergröße (meistens im einstelligen oder niedrigen zweistelligen Megabytebereich)
AFAIR ca. 1 MB.
[14:42:36][~][0]$ ulimit -a ... stack size (kbytes, -s) 8192 ...
-
Hab mich gerade erinnert, bei VC ist der default-wert für die stack größe 1MB. So hab ichs gelesen.