Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

warning: function returns address of local variable

65 réponses
Avatar
pere.noel
à la compile d'un ensemble de fonctions + main, j'ai le message de
warning :
function returns address of local variable
pour la fonction "target_path_normalize"

le but de cette fonction :
si j'ai en entrée :

target_path_checked =
////Users////yvon/./////////////////////work/C/../.headers
toto/CFArray.h

elle retourne ce path normalisé :
target_path_normalized = /Users/yvon/work/.headers toto/CFArray.h

cette fonction "marche" mais je me demande quel risque je prends en
laissant trainer ce warning

le contexte : avant l'utilisation de cette fonction, j'en utilise une
autre "target_path_check" qui retourne NULL si le path n'est pas absolu
et accessoirement supprime le "/" en fin de chaîne s'il existe.

--- target_path_normalize ---------------------------------------------
char* target_path_normalize(const char* target_path)
{
int trente_deux = 32; /* maximum de répertoires traversés */
int mille_vingt_quatre = 1024; /* taille maximum d'un path */
char p[mille_vingt_quatre]="";
char *q;
char *token;
const char needle[] = "/";
const char *dot = ".";
const char *dotdot = "..";
int j;
q = strdup(target_path);
j = 0;
char *pieces[trente_deux];
// initialisation des éléments du tableau à NULL
while(j < trente_deux) {
pieces[j] = NULL;
j++;
}

// démarrage du découpage de q (target_path)
token = strtok(q, needle);
j = 0;

// découpage de q (target_path)
while(token != NULL) {
// si ".." on décrémente j equivalent à cd ..
// si "." on ne fait rien
// si différent de ".." et de "." on enregistre token dans
pieces[j] et on incrémente j
if(strcmp(token, dotdot) == 0) {
j--;
} else if(strcmp(token, dot) != 0) {
pieces[j]=token;
j++;
}
token = strtok(NULL, needle);
}
j = 0;

// concaténation de "/" (needle) et de pieces[j] jusqu'à épuisement
(quand pieces[j] == NULL)
while(pieces[j] != NULL) {
strcat(p, needle);
strcat(p, pieces[j]);
j++;
}
return p;
}
-----------------------------------------------------------------------
donc c'est le "return p" qui pose pb à la compil mais pas à
l'utilisation.
--
une bévue

10 réponses

1 2 3 4 5
Avatar
pere.noel
johann.d wrote:

Une bonne habitude est de toujours suivre un free d'une affectation à NULL :


ben oui, je sais ça.

ptr = malloc(...);
if (ptr == NULL) return AIEAIEAIE;
/* do some job */
free(ptr);
ptr = NULL;
/* do some other job */
printf("%sn", ptr); // ici ptr est NULL donc l'erreur devrait être franche


MAIS gros prob le ptr, dans mon cas est la valeur retournée ...

en gros, pour l'instant, je fais ça (sans le free))) :

char* target_path_dirname(const char* target_path) {
[...]
p = (char *) malloc (PATH_SIZE_MAX * sizeof (char));
if (p == NULL)
{ /* l'allocation a echoué: */
/* message d'erreur et arrêt du programme */
printf ("Malloc failed !n");
return NULL;
}
[...]
return p;
}

je ne vois pas trop comment m'en sortir sinon en définissant p à
l'extérieur en ajoutant un paramètre à la function qqc dans ce goût là :

[...]

p = (char *) malloc (PATH_SIZE_MAX * sizeof (char));
if (p == NULL)
{ /* l'allocation a echoué: */
/* message d'erreur et arrêt du programme */
printf ("Malloc failed !n");
return NULL;
}

// appel de target_path_dirname
int ierr = target_path_dirname(const char* target_path, char* p) {
p = "machin_truc_muche";
return ierr;
}

[...]

free(p);
p = NULL;

return EXIT_SUCCESS;

--
une bévue

Avatar
Harpo
Une bévue wrote:

johann.d wrote:

C'est parce que le garbagge collector n'est pas encore passé...


ça n'existe pas en C non ???


Non, à moins que tu n'utilises un garbage collector pour remplacer
malloc/free.
Ca ne veut pas dire que les données désalloués ne sont pas accessibles,
En fait cela dépend de pas mal.
Une donnée libérée peut être dans ton espace alloué pour le process, il
peut y avoir un mappingentre une adresse virtuelle et une adresse
physique.

Pour simplifier un peu excessivement (et ce n'est pas toujours comme ça)
mais le principe y est, la mémoire virtuelle est allouée par page
(souvent 4096 bytes mais ça dépend d la plateforme) pour le process.

Si tu veux allouer de la mémoire pour y mettre 'blah' et qu'il n'y a
plus de place dans une page allouée par le process, il y aura
allocation d'une page, et tu pourras y mettre 'blah' à l'adresse qu'a
renvoyé malloc().
Si ensuite tu alloues de la place pour mettre 'Hello World!', comme il
reste de la place sur la page, malloc te renverra une adresse dans
cette page, mettons un peu après 'blah'.

Quand tu libères la mémoire dans laquelle tu as mis 'hello World!', la
page ne peut pas être libérée parce qu'il y a 'blah' que tu tiens à
retrouver plus tard. La page n'est pas libérée et déréférencer un
pointeur sur cette page ne génère pas d'interruption au niveau du
processeur puisque l'adresse de la page peut être traduite par des
circuits appropriés, si tu n'a rien fait entre le moment ou tu as
libéré la page et le momnt où tu y accède, tu peux retrouver 'Hello
World!'(ça doit être fréquent), ou autre chose.
Accéder à de la mémoire libérée est un comportement indéterminé. Dans le
meilleur des cas tu as SegFault, sinon tu peux avoir tout où n'importe
quoi.

--
http://patrick.davalan.free.fr/


Avatar
Stéphane Goujet
Une bévue wrote:

str3 = (char *)calloc(PATH_SIZE_MAX, sizeof(char));


sizeof(char) vaut toujours 1 (par définition).

A+,
Stéphane.

Avatar
Harpo
johann.d wrote:

Moralité, après le free tu effectues un accès à une zone mémoire qui
ne t'appartient plus, cela n'implique pas pour autant que la zone
mémoire aura été modifiée entre temps. En tout cas c'est un
comportement indéfini (par contre, arrêtez moi si je me trompe, il y a
des machines ou des cas où le gestionnaire de mémoire pourrait lever
une exception ?).


Quand on utilise un printf, ça ne passe pas par le gestionnaire de
mémoire.
Il peut lever une exception où râler d'une manière ou d'une autre car il
a pu se reservir de la mémoire pour y mettre ses pointeurs de chaînage
de memoire allouée et peut s'apercevoir qu'un pointeur a été corrompu
si on a écrit dans le machin.
Il peut donc gueuler à un malloc ou à un free suivant.
Où alors la page n'existe plus et il y aura une exception à son accès.


Une bonne habitude est de toujours suivre un free d'une affectation à
NULL :


Voilà, excellente habitude qui ne coûte pas cher.

--
http://patrick.davalan.free.fr/

Avatar
pere.noel
Harpo wrote:


Non, à moins que tu n'utilises un garbage collector pour remplacer
malloc/free.
Ca ne veut pas dire que les données désalloués ne sont pas accessibles,
En fait cela dépend de pas mal.
Une donnée libérée peut être dans ton espace alloué pour le process, il
peut y avoir un mappingentre une adresse virtuelle et une adresse
physique.

Pour simplifier un peu excessivement (et ce n'est pas toujours comme ça)
mais le principe y est, la mémoire virtuelle est allouée par page
(souvent 4096 bytes mais ça dépend d la plateforme) pour le process.

Si tu veux allouer de la mémoire pour y mettre 'blah' et qu'il n'y a
plus de place dans une page allouée par le process, il y aura
allocation d'une page, et tu pourras y mettre 'blah' à l'adresse qu'a
renvoyé malloc().
Si ensuite tu alloues de la place pour mettre 'Hello World!', comme il
reste de la place sur la page, malloc te renverra une adresse dans
cette page, mettons un peu après 'blah'.

Quand tu libères la mémoire dans laquelle tu as mis 'hello World!', la
page ne peut pas être libérée parce qu'il y a 'blah' que tu tiens à
retrouver plus tard. La page n'est pas libérée et déréférencer un
pointeur sur cette page ne génère pas d'interruption au niveau du
processeur puisque l'adresse de la page peut être traduite par des
circuits appropriés, si tu n'a rien fait entre le moment ou tu as
libéré la page et le momnt où tu y accède, tu peux retrouver 'Hello
World!'(ça doit être fréquent), ou autre chose.
Accéder à de la mémoire libérée est un comportement indéterminé. Dans le
meilleur des cas tu as SegFault, sinon tu peux avoir tout où n'importe
quoi.


je vois le shimiliblick )))
--
une bévue

Avatar
pere.noel
Stéphane Goujet wrote:

sizeof(char) vaut toujours 1 (par définition).


oui, mais c'est plus zoli )))
--
une bévue

Avatar
johann.d
"Une bévue" a écrit dans le message de
news:1hlb1je.e1rbzq104uqqnN%
johann.d wrote:

Une bonne habitude est de toujours suivre un free d'une affectation à
NULL :



ben oui, je sais ça.

ptr = malloc(...);
if (ptr == NULL) return AIEAIEAIE;
/* do some job */
free(ptr);
ptr = NULL;
/* do some other job */
printf("%sn", ptr); // ici ptr est NULL donc l'erreur devrait être
franche



MAIS gros prob le ptr, dans mon cas est la valeur retournée ...


Ben... Où est le problème ? Tu retournes le ptr, et tu laisse la fonction
appelante faire le free quand elle en aura marre, non ?


en gros, pour l'instant, je fais ça (sans le free))) :

char* target_path_dirname(const char* target_path) {
[...]
p = (char *) malloc (PATH_SIZE_MAX * sizeof (char));
if (p == NULL)
{ /* l'allocation a echoué: */
/* message d'erreur et arrêt du programme */
printf ("Malloc failed !n");
return NULL;
}
[...]
return p;
}


Petite remarques au passage mais je crois qu'on te les a signalé par
ailleurs : sizeof (char) vaut toujours 1.


je ne vois pas trop comment m'en sortir sinon en définissant p à
l'extérieur en ajoutant un paramètre à la function qqc dans ce goût là :


Pourquoi faire ???

Ca ne te convient pas ce genre de construction :

int ma_fonction(...) {
char *tgt;

tgt = target_path_dirname(...);
if (tgt == NULL) return -1;

[...]

free(tgt);
tgt = NULL;

[...]

return 0;
}


p = (char *) malloc (PATH_SIZE_MAX * sizeof (char));
if (p == NULL)
{ /* l'allocation a echoué: */
/* message d'erreur et arrêt du programme */
printf ("Malloc failed !n");
return NULL;
}

// appel de target_path_dirname
int ierr = target_path_dirname(const char* target_path, char* p) {
p = "machin_truc_muche";
return ierr;
}


Là je ne comprends rien du tout...

Si tu veux "seulement" modifier target_path_dirname pour renvoyer un code
d'erreur plutôt que le pointeur, "il suffit" de lui passer un pointeur sur
le pointeur, non ?

int ma_fonction(...) {
char *tgt = NULL;
int ierr;

ierr = target_path_dirname(..., &tgt);
if (ierr) return ierr;
if (tgt == NULL) return -1;

[...]

free(tgt);
tgt = NULL;

[...]

return 0;
}

en écrivant bien évidemment target_path_dirname ainsi :

int target_path_dirname(const char* target_path, char **result) {
char *p = NULL;

if (result == NULL)
return -71; // un code d'erreur

[...]
p = (char *) malloc (PATH_SIZE_MAX * sizeof (char));
if (p == NULL)
{ /* l'allocation a echoué: */
/* message d'erreur et arrêt du programme */
printf ("Malloc failed !n");
return -72; // un autre code d'erreur
}
[...]

*result = p;
return 0; // tout va bien
}

Ou alors c'est que je n'ai rien compris à ton besoin ???

--
Johann.D


Avatar
Harpo
Une bévue wrote:

en gros, pour l'instant, je fais ça (sans le free))) :


S'il doit retourner de la mémoire allouée, il vaut mieux qu'il ne la
libère pas avant de retourner, hein.


char* target_path_dirname(const char* target_path) {
[...]
p = (char *) malloc (PATH_SIZE_MAX * sizeof (char));


Je crois que sizeof(char) vaut toujours 1, à vérifier.

if (p == NULL)
{ /* l'allocation a echoué: */
/* message d'erreur et arrêt du programme */
printf ("Malloc failed !n");
return NULL;


Cool !

}
[...]
return p;
}

je ne vois pas trop comment m'en sortir sinon en définissant p à
l'extérieur en ajoutant un paramètre à la function qqc dans ce goût là


p est retourné par valeur, comme toujours, ce qui fait que la fonction
appelante aura l'adresse de la mémoire allouée.
Je ne vois pas ce qui pose problème à moins que j'ai loupé un truc. Ta
fonction m'a l'air bonne.
Ce n'est pas comme si t'avais mis
char p[] = "blah";
(blah étant alloué dans la pile)
D'ailleurs je me demande même si
char * p = "blah";
(blah étant alloué ailleurs que dans la pile)
ne serait pas valide

Sinon, target_path n'est pas utilisé dans la fonction, de bonnes options
de warning auraient du te le signaler.

--
http://patrick.davalan.free.fr/

Avatar
Harpo
Une bévue wrote:

Stéphane Goujet wrote:

sizeof(char) vaut toujours 1 (par définition).


oui, mais c'est plus zoli )))


J'ai parfois vu ça dans des programmes écrits par des dandies.

--
http://patrick.davalan.free.fr/


Avatar
pere.noel
johann.d wrote:

MAIS gros prob le ptr, dans mon cas est la valeur retournée ...


Ben... Où est le problème ? Tu retournes le ptr, et tu laisse la fonction
appelante faire le free quand elle en aura marre, non ?


voilà, merci, ou peut donc faire qqc du genre :

---------------------------------
char * ma_fonction(...) {

char * ptr;
ptr=malloc(...);

[...]

return ptr;
}

int main(...) {
//l'appel de la fonction :

char * mon_ptr=ma_fonction(...);

printf("mon_ptr=%sn", mon_ptr);

// plus besoin de mon_ptr on libère

free(mon_ptr);
mon_ptr=NULL;

return EXIT_SUCCESS;
}
---------------------------------

donc, si j'ai bien compris (je commence à me faire à C, ça commence à
devenir amusant) :

free(mon_ptr);

libère la zone mémoire allouée à mon_ptr qui pointe la même adresse que
ptr dans la fonction ma_fonction et donc les deux sont libérés car il ne
font qu'un seul, c'est bien ça ???

si c'est vrai, j'ai fait un bon en avant )) (en C)



<snip/>



Petite remarques au passage mais je crois qu'on te les a signalé par
ailleurs : sizeof (char) vaut toujours 1.


oui, mais je pense passer à autre chose que du char (utf8)...


je ne vois pas trop comment m'en sortir sinon en définissant p à
l'extérieur en ajoutant un paramètre à la function qqc dans ce goût là :


<snip/>


Là je ne comprends rien du tout...


pas grave j'avais loupé un métro (voir + haut)

<snip/>

Ou alors c'est que je n'ai rien compris à ton besoin ???


non, non, tu as bien pigé, mon pb n'a rien de spécial ;-)
--
une bévue


1 2 3 4 5