Arraywertige Funktion malloc.c:3096: sYSMALLOc...



  • Hallo,

    ich habe ein Problem mit einem Allokierungsfehler den ich nicht entschlüsseln kann. Ich habe meinen Quellcode mal so weit kleingeschnibbelt, damit nur noch das nötigste zur Erzeugung des Fehlers drinsteht. Es handlt sich nurnoch um ein Bruchstück, also wundert euch bitte nicht, falls ihr keinen Sinn in der Funktion erkennt. Der folgende Code sollte compilierbar und ausführbar sein:

    #include <string>
    
    class Knote
    {
    	private:
    		float x, y, z;
    	public:
    		Knote( float x, float y, float z, int name ): x(x), y(y), z(z), name(name), next(0) {};
    		int name;
    		Knote* next;
    };
    
    class Knoten
    {
    
    	private:
    		Knote* first;
    		Knote* last;
    
    	public:
    		Knoten(): first(0), last(0) {};
    		Knote* neuerKnoten( float x, float y, float z, int name );
    		Knote* neuerKnoten( float x, float y, float z );
    		Knote** toArray();
    		int getHighestName();
    
    };
    
    int Knoten::getHighestName()
    {
    	Knote* akt = first;
    	int highest = 0;
    	while( akt != 0 )
    	{
    		if( (*akt).name > highest ) highest = (*akt).name;
    		akt = (*akt).next;
    	}
    	return highest;
    }
    
    Knote** Knoten::toArray()
    {
    	int size = getHighestName() + 1;
    	Knote** array = new Knote*[ size ];
    	for( int i = 0; i <= size; i++ )
    	{
    		array[i] = 0;
    	}
    	Knote* akt = first;
    	while( akt != 0 )
    	{
    		array[ (*akt).name ] = akt;
    		akt = (*akt).next;
    	}
    	return array;
    }
    
    Knote* Knoten::neuerKnoten( float x, float y, float z, int name)
    {
    	if( first == 0 ) first = last = new Knote( x, y, z, name );
    	else last = (*last).next = new Knote( x, y, z, name );
    	return last;
    }
    
    Knote* Knoten::neuerKnoten( float x, float y, float z )
    {
    	return neuerKnoten( x, y, z, getHighestName() + 1 );
    }
    
    int main()
    {
    	Knoten k;
    	k.neuerKnoten( 1, 2, 3 );
    	//k.neuerKnoten( 1, 2, 3 );
    	Knote** arr = k.toArray();
    	int* arr2 = new int[1];
    }
    

    So wie es hier steht läuft es fehlerfrei. Wenn man jedoch die viertletzte Zeile nicht wegkommentiert, so kommt folgender Fehler:
    a.out: malloc.c:3096: sYSMALLOc: Assertion `(old_top == (((mbinptr) (((char 😉 &((av)->bins[((1) - 1) * 2])) - __builtin_offsetof (struct malloc_chunk, fd)))) && old_size == 0) || ((unsigned long) (old_size) >= (unsigned long)((((__builtin_offsetof (struct malloc_chunk, fd_nextsize))+((2 * (sizeof(size_t))) - 1)) & ~((2 * (sizeof(size_t))) - 1))) && ((old_top)->size & 0x1) && ((unsigned long)old_end & pagemask) == 0)' failed.
    Abgebrochen

    Der Fehler scheint in der Funktion Knoten::toArray() zu liegen. Wenn ich die aufrufe und anschließend ein neues Array, egal welchen Datentyps, erzeuge, dann kommt der Fehler. Er tritt aber nur auf, wenn ich zuvor die Funktion Knoten::neuerKnoten( float x, float y, float z ) eine gerade Anzahl oft aufgerufen habe. Wenn ich sie 1, 3, 5 usw mal aufrufe und anschließend Knoten::toArray() und danach ein weiteres Array erzeuge passiert nichts.

    Kann mir jemand:
    -sagen (oder sogar erklären) was ich falsch mache
    -zumindest die Aussage des Fehlers erklären
    -oder sagen wo ich hierzu hilfreiche Informationen finde

    Ich compiliere mit g++ unter xubuntu 11.10.

    Vielen Dank bereits im Voraus!


  • Mod

    Nein, das läuft nicht fehlerfrei. Du schreibst fröhlich über Arraygrenzen hinweg (Zeile 48). Du merkst es bloß zufällig nicht bei dem einen Knoten, weil das eben undefiniertes Verhalten ist und nicht unbedingt auffallen muss. Da du Linux benutzt, empfehle ich valgrind, um solche Fehler zu finden. So habe ich das so schnell gemacht, ohne deinen Code groß ansehen zu müssen.

    Was soll das Programm eigentlich machen? Das kann man garantiert VIEL besser machen, dein gegenwärtiger Code sieht schrecklich aus, ich mag gar nicht hinsehen. Hast du schon einmal etwas vom Drei-Sterne-Programmierer gehört? Das ist in C schon ein Anti-Pattern, aber in C++ so wild mit rohen Pointern rumjonglieren ist nun wirklich nicht nötig. Und wenn du es trotzdem tust, dann halte dich an gängige Sicherheitsvorschriften wie die Regel von den großen Drei oder gute Vorgehensweisen wie RAII.

    P.S.: Und was da übrigens genau schiefgeht: So wie es aussieht, überschreibst du durch deinen illegalen Zugriff gerade irgendwelche internen Verwaltungsdaten des Speicherallocators. Wenn dieser das nächste Mal gefragt ist, dann passieren schreckliche Dinge. Das ruft das interessante Phänomen hervor, dass das Programm in valgrind fehlerlos durchläuft, auch mit der auskommentierten Zeile. Dies liegt da dran, dass valgrind den Allocator ersetzt und der Allocator von valgrind ganz woanders seine Daten hat. Aber den illegalen Zugriff sieht man so natürlich trotzdem.


Anmelden zum Antworten