J'ai un code en C++ qui appelle une libraire C qui me retourne un tableau
while(...){
tmp tab =GetMachinTruc()
//DoSomething
}
où GetMachinTruc vient de la librairie C
dans le code de UINT16* GetMachinTruc()
tab=malloc()...
return tab
Donc j'ai donc mon tmptab qui est alloué dans GetMachinTruc
ce qui me donne sachant que je suis dans une loop une grosse fuite de mémoire.
Si je fait
while(...) {
UINT16* tmptab=GetMachinTruc
//Do Something with tmptab
free(tmptab)
}
J'ai droit a une superbe Segmentation fault pareil si j'utilise delete (car je le rapelle mon code est en C++ c'est la librairier qui est en C)
C'est là ou je me rend compte qu'en fait je suis à la masse sur la gestion de la mémoire, entre multiple fonction
-Est il autorisé d'éffacer un pointeur alloué ailleur ?
Si non pourquoi le compilateur n'a rien dit ?
-Y a t'il d'autre vérification à faire avant ?
Merci à tous
P.S.
//Do something correspond à copier le pointeur dans un container civilisé (un vecteur) qui lui même est propagé par référence dans tout le code.
# Plusieurs remarques
Posté par TortuXm . Évalué à 3.
Ensuite, si une zone mémoire est allouée avec "new", alors il faut la libérer avec "delete", si elle est allouée avec "new[]", on la libère avec "delete[]" et si elle est allouée comme en C avec malloc ou calloc ou les autres variantes, on la libère avec free.
"Est il autorisé d'éffacer un pointeur alloué ailleur" n'a pas vraiment de sens en C ou en C++. On peut libérer un pointeur qui a été alloué par le processus courant. On ne peut pas libérer deux fois le même pointeur, ni libérer une adresse mémoire invalide
Un petit exemple qui plante forcément :
char * pointer = malloc(3);
int i = 0;
for (i = 0; i < 3; i++)
*pointer++ = 0;
free(pointer);
--> on aura une erreur puisqu'on essaye de libérer une zone mémoire invalide.
Sans en savoir plus, je pencherais sur un problème du type expliqué ci-dessus, ou alors tout simplement la zone mémoire libérée est utilisée ensuite dans un traitement ultérieur.
[^] # Re: Plusieurs remarques
Posté par Mais qui suis-je ? :) . Évalué à 1.
Merci pour tes précisions
-Oui je sais qu'en C++ c'est plutôt du new/delete Saut qu'en pratique je linke dynamiquement un code C avec un code C++ sans passer par un wrapper ou quelque chose de ce genre là.
-Alors si la zone de mémoire libérée était utilisé plus tard j'imagine que j'aurais le segmentation fault plus tard est pas à l'appel de free (gdb m'indique clairement que le segmentation fault a lieu à l'appel de free)
Sur le traitement que je fait subir à mon pointeur :
198 UINT16* tmpseries=getChannelXData(ch_id+1); //Ici je fait appel à une libraire C dynamique
199 for (int ii=0;ii<numberofsamples;++ii) {
200 thistrace.PushBack(double(tmpseries[ii])); //(écriture dans un "vecteur à notre sauce")
201 }
202 if (tmpseries!=NULL) {
203 free(tmpseries);
204 tmpseries=NULL;
205 }
Sachant que si je ne delete pas tmpseries, les valeurs propagée dans la suite du programme ne sont pas abérantes, donc je ne pense pas qu'il y ai d'erreur à l'écriture ou à la lecture
[^] # Re: Plusieurs remarques
Posté par TortuXm . Évalué à 2.
Je n'en suis pas sûr du tout, mais le fait de libérer les données en dehors de la librairie pourrait être la cause du plantage si c'est une librairie dynamique.
[^] # Re: Plusieurs remarques
Posté par Mais qui suis-je ? :) . Évalué à 1.
(Et la variable retournée est locale dans la fonction)
J'en ai touché 2 mots à mon collègues, j'éspère que quelque chose va en sortir rapidement sinon je devrais m'en ocupper moi même.
[^] # Re: Plusieurs remarques
Posté par shbrol . Évalué à 1.
Sinon, pour le code source reproduit ici, il n'est pas necessaire de tester le pointeur à NULL avant de faire le free(), ca ne sert a rien. Par contre, avant la boucle for, ca pourrait être plus utile...
[^] # Re: Plusieurs remarques
Posté par ǝpɐןƃu∀ nǝıɥʇʇɐW-ǝɹɹǝıԀ (site web personnel) . Évalué à 2.
Malheureusement je n'ai pas la solution du problème. Juste quelques commentaires. Désolé.
Il me semble évident que vous avez bien parfaitement modélisé le problème. Et pour autant que je sache votre free semble parfaitement valide. Si tant est que le modèle présenté est correct.
Je ne vois donc que quelques commentaires à faire :
- avez vous envisagé qu'en réalité les choses ne se passent pas exactement comme prévu. Par exemple le pointeur tmptab n'est pas vraiment alloué comme prévu, etc. Et dans ce cas il faut suivre au debugger ce qui se passe étape par étape pour soudain observer que le modèle n'est pas bon.
- Une autre possibilité serait un bug du compilateur (par exemple lié au mélange de C et C++). Mais ce serait tellement étrange. À la fois faire le test ne coûte pas grand chose…
- Quelque part, il me semble avoir lu que les mélanges de malloc/free et new/delete sont proscrits ; non seulement pour un tableau (ça vous l'avez parfaitement respecté) mais aussi dans un même code. Je ne suis pas certains que ce soit juste cependant. Le même bouquin prétendait qu'il était cependant possible moyennant quelques précautions de faire le mélange. Si votre problème n'est pas résolu d'ici lundi, je me ferais un plaisir de vous rapporter ce que disait ce livre.
« IRAFURORBREVISESTANIMUMREGEQUINISIPARETIMPERAT » — Odes — Horace
[^] # Re: Plusieurs remarques
Posté par shbrol . Évalué à 4.
Ce qui pose problème, c'est la libération par free() d'un pointeur alloué par new, et réciproquement delete pour malloc(). Mais il n'y a pas de contre indication technique a l'utilisation des deux systêmes dans le même code, sous réserver de respecter la régle précédente.
Eventuellement, on pourra dire que le mélange des deux est une faute de style, une horreur pour la maintenance, une plaie pour la gestion des erreurs, etc. mais ca ne va pas plus loin.
Autrement dit, si le bouquin en question affirme que le code suivant est proscrit pour raison technique :
void foobar() {
char* x = (char*)malloc(1) ;
char* y = new(nothrow) char ;
// ...
delete y ;
free(x);
}
alors mauvais bouquin, changer bouquin.
[^] # Re: Plusieurs remarques
Posté par RodZilla . Évalué à 1.
[^] # Re: Plusieurs remarques
Posté par JoeltheLion (site web personnel) . Évalué à 3.
Il y a très peu de programmes qui "plantent" forcément. On a un comportement indéfini, qui peut ou non se traduire par un plantage. C'est important de le savoir, parce que ce n'est pas parce qu'un programme ne plante pas qu'il ne contient pas d'erreur de gestion de la mémoire.
[^] # Re: Plusieurs remarques
Posté par TortuXm . Évalué à 2.
En particulier, accéder un pointeur non défini peut très bien fonctionner en fonction de "où on tombe", d'où des bugs détectés parfois très tard.
Pour mon exemple, il me semble que dans ce cas précis, la libc détecte immédiatement l'erreur, mais il est vrai que dans parfois, c'est bien plus tard que la corruption est détectée, et c'est alors difficile de remonter à la vraie erreur.
[^] # Re: Plusieurs remarques
Posté par fearan . Évalué à 4.
Depuis que j'ai eu accès à ce truc les fuites mémoires sont un lointain souvenir
Alfonse Zeymer
Il ne faut pas décorner les boeufs avant d'avoir semé le vent
# free ... ou pas ?
Posté par gaaaaaAab . Évalué à 3.
c'est autorisé, mais déconseillé.
La règle usuelle : c'est celui qui alloue qui désalloue
Confier l'allocation et la désallocation à des layers différents du code complique énormément la maintenance (et donc favorise les bugs).
Là, c'est à la lib de fournir les APIs qu'il faut pour (au choix):
- désallouer la mémoire allouée,
- laisser la charge de l'allocation/désallocation à l'appelant
//Do something correspond à copier le pointeur dans un container civilisé (un vecteur) qui lui même est propagé par référence dans tout le code.
possible que j'interprète mal, mais si tu copie des *pointeurs* dans ton vecteur, et que tu désalloues la mémoire pointée, forcément ...
[^] # Re: free ... ou pas ?
Posté par shbrol . Évalué à 1.
Tu interprète mal, regardes les ligne 199-200 dans le codé posté ci-dessus : le pointeur en question est en fait un tableau, et il y a copie du contenu de ce tableau dans un vecteur via une boucle for. Donc le pointeur lui même n'est pas mémorisé, il n'est plus utilisé après la boucle, on peut le libérer.
Pour le reste, 100% d'accord.
# déjà
Posté par Axioplase ıɥs∀ (site web personnel) . Évalué à 3.
Donc tu files ton code, ta lib, et à partir de là, on regarde.
Sinon, une question :
int* tab=allocmachin();
tab++;
free(tab)
ne risque-t-il pas de causer un bug car tu fais un free au pif, et non au point de départ de tes données allouées ?
Je ne sais pas comment malloc gère la mémoire, mais je pense qu'il n'aime pas (lui, ou l'OS) qu'on lui demande de désallouer des données qui ne sont pas connues (car j'imagine qu'il tient à jour une table de (adresse-initiale, taille-allouée))
Suivre le flux des commentaires
Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.