realloc - double free or corruption



  • Hallo zusammen,

    anhand einer Datei baue ich in einer Schleife einen String als char* zusammen. Danach würde ich diesen gerne für spätere Benutzung in einem Array speichern.

    Ich prüfe, ob dieses Array voll ist und versuche es dann mit realloc zu vergrößern. Irgendwo werden dabei aber Pointer beschädigt, sodass es zu einem double free or corruption Fehler kommt.

    // save current character from file
    current_line[i] = c;
    
    // ...
    
    // check if "my_map" has to be resized
    if(lines >= my_map) {
     my_map_size+=10;
     my_map = (char**) realloc(my_map, my_map_size);
    }
    
    // save current_line in array for later use
    my_map[lines] = current_line;
    
    free(current_line);
    

    Hat jemand eine Idee, woran das liegen könnte?

    Vielen Dank
    freakC++



  • Was hat my_map mit current_line zu tun?



  • if(lines >= my_map) {
    my_map_size+=10;
    my_map = (char**) realloc(my_map, my_map_size);
    }

    ?

    Irgendwie schaut das alles seltsam aus.



  • In my_map sollen die fertigen Zeichenketten (current_line) gespeichert werden. Diese sind vom Typ char*. Eine Zeichenkette stellt eine Zeile dar. Daher ist lines der Arrayindex.

    Im if-Block soll das zu kleine Array vergrößert werden.


  • Mod

    Mindestens das was Mechanics genannt hat ist schon einmal falsch. C-Allokationen sind nicht wie new aus C++, die können nicht sehen, mit welchen Typen du planst. Höchstwahrscheinlich ist aber noch viel mehr falsch, da dieser Fehler nicht unbedingt die Meldung erklärt. Daher wäre es hilfreich, ein vollständiges, compilierbares Minimalbeispiel zu präsentieren.

    Höchst verdächtig sind beispielsweise auch die Zeilen 13 und 15. Kann kontextabhängig korrekt sein, ist es aber höchstwahrscheinlich nicht. Daher wäre es wichtig für uns, den Kontext zu kennen, damit wir weniger spekulieren müssen.



  • ΘEigentlich passiert da nicht mehr sonderlich viel. Hier ist etwas mehr Kontext:

    char** my_map = (char**) malloc(my_map_size * sizeof(char*));
    
    while ((c = getc(fp)) != EOF) {
    
    	// init ...
    
    	// resize string if necessary
    	if(i >= n) { 
    		char* tmp = (char*) malloc(sizeof(char) * i);
    		memcpy(tmp, current_line, i);
    		free(current_line);
    		n+=chunk_size;
    		current_line = (char*) malloc(sizeof(char) * n);
    		memcpy(current_line, tmp, i);
    		free(tmp);
    	}
    
    	// save current character
    	current_line[i] = c;
    	i++;
    
    	// reached EOL
    	if(c == '\n') {
    		if(i <= n) { // truncate oversized line
    			char* tmp = (char*) malloc(sizeof(char) * i);
    			memcpy(tmp, current_line, i);
    			current_line = (char*) malloc(sizeof(char) * i);
    			memcpy(current_line, tmp, i);
    			free(tmp);
    		}
    
    		// add line to my_map and extend my_map if necessary
    		if(lines >= my_map) {
    			my_map_size+=10;		
    			my_map = (char**) realloc(my_map, my_map_size);
    		}
    
                    my_map[lines] = (char*) malloc(sizeof(char) * i); // ERROR
    		my_map[lines] = current_line;
    
    		free(current_line);
    		lines++;
    	}
    }
    

    Der Zugriff in Zeile 36 verursacht den Fehler, nachdem realloc zum ersten Mal aufgerufen worden ist. Ich vermute, dass my_map[lines] ins Nirvana zeigt...


  • Mod

    War "compilierbar" als Anforderung unverständlich?

    Zeilen 8-16 und 23-30: Wieso programmierst du ein eigenes, schlechtes realloc?

    33-35 sind falsch, wie bereits gesagt wurde. Besonders die Zeilen 33 und 35. Erklär mal 33 in Worten.

    38-39 sind doch Quatsch. Erklär mal in deinen eigenen Worten, was du denkst, was da passiert, insbesondere in Zeile 39.

    Zeile 41 ist wie vorhergesagt falsch. Weil deine Zeilen 38-39 was anderes machen als du denkst.

    Da sind noch viele weitere Kleinigkeiten, aber der Code ist insgesamt so falsch, dass sich eine Korrektur nicht lohnt. Besonders die Sequenz 38-41 sticht heraus. Du solltest dich erst einmal gründlich damit beschäftigen, wie Arrays, Zeiger und dynamische Speicherverwaltung funktionieren. Das ist in C nämlich anders als du dies aus anderen Sprachen gewohnt sein könntest.

    Ein paar der wichtigsten Punkte, die du falsch gemacht hast:
    -Arrays sind keine Pointer, Pointer sind keine Arrays.
    -Arrays haben keine Kopiersemantik. Pointer haben zwar eine Kopiersemantik, aber dies ist keine "Deep Copy". Ein Pointer hat keine Ahnung von der Semantik der Objekte, auf die er zeigt.
    -Die ganzen Allokationsfunktionen in C haben keine Ahnung von den Datentypen, für die du Speicher reservierst. Das ist einfach nur roher Speicher. du musst dich selber darum kümmern, dass das alles passt.
    -Du weißt nicht, wie realloc arbeitet.



  • SeppJ schrieb:

    Zeilen 8-16 und 23-30: Wieso programmierst du ein eigenes, schlechtes realloc?

    Weil ich realloc falsch verstanden habe.

    SeppJ schrieb:

    33-35 sind falsch, wie bereits gesagt wurde. Besonders die Zeilen 33 und 35. Erklär mal 33 in Worten.

    Ja, das sollte natürlich my_map_size heißen.

    38-39 sind doch Quats

    SeppJ schrieb:

    -Du weißt nicht, wie realloc arbeitet.

    Richtig

    Mittlerweile weiß ich es. Ich habe einfach ein sizeof(char) vergessen.

    Also so:

    my_map = (char**) realloc(my_map, my_map_size * sizeof(char*));
    

    Naja, ihr hättet mir diesen blöden Fehler sicherlich gesagt, wenn ihr es gesehen hättet. Diese eigenen realloc Hacks sind jetzt rausgeflogen, weil ich ja jetzt meinen Fehler kenne 🕶



  • freakC++ schrieb:

    Mittlerweile weiß ich es. Ich habe einfach ein sizeof(char) vergessen.

    Wirklich verstanden?

    Denn sizeof(char) ist per Definition 1.
    Also sollte das keine Auswirkung haben.



  • Da fehlt natürlich ein . Ich habe ein sizeof(char) vergessen.



  • Auch das ist falsch.


Log in to reply