Pointer being freed was not allocated...

Résolu/Fermé
Utilisateur anonyme - 5 déc. 2016 à 00:10
mamiemando Messages postés 33079 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 23 avril 2024 - 8 déc. 2016 à 10:01
Bonsoir.
J'essaie de recoder la fonction unsetenv implémentée dans le csh, sans aucune fuite de mémoire.
J'ai placé des free() là où je suis censé libérer la mémoire (suite à un malloc par exemple).
Les fonctions suivantes que j'utilise dans mon code appellent le malloc et retournent une chaine fraîche "malloquée" : ft_strjoin et ft_strdup.
Autres infos :
"env" est en réalité un char ** en gros c'est les variables d'environnement du shell dans un tableau à deux dimensions mais ma fonction ft_unsetenv est appelée de loin donc j'ai du passer l'adresse de env plusieurs fois pour pouvoir modifier env depuis cette fonction du coup (**env)[i] est une chaine de caractère (une ligne dans le char ** d'environnement, genre le PATH=/bin/:/usr/bin).
ft_unsetenv est censée retirer une variable que l'utilisateur du shell appelle en argument.
Par exemple si mon char **env vaut {"Hello=test", "Ok=test", "World=test", NULL}, et que je choisis de supprimer "Ok=test" j'appelle ft_unsetenv avec l'argument "Ok", et je dois avoir en résultat {"Hello=test", "World=test", NULL}.
Ça marche plutôt bien, mais voilà j'ai un soucis avec les free : lorsque je veux supprimer le dernier élément de char **env ou alors si je veux supprimer plusieurs éléments d'un coup (unsetenv Hello Ok World) avec le dernier élément dedans, je reçois un "Pointer being freed was not allocated", pourtant il me semble avoir bien protégé free.
Quelqu'un saurait-t'il m'aider s'il vous plait ?


void	ft_delete(char **env)
{
	char	*tmp;

	while (*(env + 1))
	{
		tmp = (*env);
		(*env) = ft_strdup((*(env + 1)));
		if (tmp && *(env + 1))
			free(tmp); //visiblement, le problème du free vient d'ici mais je ne sais pas pourquoi
		env++;
	}
	if ((*env))
		free(*env);
	(*env) = NULL;
}

void	ft_unsetenv(char **command, char ****env)
{
	int	i;
	int	j;
	char	*cleaner;
	char	*tmp;

	i = 0;
	j = 1;
	while ((**env)[i])
	{
		while (command[j])
		{
			tmp = ft_strjoin((**env)[i], "=");
			cleaner = ft_strstr(tmp, command[j]);
			if (cleaner)
				ft_delete(&((**env)[i]));
			if (tmp)
				free(tmp);
			j++;
		}
		j = 1;
		i++;
	}
}

Merci !

1 réponse

mamiemando Messages postés 33079 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 23 avril 2024 7 749
Modifié par mamiemando le 7/12/2016 à 10:00
Bonjour,

Sans le code complet c'est un peu dur de déboguer et de suivre ton programme, mais en gros, tu fais un free sur un pointeur qui n'a pas été
malloc
. Un outil comme
valgrind
ou
gdb
te permettrait de déterminer à quelle ligne tu t'es trompé.

À titre personnel je trouve beaucoup bien compliquée la manière dont est écrite le programme pour quelque chose qui me paraît assez simple.

- Des boucles
for
seraient plus lisibles

- Il n'est pas forcément nécessaire de passer par un index pour progresser dans un tableau de pointeur (incrémenter un pointeur suffirait). Par exemple si tu as un tableau d'entier
int *tab
, et un pointeur sur la case courante int *pi = *tab (ici placé sur *tab == tab[0]), écrire pi++ le fait passer à la case suivante.

- Je suis sceptique sur le besoin de manipuler un
char ****
pour représenter ton environnement. Surtout qu'au final dans toute ta fonction tu utilises
**env
en pratique.

Exemple :

char * s = "bonjour";
char * pc;
for (pc = s; *pc; pc++) printf("%c", *pc);


Donc mon conseil serait :
1) simplifie ton code
2) débogue le avec
gdb
ou
valgrind
.
3) si tu es bloqué, donne nous un extrait de code minimal qu'on peut compiler et déboguer.

Bonne chance
0
Bonsoir mamiemando, merci pour ta réponse.

Je ne peux pas faire grand chose pour simplifier mon code étant donné que je suis une norme spécifique donc je n'ai pas le droit d'utiliser les boucles for :)
Je ne peux pas bouger mon pointeur sur env, parce-que je travaille directement avec son adresse ici donc j'ai besoin de réutiliser env dans d'autres fonctions en gardant un pointeur au début.
Sinon pour la manipulation d'un char **** c'est parce-que la fonction est appelée d'assez loin et j'ai besoin à chaque fois de modifier ma variable env.

gdb et valgrind n'ont rien donné, c'est pour ça que j'ai demandé de l'aide ici.
Sinon, j'ai réussi à debugguer mon programme, la source du problème venait d'une autre fonction (setenv, celle d'insertion des éléments dans l'environnement). En gros, les variables d'environnement récupérées au lancement du programme n'ont pas nécessité une allocation de mémoire avec malloc, ou alors le pointeur a bougé depuis. Donc évidemment, lorsque j'essayais de les free, je recevais une erreur (tandis que je pouvais free les NOUVEAUX éléments ajoutés par mon programme, qui eux, ont demandé un malloc).
Pour régler le problème, j'ai tout simplement placé dans un buffer (déclaré en static), à la suite, tous les nouveaux éléments que j'ai malloc : donc au moment du free, je vérifie si le pointeur existe (chose que je faisais déjà) ET que la variable que j'essaie de supprimer se trouve dans le buffer (ce qui implique qu'elle a été malloc par mon programme).

Voilà :)

Bonne soirée.

PS : voici le code modifié et fonctionnel

void	ft_delete(char **env)
{
	while (*(env + 1))
	{
		(*env) = *(env + 1);
		env++;
	}
	(*env) = NULL;
}

void	ft_unsetenv(char **command, char ****env, char *buffer)
{
	int		i;
	int		j;
	char	*tmp;

	i = 0;
	j = 1;
	while ((**env)[i])
	{
		while (command[j])
		{
			tmp = ft_strjoin(command[j], "=");
			if (ft_strstr((**env)[i], tmp))
			{
				if (buffer && ft_strstr(buffer, tmp))
					free((**env)[i]);
				ft_delete(&((**env)[i]));
			}
			free(tmp);
			j++;
		}
		j = 1;
		i++;
	}
}
0
mamiemando Messages postés 33079 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 23 avril 2024 7 749
8 déc. 2016 à 10:01
Merci pour ton retour :-)
0