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 ?

4 réponses

1 2
Avatar
Antoine Leca
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.


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:
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.
Avatar
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
Avatar
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 à :

Bitmap *bmp = malloc(sizeof(Bitmap) - 1 + (bitmap_width *
bitmap_height));
bmp->width = bitmap_width;
bmp->height = bitmap_height;

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
1 2