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

strcpy sur un char[1] ???

14 réponses
Avatar
Alain Montfranc
Bonjour

Dans un code source je trouve cela :

struct NAME
{
struct NAME * next;
char name[1];
};

puis :

strcpy(p->name, dp2->d_name);

Il me semble que strcpy copie jusqu'au premier \0 ? A moins que la
chaine soit vide, ce genre de truc va forcément "déborder", non et
corrompre la stack ?

10 réponses

1 2
Avatar
JKB
Le 06-09-2008, à propos de
strcpy sur un char[1] ???,
Alain Montfranc écrivait dans fr.comp.lang.c :
Bonjour



Rebonjour ;-)

Dans un code source je trouve cela :

struct NAME
{
struct NAME * next;
char name[1];
};

puis :

strcpy(p->name, dp2->d_name);



Des noms, des noms, des noms ! ;-)

Il me semble que strcpy copie jusqu'au premier ? A moins que la
chaine soit vide, ce genre de truc va forcément "déborder", non et
corrompre la stack ?



Oui. Je site :

La fonction strcpy() copie la chaîne pointée par src, y compris le car
actère nul (« ») final dans la chaîne pointée par dest.

Ça déborde dès que la chaine source est de taille strictement supérieure
à 0

JKB

--
Le cerveau, c'est un véritable scandale écologique. Il représente 2% de notre
masse corporelle, mais disperse à lui seul 25% de l'énergie que nous
consommons tous les jours.
Avatar
Erwan David
Alain Montfranc écrivait :

Bonjour

Dans un code source je trouve cela :

struct NAME
{
struct NAME * next;
char name[1];
};

puis :

strcpy(p->name, dp2->d_name);

Il me semble que strcpy copie jusqu'au premier ? A moins que la
chaine soit vide, ce genre de truc va forcément "déborder", non et
corrompre la stack ?



Tout dépend de comment a été alloué p.

--
Le travail n'est pas une bonne chose. Si ça l'était,
les riches l'auraient accaparé
Avatar
Alain Montfranc
Erwan David a écrit
Alain Montfranc écrivait :

Bonjour

Dans un code source je trouve cela :

struct NAME
{
struct NAME * next;
char name[1];
};

puis :

strcpy(p->name, dp2->d_name);

Il me semble que strcpy copie jusqu'au premier ? A moins que la
chaine soit vide, ce genre de truc va forcément "déborder", non et
corrompre la stack ?



Tout dépend de comment a été alloué p.



Par un malloc. Ca change quoi ?
Avatar
Alain Montfranc
JKB a écrit
Le 06-09-2008, à propos de
strcpy sur un char[1] ???,
Alain Montfranc écrivait dans fr.comp.lang.c :
Bonjour



Rebonjour ;-)

Dans un code source je trouve cela :

struct NAME
{
struct NAME * next;
char name[1];
};

puis :

strcpy(p->name, dp2->d_name);



Des noms, des noms, des noms ! ;-)



openqm, version gpl


Il me semble que strcpy copie jusqu'au premier ? A moins que la
chaine soit vide, ce genre de truc va forcément "déborder", non et
corrompre la stack ?



Oui. Je site :

La fonction strcpy() copie la chaîne pointée par src, y compris le car
actère nul (« ») final dans la chaîne pointée par dest.

Ça déborde dès que la chaine source est de taille strictement supérieure
à 0

JKB



beurk quoi...
Avatar
Erwan David
Alain Montfranc écrivait :

Erwan David a écrit
Alain Montfranc écrivait :

Bonjour

Dans un code source je trouve cela :

struct NAME
{
struct NAME * next;
char name[1];
};

puis :

strcpy(p->name, dp2->d_name);

Il me semble que strcpy copie jusqu'au premier ? A moins que la
chaine soit vide, ce genre de truc va forcément "déborder", non et
corrompre la stack ?



Tout dépend de comment a été alloué p.



Par un malloc. Ca change quoi ?



malloc avec quelle taille ? C'est une technique classique en C pré 99
d'avoir une structure qui déclare un dernier composant qui est un
tableau de taille 1, mais la taille allouée est celle qu'il faut.



--
Le travail n'est pas une bonne chose. Si ça l'était,
les riches l'auraient accaparé
Avatar
Alain Montfranc
Erwan David a écrit
Alain Montfranc écrivait :

Erwan David a écrit
Alain Montfranc écrivait :

Bonjour

Dans un code source je trouve cela :

struct NAME
{
struct NAME * next;
char name[1];
};

puis :

strcpy(p->name, dp2->d_name);

Il me semble que strcpy copie jusqu'au premier ? A moins que la
chaine soit vide, ce genre de truc va forcément "déborder", non et
corrompre la stack ?



Tout dépend de comment a été alloué p.



Par un malloc. Ca change quoi ?



malloc avec quelle taille ? C'est une technique classique en C pré 99
d'avoir une structure qui déclare un dernier composant qui est un
tableau de taille 1, mais la taille allouée est celle qu'il faut.



ok
Avatar
Antoine Leca
En news:, JKB va escriure:
Le 06-09-2008, à propos de strcpy sur un char[1] ???,
Alain Montfranc écrivait dans fr.comp.lang.c :
struct NAME { struct NAME * next; char name[1]; };
strcpy(p->name, dp2->d_name);
Il me semble que strcpy copie jusqu'au premier ?



Oui. Je site :
La fonction strcpy() copie la chaîne pointée par src, y
compris le car actère nul (« ») final dans la chaîne
pointée par dest.



Et...

Ça déborde dès que la chaine source est de taille strictement
supérieure à 0




Cela ne déborde que si la chaîne finale (la vraie, pas la déclaration) a une
taille réservée inférieure à la taille réelle (strlen+1) de la chaîne
origine.

Et en C, du fait de l'équivalence pointeur-tableau, la déclaration
« visible » d'un tableau n'est pas forcément la déclaration réelle, en
particulier en ce qui concerne la taille du tableau.


Antoine
Avatar
JKB
Le 09-09-2008, à propos de
Re: strcpy sur un char[1] ???,
Antoine Leca écrivait dans fr.comp.lang.c :
En news:, JKB va escriure:
Le 06-09-2008, à propos de strcpy sur un char[1] ???,
Alain Montfranc écrivait dans fr.comp.lang.c :
struct NAME { struct NAME * next; char name[1]; };
strcpy(p->name, dp2->d_name);
Il me semble que strcpy copie jusqu'au premier ?



Oui. Je site :
La fonction strcpy() copie la chaîne pointée par src, y
compris le car actère nul (« ») final dans la chaîne
pointée par dest.



Et...

Ça déborde dès que la chaine source est de taille strictement
supérieure à 0




Cela ne déborde que si la chaîne finale (la vraie, pas la déclaration) a une
taille réservée inférieure à la taille réelle (strlen+1) de la chaîne
origine.

Et en C, du fait de l'équivalence pointeur-tableau, la déclaration
« visible » d'un tableau n'est pas forcément la déclaration réelle, en
particulier en ce qui concerne la taille du tableau.



Nous sommes d'accord, mais je réagissais avec le source sous les
yeux (ce fil est issu d'une discussion avec un psychopathe sur un
autre forum). Dans le code en question, une structure est déclarée,
et _jamais_ on ne contrôle que le strcpy ne va pas écraser quelque
chose.

Cordialement,

JKB

--
Le cerveau, c'est un véritable scandale écologique. Il représente 2% de notre
masse corporelle, mais disperse à lui seul 25% de l'énergie que nous
consommons tous les jours.
Avatar
Antoine Leca
En news:, JKB va escriure:
Antoine Leca écrivait dans fr.comp.lang.c :
Et en C, du fait de l'équivalence pointeur-tableau, la déclaration
« visible » d'un tableau n'est pas forcément la déclaration réelle,
en particulier en ce qui concerne la taille du tableau.



Nous sommes d'accord, mais je réagissais avec le source sous les
yeux [...]. Dans le code en question, une structure est déclarée,
et _jamais_ on ne contrôle que le strcpy ne va pas écraser quelque
chose.



Avec strcpy tout seul, il est virtuellement impossible de contrôler que tu
ne vas pas écraser quelque chose.

Problème, la logique de nommage de la norme semble proposer strncpy quand tu
veux contrôler, et pour des raisons historiques strncpy n'a pas cette
fonction ; il faudrait utiliser strlcpy qui n'est pas normalisée, ou
snprintf qui est d'une part C99 et d'autre part demande plus de ressources,
ou sprintf(,"%.*s",) qui demande aussi beaucoup de ressources et n'est pas
facile à relire car ce n'est pas « idiomatique »¹, ou strcpy_s qui est la
réponse officielle du comité mais n'est pas très répandue, voire strncpy_s
qui cumule tous les inconvénients : 4 arguments, sémantique différente à la
fois de strncpy et de strlcpy, peu utilisée, possibilité de mettre en jeu un
mécanisme d'exception à rebond multiple, fonction des implémentations et
potentiellement différent à la fois de signal/raise et de setjmp/longjmp.


Par ailleurs, et c'était mon propos ci-dessus, lorsque tu utilises
fct_qui_modifie_arg1(p->name, ...), la structure qui est déclarée pour &p
importe peu, c'est la structure réellement utilisée pour l'allocation qui
importe (le C a une règle spéciale pour permettre justement ce genre
d'utilisation); note bien que dans le cas d'une allocation dynamique, même
la déclaration utilisée pour l'allocation de la structure qui va être passée
ensuite dans le pointeur p [ouf!] n'importe pas vraiment, c'est en fait le
paramètre passé à malloc/calloc/realloc ou équivalent qui va déterminer
indirectement la taille des éléments de la structure.


Antoine
__________
¹: Techniquement c'est-à-dire dans le respect strict de la norme, s[n]printf
sont de plus limitées à des chaînes de 4095 caractères avec C99, voire 509
en C90.
Avatar
JKB
Le 09-09-2008, à propos de
Re: strcpy sur un char[1] ???,
Antoine Leca écrivait dans fr.comp.lang.c :
En news:, JKB va escriure:
Antoine Leca écrivait dans fr.comp.lang.c :
Et en C, du fait de l'équivalence pointeur-tableau, la déclaration
« visible » d'un tableau n'est pas forcément la déclaration réelle,
en particulier en ce qui concerne la taille du tableau.



Nous sommes d'accord, mais je réagissais avec le source sous les
yeux [...]. Dans le code en question, une structure est déclarée,
et _jamais_ on ne contrôle que le strcpy ne va pas écraser quelque
chose.



Avec strcpy tout seul, il est virtuellement impossible de contrôler que tu
ne vas pas écraser quelque chose.



Je sais bien, on contrôle les longueurs _avant_ d'appliquer le
strcpy. Ce qui n'est pas fait dans le code dont on parle.

Problème, la logique de nommage de la norme semble proposer strncpy quand tu
veux contrôler, et pour des raisons historiques strncpy n'a pas cette
fonction ; il faudrait utiliser strlcpy qui n'est pas normalisée, ou
snprintf qui est d'une part C99 et d'autre part demande plus de ressources,
ou sprintf(,"%.*s",) qui demande aussi beaucoup de ressources et n'est pas
facile à relire car ce n'est pas « idiomatique »¹, ou strcpy_s qui est la
réponse officielle du comité mais n'est pas très répandue, voire strncpy_s
qui cumule tous les inconvénients : 4 arguments, sémantique différente à la
fois de strncpy et de strlcpy, peu utilisée, possibilité de mettre en jeu un
mécanisme d'exception à rebond multiple, fonction des implémentations et
potentiellement différent à la fois de signal/raise et de setjmp/longjmp.


Par ailleurs, et c'était mon propos ci-dessus, lorsque tu utilises
fct_qui_modifie_arg1(p->name, ...), la structure qui est déclarée pour &p
importe peu, c'est la structure réellement utilisée pour l'allocation qui
importe (le C a une règle spéciale pour permettre justement ce genre
d'utilisation); note bien que dans le cas d'une allocation dynamique, même
la déclaration utilisée pour l'allocation de la structure qui va être passée
ensuite dans le pointeur p [ouf!] n'importe pas vraiment, c'est en fait le
paramètre passé à malloc/calloc/realloc ou équivalent qui va déterminer
indirectement la taille des éléments de la structure.



Nous sommes bien d'accord. Sauf que dans le cas présent, on alloue
une structure d'une certaine taille et on écrit brutalement
derrière. C'est assez casse-gueule comme manipulation. Note que je
ne parle que du code en question et non de la programmation C en
général.

Cordialement,

JKB

--
Le cerveau, c'est un véritable scandale écologique. Il représente 2% de notre
masse corporelle, mais disperse à lui seul 25% de l'énergie que nous
consommons tous les jours.
1 2