2014-12-24 4 views
17

Zuerst weiß ich ähnlich Fragen wurden gestellt. Ich möchte jedoch eine allgemeinere einfache Frage mit wirklich primitiven C-Datentypen haben. Hier ist es also.Valgrind - Adresse ---- ist 0 Bytes nach einem Block der Größe 8 alloc'd

In main.c nenne ich eine Funktion jene Zeichenfolge zu füllen:

int 
main (int argc, char *argv[]){ 

    char *host = NULL ; 
    char *database ; 
    char *collection_name; 
    char *filename = ""; 
    char *fields = NULL; 
    char *query = NULL; 
    ... 

    get_options(argc, argv, &host, &database, &collection_name, &filename, 
       &fields, &query, &aggregation); 

Innen get_options:

if (*filename == NULL) { 
    *filename = (char*)realloc(*filename, strlen(*collection_name)*sizeof(char)+4); 
    strcpy(*filename, *collection_name); 
    strcat(*filename, ".tde"); # line 69 
} 

Mein Programm funktioniert gut, aber dann Valgrind sagt mir, ich es falsch mache:

==8608== Memcheck, a memory error detector 
==8608== Copyright (C) 2002-2011, and GNU GPL'd, by Julian Seward et al. 
==8608== Using Valgrind-3.7.0 and LibVEX; rerun with -h for copyright info 
==8608== Command: ./coll2tde -h localhost -d test -c test 
==8608== 
==8608== Invalid write of size 1 
==8608== at 0x403BE2: get_options (coll2tde.c:69) 
==8608== by 0x402213: main (coll2tde.c:92) 
==8608== Address 0xa2edd18 is 0 bytes after a block of size 8 alloc'd 
==8608== at 0x4C28BED: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) 
==8608== by 0x4C28D6F: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) 
==8608== by 0x403BBC: get_options (coll2tde.c:67) 
==8608== by 0x402213: main (coll2tde.c:92) 

Können Sie das erklären Fehler Address 0xa2edd18 is 0 bytes after a block of size 8 alloc'd? Wie kann ich dieses Problem lösen?

Antwort

27

strcpy fügt ein Nullabschlusszeichen '\0' hinzu. Sie haben vergessen, Platz für sie zu reservieren:

*filename = (char*)realloc(*filename, strlen(*collection_name)*sizeof(char)+5); 

Sie brauchen Platz für 5 Zeichen hinzuzufügen: 4 für ".tde" Suffix, und eine weitere für die '\0' Terminator. Ihr aktueller Code weist nur 4 zu, so dass der letzte Schreibvorgang in den Speicherbereich unmittelbar nach dem Block erfolgt, den Sie für den neuen Dateinamen reserviert haben (d. H. 0 Byte nach dem Block).

Hinweis: Ihr Code hat ein häufiges Problem - er ordnet die Ergebnisse von realloc direkt einem neu zugewiesenen Zeiger zu. Das ist in Ordnung, wenn realloc erfolgreich ist, aber wenn es fehlschlägt, erstellt ein Speicherverlust. diesen Fehlers Fixierung erfordert das Ergebnis realloc in einem separaten Variable speichern, und ihn für NULL, bevor den Wert wieder auf *filename Zuweisen Überprüfung:

char *tmp = (char*)realloc(*filename, strlen(*collection_name)*sizeof(char)+5); 
if (tmp != NULL) { 
    *filename = tmp; 
} else { 
    // Do something about the failed allocation 
} 

Zuordnung direkt an *filename schafft einen Speicherverlust, weil der Zeiger der *filename wurde Nach unten zeigen würde bei einem Fehler überschrieben und nicht wiederherstellbar.

+0

douh! Ich habe das schon mal ausprobiert und aus irgendeinem Grund entferne ich es. Also muss ich hier vorsichtiger sein! Aber warum das vage Englisch? Wenn meine neu erstellte Zeichenfolge um 1 größer ist, warum sagt Valgrind dann: 0 Bytes nach ...? – Oz123

+5

Ok, du hast es schon kommen sehen. Also, "0 Bytes nach" ist Valgrind Entwickler Weg, um mir in einfachem Englisch zu sagen: "Es ist nebenan", oder "direkt danach". – Oz123

+0

@ Oz123: '0 Bytes nach 'ist so korrekt wie' 42 Bytes nach ', oder? – alk