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 ?
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.
Incompréhensible.
Je rappelle le message original (dans ce groupe), news: :
: Dans un code source je trouve cela : : : struct NAME : { : struct NAME * next; : char name[1]; : }; : : puis : : : strcpy(p->name, dp2->d_name);
Il n'y a pas d'allocation (dynamique ou pas), il y a évidemmement des lignes qui manquent au niveau du « puis », on ne sait pas (exactement) ce qu'est dp2 même si on a le droit d'avoir des idées. Rien à voir donc avec ce dont tu sembles parler, y compris à propos de « psychopathes ».
Si tu as en vue un _autre_ code qui fait des opérations similaires, il serait utile pour la discussion de _publier_ ce dit code, afin de pouvoir entreprendre des discussions productives, car malheureusement je ne suis pas devin, et d'ailleurs la plupart des contributeurs ici ne le sont pas non plus.
Antoine
En news:slrngcclfu.rul.knatschke@rayleigh.systella.fr, JKB va escriure:
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.
Incompréhensible.
Je rappelle le message original (dans ce groupe),
news:mn.349e7d89e4a3d43b.51095@x.con :
: Dans un code source je trouve cela :
:
: struct NAME
: {
: struct NAME * next;
: char name[1];
: };
:
: puis :
:
: strcpy(p->name, dp2->d_name);
Il n'y a pas d'allocation (dynamique ou pas), il y a évidemmement des lignes
qui manquent au niveau du « puis », on ne sait pas (exactement) ce qu'est
dp2 même si on a le droit d'avoir des idées. Rien à voir donc avec ce dont
tu sembles parler, y compris à propos de « psychopathes ».
Si tu as en vue un _autre_ code qui fait des opérations similaires, il
serait utile pour la discussion de _publier_ ce dit code, afin de pouvoir
entreprendre des discussions productives, car malheureusement je ne suis pas
devin, et d'ailleurs la plupart des contributeurs ici ne le sont pas non
plus.
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.
Incompréhensible.
Je rappelle le message original (dans ce groupe), news: :
: Dans un code source je trouve cela : : : struct NAME : { : struct NAME * next; : char name[1]; : }; : : puis : : : strcpy(p->name, dp2->d_name);
Il n'y a pas d'allocation (dynamique ou pas), il y a évidemmement des lignes qui manquent au niveau du « puis », on ne sait pas (exactement) ce qu'est dp2 même si on a le droit d'avoir des idées. Rien à voir donc avec ce dont tu sembles parler, y compris à propos de « psychopathes ».
Si tu as en vue un _autre_ code qui fait des opérations similaires, il serait utile pour la discussion de _publier_ ce dit code, afin de pouvoir entreprendre des discussions productives, car malheureusement je ne suis pas devin, et d'ailleurs la plupart des contributeurs ici ne le sont pas non plus.
Antoine
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:
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.
Incompréhensible.
Je rappelle le message original (dans ce groupe), news: :
: Dans un code source je trouve cela : : : struct NAME : { : struct NAME * next; : char name[1]; : }; : : puis : : : strcpy(p->name, dp2->d_name);
Il n'y a pas d'allocation (dynamique ou pas), il y a évidemmement des lignes qui manquent au niveau du « puis », on ne sait pas (exactement) ce qu'est dp2 même si on a le droit d'avoir des idées. Rien à voir donc avec ce dont tu sembles parler, y compris à propos de « psychopathes ».
Si tu as en vue un _autre_ code qui fait des opérations similaires, il serait utile pour la discussion de _publier_ ce dit code, afin de pouvoir entreprendre des discussions productives, car malheureusement je ne suis pas devin, et d'ailleurs la plupart des contributeurs ici ne le sont pas non plus.
La discussion originelle était sur fr.comp.applications.sgbd. Le code est issu des sources de openqm.
Je suis parfaitement d'accord avec tes conclusions, mais elles ne s'appliquent pas pour moi dans ce code. J'ai essayé de compiler le truc sur sparc64 (bonjour les problèmes d'alignement ! Les SIGBUS se ramassent à la pelle [air trop connu] et le truc est _mal_ écrit !) pour l'utiliser. J'ai corrigé un tas de trucs comme celui-ci puis j'ai abandonné ayant d'autres choses à faire que de corriger un code pareil pour évaluer un soft. Il n'y a d'ailleurs pas que ce genre de bêtise : les retours de malloc() sont systématiquement ignorés, des memcpy et memset sont hasardeux et non alignés... Bref, que du bonheur !
La question initiale était "est-ce licite ?". La réponse est "oui" si on sait exactement ce qu'on fait. Dans ce code (j'aurais pu effectivement préciser), la réponse est "non", parce qu'on écrase joyeusement et sans vergogne ce qui suit. Il suffit de faire tourner le truc avec electric-fences pour s'en convaincre...
La question étant résolue, je ne vois pas pourquoi continuer à discuter (ou alors, il faudrait ouvrir un forum rien que pour analyser ligne par ligne le code source et il y aura du boulot. Un volontaire pour lancer un AAD sur fufe ? ;-) )
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.
Le 09-09-2008, à propos de
Re: strcpy sur un char[1] ???,
Antoine Leca écrivait dans fr.comp.lang.c :
En news:slrngcclfu.rul.knatschke@rayleigh.systella.fr, JKB va escriure:
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.
Incompréhensible.
Je rappelle le message original (dans ce groupe),
news:mn.349e7d89e4a3d43b.51095@x.con :
: Dans un code source je trouve cela :
:
: struct NAME
: {
: struct NAME * next;
: char name[1];
: };
:
: puis :
:
: strcpy(p->name, dp2->d_name);
Il n'y a pas d'allocation (dynamique ou pas), il y a évidemmement des lignes
qui manquent au niveau du « puis », on ne sait pas (exactement) ce qu'est
dp2 même si on a le droit d'avoir des idées. Rien à voir donc avec ce dont
tu sembles parler, y compris à propos de « psychopathes ».
Si tu as en vue un _autre_ code qui fait des opérations similaires, il
serait utile pour la discussion de _publier_ ce dit code, afin de pouvoir
entreprendre des discussions productives, car malheureusement je ne suis pas
devin, et d'ailleurs la plupart des contributeurs ici ne le sont pas non
plus.
La discussion originelle était sur fr.comp.applications.sgbd. Le
code est issu des sources de openqm.
Je suis parfaitement d'accord avec tes conclusions, mais elles ne
s'appliquent pas pour moi dans ce code. J'ai essayé de compiler le
truc sur sparc64 (bonjour les problèmes d'alignement ! Les SIGBUS se
ramassent à la pelle [air trop connu] et le truc est _mal_ écrit !) pour
l'utiliser. J'ai corrigé un tas de trucs comme celui-ci puis j'ai
abandonné ayant d'autres choses à faire que de corriger un code
pareil pour évaluer un soft. Il n'y a d'ailleurs pas que ce genre de
bêtise : les retours de malloc() sont systématiquement ignorés, des
memcpy et memset sont hasardeux et non alignés... Bref, que du
bonheur !
La question initiale était "est-ce licite ?". La réponse est "oui"
si on sait exactement ce qu'on fait. Dans ce code (j'aurais pu
effectivement préciser), la réponse est "non", parce qu'on écrase
joyeusement et sans vergogne ce qui suit. Il suffit de faire tourner
le truc avec electric-fences pour s'en convaincre...
La question étant résolue, je ne vois pas pourquoi continuer à
discuter (ou alors, il faudrait ouvrir un forum rien que pour
analyser ligne par ligne le code source et il y aura du boulot. Un
volontaire pour lancer un AAD sur fufe ? ;-) )
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.
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:
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.
Incompréhensible.
Je rappelle le message original (dans ce groupe), news: :
: Dans un code source je trouve cela : : : struct NAME : { : struct NAME * next; : char name[1]; : }; : : puis : : : strcpy(p->name, dp2->d_name);
Il n'y a pas d'allocation (dynamique ou pas), il y a évidemmement des lignes qui manquent au niveau du « puis », on ne sait pas (exactement) ce qu'est dp2 même si on a le droit d'avoir des idées. Rien à voir donc avec ce dont tu sembles parler, y compris à propos de « psychopathes ».
Si tu as en vue un _autre_ code qui fait des opérations similaires, il serait utile pour la discussion de _publier_ ce dit code, afin de pouvoir entreprendre des discussions productives, car malheureusement je ne suis pas devin, et d'ailleurs la plupart des contributeurs ici ne le sont pas non plus.
La discussion originelle était sur fr.comp.applications.sgbd. Le code est issu des sources de openqm.
Je suis parfaitement d'accord avec tes conclusions, mais elles ne s'appliquent pas pour moi dans ce code. J'ai essayé de compiler le truc sur sparc64 (bonjour les problèmes d'alignement ! Les SIGBUS se ramassent à la pelle [air trop connu] et le truc est _mal_ écrit !) pour l'utiliser. J'ai corrigé un tas de trucs comme celui-ci puis j'ai abandonné ayant d'autres choses à faire que de corriger un code pareil pour évaluer un soft. Il n'y a d'ailleurs pas que ce genre de bêtise : les retours de malloc() sont systématiquement ignorés, des memcpy et memset sont hasardeux et non alignés... Bref, que du bonheur !
La question initiale était "est-ce licite ?". La réponse est "oui" si on sait exactement ce qu'on fait. Dans ce code (j'aurais pu effectivement préciser), la réponse est "non", parce qu'on écrase joyeusement et sans vergogne ce qui suit. Il suffit de faire tourner le truc avec electric-fences pour s'en convaincre...
La question étant résolue, je ne vois pas pourquoi continuer à discuter (ou alors, il faudrait ouvrir un forum rien que pour analyser ligne par ligne le code source et il y aura du boulot. Un volontaire pour lancer un AAD sur fufe ? ;-) )
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.
Patrick 'Zener' Brunet
Bonjour.
"Alain Montfranc" a écrit dans le message de news:
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 ?
Je passe un peu tard, alors juste une précision:
Cette pratique n'est pas malsaine du tout, si elle est bien maîtrisée: c'est un bon moyen de stocker efficacement des chaînes nombreuses et dont la taille majorante n'est pas connue lors de la compilation, ou bien représente un gaspillage inacceptable. Visiblement vos NAME sont chaînés (pointeur next), donc ça sert visiblement à sous-allouer un espace de mémoire en une liste de chaînes.
Ca se fait souvent dans la programmation genre IA, ou bien plus généralement dans le stockage des tokens lus par un compilateur. Quoique la structure soit alors plutôt un map clé->valeur qu'une liste chaînée. Je pense que ce chaînage en liste sert à autre chose et qu'il y a aussi un tableau de pointeurs vers les NAME.
L'alternative serait de réserver un tableau de chaînes toutes dimensionnées à la taille maximale, gaspillage monstrueux.
Souvent d'ailleurs en IA vous aurez name[] dans une union, en alternative à d'autres masques de lecture (struct, int, double, etc.), et un tag de type int ou enum dans NAME pour sélectionner le bon format. On peut aussi y conserver le nombre de caractères, ça épargne bien des strlen... On alloue alors max( sizeof( NAME), Nb_caractères + 1 + offsetof( NAME, union))
Evidemment ce n'est pas sécurisé du tout d'un point de vue automatique, mais à ce niveau de codage on n'est plus en apprentissage. Si on veut sécuriser un peu, on fait l'allocation+remplissage+chaînage dans une fonction dédiée et soigneusement validée.
-- Cordialement. -- * Patrick BRUNET www.ipzb.fr * E-mail: lien sur http://zener131.eu/ContactMe
Bonjour.
"Alain Montfranc" <x@x.con> a écrit dans le message de news:
mn.349e7d89e4a3d43b.51095@x.con...
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 ?
Je passe un peu tard, alors juste une précision:
Cette pratique n'est pas malsaine du tout, si elle est bien maîtrisée: c'est
un bon moyen de stocker efficacement des chaînes nombreuses et dont la
taille majorante n'est pas connue lors de la compilation, ou bien représente
un gaspillage inacceptable.
Visiblement vos NAME sont chaînés (pointeur next), donc ça sert visiblement
à sous-allouer un espace de mémoire en une liste de chaînes.
Ca se fait souvent dans la programmation genre IA, ou bien plus généralement
dans le stockage des tokens lus par un compilateur. Quoique la structure
soit alors plutôt un map clé->valeur qu'une liste chaînée.
Je pense que ce chaînage en liste sert à autre chose et qu'il y a aussi un
tableau de pointeurs vers les NAME.
L'alternative serait de réserver un tableau de chaînes toutes dimensionnées
à la taille maximale, gaspillage monstrueux.
Souvent d'ailleurs en IA vous aurez name[] dans une union, en alternative à
d'autres masques de lecture (struct, int, double, etc.), et un tag de type
int ou enum dans NAME pour sélectionner le bon format. On peut aussi y
conserver le nombre de caractères, ça épargne bien des strlen...
On alloue alors
max( sizeof( NAME),
Nb_caractères + 1 + offsetof( NAME, union))
Evidemment ce n'est pas sécurisé du tout d'un point de vue automatique, mais
à ce niveau de codage on n'est plus en apprentissage. Si on veut sécuriser
un peu, on fait l'allocation+remplissage+chaînage dans une fonction dédiée
et soigneusement validée.
--
Cordialement.
--
* Patrick BRUNET www.ipzb.fr
* E-mail: lien sur http://zener131.eu/ContactMe
"Alain Montfranc" a écrit dans le message de news:
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 ?
Je passe un peu tard, alors juste une précision:
Cette pratique n'est pas malsaine du tout, si elle est bien maîtrisée: c'est un bon moyen de stocker efficacement des chaînes nombreuses et dont la taille majorante n'est pas connue lors de la compilation, ou bien représente un gaspillage inacceptable. Visiblement vos NAME sont chaînés (pointeur next), donc ça sert visiblement à sous-allouer un espace de mémoire en une liste de chaînes.
Ca se fait souvent dans la programmation genre IA, ou bien plus généralement dans le stockage des tokens lus par un compilateur. Quoique la structure soit alors plutôt un map clé->valeur qu'une liste chaînée. Je pense que ce chaînage en liste sert à autre chose et qu'il y a aussi un tableau de pointeurs vers les NAME.
L'alternative serait de réserver un tableau de chaînes toutes dimensionnées à la taille maximale, gaspillage monstrueux.
Souvent d'ailleurs en IA vous aurez name[] dans une union, en alternative à d'autres masques de lecture (struct, int, double, etc.), et un tag de type int ou enum dans NAME pour sélectionner le bon format. On peut aussi y conserver le nombre de caractères, ça épargne bien des strlen... On alloue alors max( sizeof( NAME), Nb_caractères + 1 + offsetof( NAME, union))
Evidemment ce n'est pas sécurisé du tout d'un point de vue automatique, mais à ce niveau de codage on n'est plus en apprentissage. Si on veut sécuriser un peu, on fait l'allocation+remplissage+chaînage dans une fonction dédiée et soigneusement validée.
-- Cordialement. -- * Patrick BRUNET www.ipzb.fr * E-mail: lien sur http://zener131.eu/ContactMe
Alexandre BACQUART
Patrick 'Zener' Brunet wrote:
Bonjour.
"Alain Montfranc" a écrit dans le message de news:
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 ?
Je passe un peu tard, alors juste une précision:
Cette pratique n'est pas malsaine du tout, si elle est bien maîtrisée: c'est un bon moyen de stocker efficacement des chaînes nombreuses et dont la taille majorante n'est pas connue lors de la compilation, ou bien représente un gaspillage inacceptable.
La technique est aussi largement utilisée dans les implémentations d'images bitmap en C89/C90. Version simplifiée :
typedef struct { int width; int height; char datas[1]; } Bitmap;
L'intérêt réside essentiellement dans l'allocation mémoire. Une seule allocation suffit pour faire cohabiter les informations + les données brutes, quelque-chose ressemblant à :
Note: le padding éventuel n'est pas pris en compte, mais en pratique, ça fonctionne.
Il n'y a plus qu'à remplir les données brutes dans datas, comme s'il s'agissait d'un pointeur. Bien-entendu, si on veut copier à partir d'un bitmap chargé quelque-part, on utilisera memcpy plutôt que strcpy, puis libération des données source, mais le principe reste le même.
Si on ne craint pas d'avoir à travailler avec des vieux compilos, l'exploitation des tableaux à taille variable (les fameux VLA de C99) peut être préférable que d'avoir recours à cette vieille technique, mais bon, ça fonctionne très bien comme ça (c'est juste un peu déroutant quand on est jamais tombé dessus).
-- Alex
Patrick 'Zener' Brunet wrote:
Bonjour.
"Alain Montfranc" <x@x.con> a écrit dans le message de news:
mn.349e7d89e4a3d43b.51095@x.con...
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 ?
Je passe un peu tard, alors juste une précision:
Cette pratique n'est pas malsaine du tout, si elle est bien maîtrisée: c'est
un bon moyen de stocker efficacement des chaînes nombreuses et dont la
taille majorante n'est pas connue lors de la compilation, ou bien représente
un gaspillage inacceptable.
La technique est aussi largement utilisée dans les implémentations
d'images bitmap en C89/C90. Version simplifiée :
typedef struct {
int width;
int height;
char datas[1];
} Bitmap;
L'intérêt réside essentiellement dans l'allocation mémoire. Une seule
allocation suffit pour faire cohabiter les informations + les données
brutes, quelque-chose ressemblant à :
Note: le padding éventuel n'est pas pris en compte, mais en pratique, ça
fonctionne.
Il n'y a plus qu'à remplir les données brutes dans datas, comme s'il
s'agissait d'un pointeur. Bien-entendu, si on veut copier à partir d'un
bitmap chargé quelque-part, on utilisera memcpy plutôt que strcpy, puis
libération des données source, mais le principe reste le même.
Si on ne craint pas d'avoir à travailler avec des vieux compilos,
l'exploitation des tableaux à taille variable (les fameux VLA de C99)
peut être préférable que d'avoir recours à cette vieille technique, mais
bon, ça fonctionne très bien comme ça (c'est juste un peu déroutant
quand on est jamais tombé dessus).
"Alain Montfranc" a écrit dans le message de news:
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 ?
Je passe un peu tard, alors juste une précision:
Cette pratique n'est pas malsaine du tout, si elle est bien maîtrisée: c'est un bon moyen de stocker efficacement des chaînes nombreuses et dont la taille majorante n'est pas connue lors de la compilation, ou bien représente un gaspillage inacceptable.
La technique est aussi largement utilisée dans les implémentations d'images bitmap en C89/C90. Version simplifiée :
typedef struct { int width; int height; char datas[1]; } Bitmap;
L'intérêt réside essentiellement dans l'allocation mémoire. Une seule allocation suffit pour faire cohabiter les informations + les données brutes, quelque-chose ressemblant à :
Note: le padding éventuel n'est pas pris en compte, mais en pratique, ça fonctionne.
Il n'y a plus qu'à remplir les données brutes dans datas, comme s'il s'agissait d'un pointeur. Bien-entendu, si on veut copier à partir d'un bitmap chargé quelque-part, on utilisera memcpy plutôt que strcpy, puis libération des données source, mais le principe reste le même.
Si on ne craint pas d'avoir à travailler avec des vieux compilos, l'exploitation des tableaux à taille variable (les fameux VLA de C99) peut être préférable que d'avoir recours à cette vieille technique, mais bon, ça fonctionne très bien comme ça (c'est juste un peu déroutant quand on est jamais tombé dessus).