Tout d'abord, je sais similaire des questions ont été posées. Cependant, j'aimerais avoir une question simple plus générale avec les types de données C vraiment primitifs. Alors voilà.
Dans main.c
J'appelle une fonction pour remplir ces chaînes:
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);
À l'intérieur get_options
:
if (*filename == NULL ) {
*filename = (char*)realloc(*filename, strlen(*collection_name)*sizeof(char)+4);
strcpy(*filename, *collection_name);
strcat(*filename, ".tde"); # line 69
}
Mon programme fonctionne bien, mais Valgrind me dit que je le fais mal:
==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)
Pouvez-vous expliquer l'erreur Address 0xa2edd18 is 0 bytes after a block of size 8 alloc'd
? Comment puis-je résoudre ce problème?
strcpy
ajoute un caractère de terminaison nul '\0'
. Vous avez oublié de lui allouer de l'espace:
*filename = (char*)realloc(*filename, strlen(*collection_name)*sizeof(char)+5);
Vous devez ajouter de l'espace pour 5 caractères: 4 pour ".tde"
suffixe, et un de plus pour le '\0'
terminateur. Votre code actuel n'en alloue que 4, donc la dernière écriture est effectuée dans l'espace immédiatement après le bloc que vous avez alloué pour le nouveau nom de fichier (c'est-à-dire 0 octet après).
Remarque: Votre code a un problème commun - il assigne les résultats de realloc
directement à un pointeur en cours de réallocation. C'est très bien lorsque realloc
réussit, mais crée une fuite de mémoire en cas d'échec. La correction de cette erreur nécessite de stocker le résultat de realloc
dans une variable distincte et de le vérifier pour NULL
avant de réaffecter la valeur à *filename
:
char *tmp = (char*)realloc(*filename, strlen(*collection_name)*sizeof(char)+5);
if (tmp != NULL) {
*filename = tmp;
} else {
// Do something about the failed allocation
}
Affectation directe à *filename
crée une fuite de mémoire, car le pointeur *filename
indiqué ci-dessous serait écrasé en cas d'échec et deviendrait irrécupérable.