Ten eerste weet ik dat er vergelijkbarevragen zijn gesteld. Ik zou echter graag een meer algemene, eenvoudige vraag willen hebben met echt primitieve C-gegevenstypen. Dus hier is het.
In main.c
roep ik een functie aan om die string te vullen:
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);
Inside get_options
:
if (*filename == NULL ) {
*filename = (char*)realloc(*filename, strlen(*collection_name)*sizeof(char)+4);
strcpy(*filename, *collection_name);
strcat(*filename, ".tde"); # line 69
}
Mijn programma werkt prima, maar dan zegt Valgrind dat ik het verkeerd doe:
==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)
Kun je de fout uitleggen Address 0xa2edd18 is 0 bytes after a block of size 8 alloc'd
?
Hoe kan ik dit probleem oplossen?
Antwoord 1, autoriteit 100%
strcpy
voegt een null-terminatorteken toe '\0'
. Je bent vergeten er ruimte voor toe te wijzen:
*filename = (char*)realloc(*filename, strlen(*collection_name)*sizeof(char)+5);
Je moet ruimte toevoegen voor 5 tekens: 4 voor het achtervoegsel ".tde"
en nog een voor de terminator '\0'
. Uw huidige code wijst slechts 4 toe, dus de laatste keer schrijven wordt gedaan in de ruimte onmiddellijk na het blok dat u hebt toegewezen voor de nieuwe bestandsnaam (d.w.z. 0 bytes erna).
Opmerking:Uw code heeft een veelvoorkomend probleem: het wijst de resultaten van realloc
rechtstreeks toe aan een aanwijzer die opnieuw wordt toegewezen. Dit is prima wanneer realloc
succesvol is, maar creëert een geheugenlek wanneer het mislukt. Om deze fout op te lossen, moet het resultaat van realloc
in een aparte variabele worden opgeslagen en moet worden gecontroleerd op NULL
voordat de waarde weer wordt toegewezen aan *filename
:
char *tmp = (char*)realloc(*filename, strlen(*collection_name)*sizeof(char)+5);
if (tmp != NULL) {
*filename = tmp;
} else {
// Do something about the failed allocation
}
Rechtstreeks toewijzen aan *filename
creëert een geheugenlek, omdat de aanwijzer waarnaar de *filename
hieronder verwijst, bij een fout wordt overschreven en niet meer kan worden hersteld.
Antwoord 2, autoriteit 2%
Ik kreeg zojuist dit bericht omdat ik een klasse had gewijzigd (een veld had toegevoegd, dus de grootte ervan had gewijzigd) en niet alle bronnen die de header bevatten opnieuw had opgebouwd. Dus sommige modules probeerden nog steeds het oude formaat te gebruiken.