2016-09-13 4 views
-4

J'écris un programme simple sous Linux. Son but est d'afficher le numéro de version GNU. Mais il semble que la fonction free() me crie dessus. Quand j'exécute le programme. Il montre les éléments suivants:Echec de la fonction gratuite

* Erreur dans `./a.out ': munmap_chunk(): pointeur non valide: 0x00007fa89f028d8a *

et Backtrace et carte mémoire.

Ci-dessous mon code:

# include <stdio.h> 
# include <gnu/libc-version.h> 
# include <string.h> 
# include <stdlib.h> 

int main(void){ 
     const char *s; 
     s = (const char *)malloc(16*sizeof(char)); 
     s = gnu_get_libc_version(); 
     printf("%s\n",s); 
     free((char *)s); 
     return 0; 
} 
+0

Qu'est-ce qu'un "numéro de version GNU"? Les Gnous en Afrique ont-ils des versions? Et ne lancez pas de 'void *' dans C! 'free' prend un' void * ', pas un' char * ' – Olaf

+0

Sur la ligne 9, vous avez une fuite de mémoire car votre mémoire allouée est toujours là mais vous la réaffectez à gnu_get_libc_version(). gnu_get_libc_version renvoie un pointeur constant vers la chaîne pour vous. vous essayez de libérer de la mémoire qui n'a pas besoin d'être libérée (la version gnu_get_libc_version), et appeler gratuitement sur tout autre chose que le pointeur de la mémoire dynamique l'amène à vous crier dessus. Indication, le prototype de gnu_get_libc_version est 'const char * gnu_get_libc_version (void); notez le const char *, c'est souvent un indice que la chaîne renvoyée n'est pas destinée à être libérée. – Dmitry

+0

Merci! J'ai réalisé que la question était un peu bête. –

Répondre

0

Cette fonction gnu_get_libc_version() retourne probablement un pointeur vers la mémoire statique.

+0

Même si ce n'est pas le cas, l'affectation écrase le pointeur sur la mémoire allouée. – Olaf

+0

Vous avez raison. Cette fonction renvoie un pointeur vers la mémoire statique. –

2

Vous avez perdu le pointeur renvoyé par malloc au moment de la réinitialisation s avec la valeur de retour gnu_get_libc_version. Vous essayez maintenant de free le pointeur renvoyé par gnu_get_libc_version qui n'a pas été alloué par malloc.

Vous n'avez pas besoin malloc avant d'appeler gnu_get_libc_version et n'avez pas besoin de free après l'avoir appelé.

+0

Merci! J'ai réalisé que je viens d'écraser le pointeur. –

1
s = gnu_get_libc_version(); 

Cela ne fait pas ce que vous croyez. Il semble que vous vous attendiez à ce qu'il remplisse la mémoire que vous avez précédemment allouée, la mémoire qui est pointée par s.

Qu'est-ce qu'il fait fait est la cause s à pointera quelque part totalement différent, quelque part qui est décidé par la fonction gnu_get_libc_version.

Étant donné l'erreur free et l'utilisation de l'exemple dans le documentation, il y a un meilleur que même la chance cette mémoire est pas allouée dans le tas, en essayant donc de le libérer entraînera un comportement non défini. En supposant que gnu_get_libc_version renvoie effectivement l'adresse d'une chaîne de style C et qu'elle ne provienne pas du tas (et cela semble certainement être le cas sur le lien ci-dessus), vous n'avez pas besoin d'allouer la mémoire pour il. Au lieu de cela, vous pouvez simplement avoir:

int main(void) { 
    const char *s = gnu_get_libc_version(); 
    printf("%s\n", s); 
    return 0; 
} 

ou même la plus courte (en utilisant puts et la valeur de retour directement):

int main(void) { 
    puts(gnu_get_libc_version()); 
    return 0; 
} 

Si vous ne veulent obtenir les informations de version dans votre propre mémoire tampon allouée (et en supposant que vous avez assez de mémoire pour cela), vous pouvez utiliser:

int main(void){ 
    const char *s = malloc(16); 
    strcpy(s, gnu_get_libc_version()); 
    printf("%s\n", s); // or puts(s) 
    free(s); 
    return 0; 
} 

Cette copies la chaîne (de la zone retournée de gnu_get_libc_version) dans votre propre tampon, plutôt que de changer s pour pointer ailleurs.


Notez que j'ai modifié d'autres éléments dans votre code d'origine. La première consiste à supprimer la distribution explicite de la valeur de retour malloc.C'est quelque chose qui ne devrait pas être fait en C car il peut cacher certaines erreurs subtiles. C est parfaitement capable de implicitement en renvoyant la valeur de retour void * à un autre type de pointeur.

La seconde est la distribution en free qui est également inutile pour la même raison.

La troisième et dernière modification consiste à supprimer la multiplication par sizeof(char). Cette valeur est garantie par la norme 1 donc il n'y a aucune raison technique pour laquelle cela est nécessaire.

+0

Merci! Votre réponse était très complète et multiforme. J'ai beaucoup appris. –

0

Dans cette ligne

s = gnu_get_libc_version(); 

réattribuer le s à un autre char * qui par retour gnu_get_libc_version. Comme l'ancienne valeur de s, qui a été allouée par malloc, est perdue, ce qui entraîne une fuite de mémoire. Et le retour char * par gnu_get_libc_version n'a pas été alloué par malloc, donc lorsque vous appelez free sur un pointeur qui n'est pas retourné par malloc, une erreur se produit. s = gnu_get_libc_version();

+0

Merci beaucoup! J'ai besoin d'apprendre et de rechercher plus. –