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

[Q] Passage d'une union ou d'un int en argument

6 réponses
Avatar
Eric Levenez
Soit la fonction d'initialisation d'un sémaphore, donc le prototype est le
suivant :

int semctl(int semid, int semnum, int cmd, ...);

J'utilise GCC 4.3.3 sous GNU/Linux/x86 en cross-compilation pour PowerPC/G3.
Les flags de compilation sont par défaut (non C99, donc C89 je suppose).

Cette fonction possède une union en 4ème argument (facultatif et dépendant
du 3ème), qui est la suivante :

union semun {
int val; /* value for SETVAL */
struct semid_ds *buf; /* buffer for IPC_STAT & IPC_SET */
u_short *array; /* array for GETALL & SETALL */
};

La méthode correcte d'appel est par exemple :

union semun sm;
sm.val = 1;
semctl(id, 0, SETVAL, sm);

Le problème est que j'utilisais (à tort je le sais) un appel de la forme :

semctl(id, 0, SETVAL, 1);

Ce que je ne comprends pas c'est que mon programme plantait sur cet appel.
Le PowerPC que j'utilise est 32 bits et donc les "int" et les "char *" sont
32 bits.

Sur une machine 64 bits avec des "int" 32 bits et des "char *" 64 bits, cela
ne plante pas, même si la valeur (ici 1) ne sera pas forcément celle qui
servira à initialiser le sémaphore (dépend de l'alignement).

Quelqu'un à une idée sur la cause du plantage ?

--
Éric Lévénez -- <http://www.levenez.com/>
Unix is not only an OS, it's a way of life.

6 réponses

Avatar
Jean-Marc Bourguet
Eric Levenez writes:

Ce que je ne comprends pas c'est que mon programme
plantait sur cet appel. Le PowerPC que j'utilise est 32
bits et donc les "int" et les "char *" sont 32 bits.


Je ne connais pas particulièrement bien les conventions
d'appel utilisées dans les power-PC. Une possibilité serait
qu'elle fasse passer toutes les unions en mémoire et les int
dans des registres. Donc le contenu de la pile ne serait
pas celui attendu.

Sur une machine 64 bits avec des "int" 32 bits et des
"char *" 64 bits, cela ne plante pas, même si la valeur
(ici 1) ne sera pas forcément celle qui servira à
initialiser le sémaphore (dépend de l'alignement).


La convention a peut-être été modifiée pour passer les
petites unions par registre.

Un moyen de savoir serait de demander l'assembleur et voir
ce qui se passe.

A+

--
Jean-Marc
FAQ de fclc: http://www.isty-info.uvsq.fr/~rumeau/fclc
Site de usenet-fr: http://www.usenet-fr.news.eu.org

Avatar
Eric Levenez
Le 2/09/06 15:26, dans , « Jean-Marc
Bourguet » a écrit :

Eric Levenez writes:

Ce que je ne comprends pas c'est que mon programme
plantait sur cet appel. Le PowerPC que j'utilise est 32
bits et donc les "int" et les "char *" sont 32 bits.


Je ne connais pas particulièrement bien les conventions
d'appel utilisées dans les power-PC.


J'ai testé sur un PowerPC G4 (32 bits) et un PowerPC G5 (32 et 64 bits), et
l'appel de semctl par "int" marche. J'utilise là, GCC 4.0.1 sur Mac OS X.

Le problème est sur PowerPC du type e300 avec un cross-compilateur GCC 3.4.3
(et non 4.3.3 comme je le disais) sous GNU/Linux/x86.

Je suppose que les conventions d'appels des programmes (utilisation des
registres...) dépend du compilateur mais aussi de la cible choisie (Linux,
Mac OS X...).

Une possibilité serait
qu'elle fasse passer toutes les unions en mémoire et les int
dans des registres. Donc le contenu de la pile ne serait
pas celui attendu.


Peut être, mais quelque soit la valeur passée dans le quatrième argument, la
fonction semctl l'utilise pour initialiser la valeur du sémaphore. Je
pourrais passer un nombre aléatoire, cela devrait marcher (bien sûr le
sémaphore ne marcherait pas comme attendu, mais le programme ne devrait pas
planter).

Sur une machine 64 bits avec des "int" 32 bits et des
"char *" 64 bits, cela ne plante pas, même si la valeur
(ici 1) ne sera pas forcément celle qui servira à
initialiser le sémaphore (dépend de l'alignement).


La convention a peut-être été modifiée pour passer les
petites unions par registre.


Une possibilité serait en effet que lors de l'appel d'une fonction où l'on
passe une union, celle-ci soit passée par adresse et non par valeur (même si
c'est de la taille d'un int). La fonction qui récupère va alors chercher la
valeur à l'adresse passée. Si on appelle avec un int, l'adresse n'est pas
initialisée et la fonction plante. C'est une possibilité.

Un moyen de savoir serait de demander l'assembleur et voir
ce qui se passe.


Je n'ai pas la machine sous les yeux pour regarder cela, mais j'avais
effectivement essayé de comparer les assembleurs générés, mais ne
connaissant pas bien cet assembleur, je n'ai pas compris comment l'appel des
paramètres marchait.

Mais ma principale question est : est-ce que ce comportement (plantage) est
conforme à la norme C ou non dans le cas où sizeof(int) == sizeof(char *).

--
Éric Lévénez -- <http://www.levenez.com/>
Unix is not only an OS, it's a way of life.


Avatar
Jean-Marc Bourguet
Eric Levenez writes:

Mais ma principale question est : est-ce que ce
comportement (plantage) est conforme à la norme C ou non
dans le cas où sizeof(int) == sizeof(char *).


Oui. Du moins, je ne me souviens de rien qui conditionne des
comportements sur l'égalite ou l'inégalité de tailles
d'objets, or si les tailles étaient différentes, tu te ne
poserais pas la question.

--
Jean-Marc
FAQ de fclc: http://www.isty-info.uvsq.fr/~rumeau/fclc
Site de usenet-fr: http://www.usenet-fr.news.eu.org

Avatar
Eric Levenez
Le 2/09/06 18:09, dans , « Jean-Marc
Bourguet » a écrit :

Eric Levenez writes:

Mais ma principale question est : est-ce que ce
comportement (plantage) est conforme à la norme C ou non
dans le cas où sizeof(int) == sizeof(char *).


Oui. Du moins, je ne me souviens de rien qui conditionne des
comportements sur l'égalite ou l'inégalité de tailles
d'objets,


Je ne comprends pas ta réponse. "Oui" c'est (utiliser un int à la place
d'une union d'un int) un comportement indéfini ? Ou oui c'est autorisé ?

or si les tailles étaient différentes, tu te ne
poserais pas la question.


Si à une fonction qui attends un int on passe un short ou un char, ce sera
un int qui sera envoyé et donc reçu. Donc même quand des paramètres ont des
tailles différentes, la norme est clair sur certains points. Et dans mon cas
les tailles sont identiques.

--
Éric Lévénez -- <http://www.levenez.com/>
Unix is not only an OS, it's a way of life.


Avatar
Jean-Marc Bourguet
Eric Levenez writes:

Le 2/09/06 18:09, dans , « Jean-Marc
Bourguet » a écrit :

Eric Levenez writes:

Mais ma principale question est : est-ce que ce
comportement (plantage) est conforme à la norme C ou non
dans le cas où sizeof(int) == sizeof(char *).


Oui. Du moins, je ne me souviens de rien qui conditionne des
comportements sur l'égalite ou l'inégalité de tailles
d'objets,


Je ne comprends pas ta réponse. "Oui" c'est (utiliser un
int à la place d'une union d'un int) un comportement
indéfini ? Ou oui c'est autorisé ?


Indéfini.

or si les tailles étaient différentes, tu te ne poserais
pas la question.


Si à une fonction qui attends un int on passe un short ou
un char, ce sera un int qui sera envoyé et donc reçu. Donc
même quand des paramètres ont des tailles différentes, la
norme est clair sur certains points. Et dans mon cas les
tailles sont identiques.


Je ne vois pas comment passer un short ou un char à une
fonction qui attend un int sauf à mentir sur le prototype, à
les mixer avec des déclarations/définitions K&R ou à caster
des pointeurs de fonctions de façon violente. Dans tous les
cas, on tombe sur du comportement indéfini.

Si ta fonction est correctement prototypée, il va y avoir
promotion (soit qu'on connait le type du paramètre, soit que
c'est une fonction variadique ou il y a de toute manière
promotion) et donc on passe un int.

A+

--
Jean-Marc
FAQ de fclc: http://www.isty-info.uvsq.fr/~rumeau/fclc
Site de usenet-fr: http://www.usenet-fr.news.eu.org



Avatar
Eric Levenez
Le 2/09/06 19:20, dans , « Jean-Marc
Bourguet » a écrit :

Indéfini.


Ok. Mais ce n'est pas clair dans la norme, je n'ai rien trouvé sur le sujet.

Je ne vois pas comment passer un short ou un char à une
fonction qui attend un int sauf à mentir sur le prototype, à
les mixer avec des déclarations/définitions K&R ou à caster
des pointeurs de fonctions de façon violente. Dans tous les
cas, on tombe sur du comportement indéfini.


Oui bien sûr. Je parlais d'une promotion grâce qu prototypage.

Si ta fonction est correctement prototypée, il va y avoir
promotion (soit qu'on connait le type du paramètre, soit que
c'est une fonction variadique ou il y a de toute manière
promotion) et donc on passe un int.


Justement semctl est variadique et c'est là le problème.

Cette fonction semctl est très vieille (+ de 20 ans) et j'ai trouvé beaucoup
de sources très vieux où justement on passait un int. La fonction a évolué
et le 4ème paramètre s'est étoffé, les manuels se sont adaptés et maintenant
il est clair qu'il faut passer une union et non un int. Le problème est que
selon les systèmes et la façon dont le compilateur optimise le passage d'une
union, un programme qui marchait va planter ou non.

Je sais bien qu'un comportement indéfini peut entraîner des problèmes, mais
là le comportement est _devenu_ indéfini. Il n'y avait pas de problème en
K&R sur aucun Unix connu vu que le passage par int était un des exemples des
docs d'AT&T.

Maintenant, comme c'est une fonction variadique, le compilateur ne peut
fournir un warning. Mais j'ai compris, et j'ai changé tous mes semctl.

--
Éric Lévénez -- <http://www.levenez.com/>
Unix is not only an OS, it's a way of life.