type punning et cast

Le
ld
Je suis entrain de mettre en place la gestion des plug-in dans COS et
je suis tombé sur le problème de devoir convertir un pointeur void* en
pointeur de fonction void (*)(void). Dans la documentation de dlym
(Linux et Open Posix), il est recommandé de faire:

void (*symbol)(void);

*(void**) &symbol = dlsym(lib_handle, symbol_name);

avec void *dlsym(void*, const char*), qui selon eux est valide. Mais
avec gcc4 j'ai un magnifique

warning: dereferencing type-punned pointer will break strict-aliasing
rules

pour éliminer le warning (que je ne veux pas désactiver) je passe par
une variable intermédiaire

void **tmp = (void**)&symbol;

*tmp = dlsym(lib_handle, symbol_name);

et le warning disparaît.

Alors est-ce que le problème est résolu (et portable) ou j'ai
seulement trompé gcc? Ca sent le UB à plein nez tout ca, non?

a+, ld.
Questions / Réponses high-tech
Vidéos High-Tech et Jeu Vidéo
Téléchargements
Vos réponses Page 1 / 2
Gagnez chaque mois un abonnement Premium avec GNT : Inscrivez-vous !
Trier par : date / pertinence
ld
Le #19552891
Juste un complément d'information sur le point qui me chiffonne:

On 12 juin, 22:30, ld
pour éliminer le warning (que je ne veux pas désactiver) je passe par
une variable intermédiaire

void **tmp = (void**)&symbol;



pas de problème pour cette ligne.

*tmp = dlsym(lib_handle, symbol_name);


^^^^^^^^
problème pré-supposé être un UB.

et le warning disparaît.

Alors est-ce que le problème est résolu (et portable) ou j'ai
seulement trompé gcc? Ca sent le UB à plein nez tout ca, non?



a+, ld.
Antoine Leca
Le #19553771
Le 12/06/2009 20:30, Laurent Deniau écrivit :
convertir un pointeur void* en pointeur de fonction void (*)(void).



Et tu espères que cela soit portable ? :^)

Sur un OS que je pratique ces jours-ci, savoir Minix sur i386, qui est
pourtant dûment estampillé Posix, le code (.text) est dans un espace
d'adressage différent des données (.data/.bss) : on ré-utilise le truc
des espaces séparés, qui servait sur les PDP11 et autres 8086 d'avoir
64K+64K... soit +100% d'espace !
Inutile de dire qu'avec ce genre d'architecture, les pointeurs vers
fonctions et les pointeurs vers données sont parfaitement incommen-
surables...

Maintenant histoire d'enfoncer le clou, considères un instant le modèle
"medium" des compilos 8086, où les pointeurs vers fonctions étaient sur
32 bits et les pointeurs vers données étaient sur 16 bits...
Comment ton truc peut-il bien fonctionner sans invoquer des
comportements indéfinis (par la norme) ?


Dans la documentation de dlym (Linux et Open Posix), il est
recommandé de faire:

void (*symbol)(void);
*(void**) &symbol = dlsym(lib_handle, symbol_name);

avec void *dlsym(void*, const char*), qui selon eux est valide.



Mouais... sachant que dlsym doit servir 95% du temps à récupérer des
fonctions, on pourrait le définir avec comme prototype
intptr_t dlsym(void*, const char*);
ce serait tout autant valable... et un poil moins sale.
Comment disaient-ils ? Tous les ordinateurs sont des Vax ? :^)

Enfin bon, c'est mon avis, hein.


Antoine
ld
Le #19554081
On 13 juin, 00:45, Antoine Leca
Le 12/06/2009 20:30, Laurent Deniau écrivit :

> convertir un pointeur void* en pointeur de fonction void (*)(void).

Et tu espères que cela soit portable ? :^)

Sur un OS que je pratique ces jours-ci, savoir Minix sur i386, qui est
pourtant dûment estampillé Posix, le code (.text) est dans un espace
d'adressage différent des données (.data/.bss) : on ré-utilise le t ruc
des espaces séparés, qui servait sur les PDP11 et autres 8086 d'avoir
64K+64K... soit +100% d'espace !
Inutile de dire qu'avec ce genre d'architecture, les pointeurs vers
fonctions et les pointeurs vers données sont parfaitement incommen-
surables...

Maintenant histoire d'enfoncer le clou, considères un instant le modè le
"medium" des compilos 8086, où les pointeurs vers fonctions étaient s ur
32 bits et les pointeurs vers données étaient sur 16 bits...
Comment ton truc peut-il bien fonctionner sans invoquer des
comportements indéfinis (par la norme) ?



Tu as raison, j'aurais du préciser que ce n'était pas au sens strict
du C mais au sens du C modulo où dlsym existe et fonctionne
correctement sur l'OS supposé.

- Si dlsym n'est pas disponible, le code en question est remplacé par
un code qui lève une exception.
- Si dlsym est disponible, je fais l'hypothèse que
l'implémentation est correcte et donc que l'architecture accepte ce
genre manipulation hasardeuse. Sinon dlsym ne pourrait pas renvoyer un
pointeur valide sur une fonction et comme tu le soulignes, il est
principalement utilisé pour ca. Ma question portait donc plus sur une
"équivalence" sémantique des deux expressions puisque du point de vue
du C les deux sont des UB si je ne me trompe pas. Qu'est ce qui fait
que dans un cas gcc émet un warning et pas dans l'autre? Je suppose
que c'est le fait que j'explicite l'utilisation d'un temporaire et
donc que l'aliasing est clairement exprimé,

> Dans la documentation de dlym (Linux et Open Posix), il est
> recommandé de faire:

> void (*symbol)(void);
> *(void**) &symbol = dlsym(lib_handle, symbol_name);

> avec void *dlsym(void*, const char*), qui selon eux est valide.

Mouais... sachant que dlsym doit servir 95% du temps à récupérer de s
fonctions, on pourrait le définir avec comme prototype
      intptr_t dlsym(void*, const char*);
ce serait tout autant valable... et un poil moins sale.
Comment disaient-ils ? Tous les ordinateurs sont des Vax ? :^)

Enfin bon, c'est mon avis, hein.



j'ai lu qqpart qu'ils (open unix) parlent d'avoir une autre fonction
dans une prochaine version:

void (*dlsymf(void*, const char*))(void);

a+, ld.
-ed-
Le #19554861
On 12 juin, 22:30, ld
Je suis entrain de mettre en place la gestion des plug-in dans COS et
je suis tombé sur le problème de devoir convertir un pointeur void* e n
pointeur de fonction void (*)(void).



C'est pas portable. (voire interdit par la norme si je me souviens
bien). Rien ne dit qu'un registre de données ait le droit de pointer
sur une zone de code exécutable, ni qu'il ait la même taille...Le
comportement est indéfini.


.
espie
Le #19554921
In article -ed-
On 12 juin, 22:30, ld
Je suis entrain de mettre en place la gestion des plug-in dans COS et
je suis tombé sur le problème de devoir convertir un pointeur void* en
pointeur de fonction void (*)(void).



C'est pas portable. (voire interdit par la norme si je me souviens
bien). Rien ne dit qu'un registre de données ait le droit de pointer
sur une zone de code exécutable, ni qu'il ait la même taille...Le
comportement est indéfini.



Bah, a cote de ca, dlsym n'est de toutes facons pas "portable", et aucun
mecanisme similaire ne peut l'etre, pour des raisons similaires.

C'est pas un vrai souci, faut juste decider du champ de portabilite de
l'appli...

De facon generale, quasiment tout ce qui concerne les pointeurs de fonction
"dans la vraie vie" (chargement de code, decouverte au vol d'endroit ou sauter
en memoire) n'est pas suffisamment specifie par la norme pour etre utilisable
sur de vrais systemes qui ont besoin de ce type de fonctionnalites...
(devoir connaitre precisement les parametres utilises pour pouvoir definir
un pointeur de fonction n'est pas realiste dans ce contexte).

J'avoue meme n'etre jamais tombe en pratique sur des archis ou les pointeurs
de fonction devaient embarquer autre chose qu'une adresse memoire...
Bruno Ducrot
Le #19643611
On 2009-06-12, ld wrote:
Je suis entrain de mettre en place la gestion des plug-in dans COS et
je suis tombé sur le problème de devoir convertir un pointeur void* en
pointeur de fonction void (*)(void). Dans la documentation de dlym
(Linux et Open Posix), il est recommandé de faire:

void (*symbol)(void);

*(void**) &symbol = dlsym(lib_handle, symbol_name);

avec void *dlsym(void*, const char*), qui selon eux est valide. Mais
avec gcc4 j'ai un magnifique

warning: dereferencing type-punned pointer will break strict-aliasing
rules

pour éliminer le warning (que je ne veux pas désactiver) je passe par
une variable intermédiaire

void **tmp = (void**)&symbol;

*tmp = dlsym(lib_handle, symbol_name);

et le warning disparaît.

Alors est-ce que le problème est résolu (et portable) ou j'ai
seulement trompé gcc? Ca sent le UB à plein nez tout ca, non?



D'apres :

http://www.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html

<cite>
2.12.3 Pointer Types

All function pointer types shall have the same representation as the
type pointer to void. Conversion of a function pointer to void * shall
not alter the representation. A void * value resulting from such a
conversion can be converted back to the original function pointer type,
using an explicit cast, without loss of information.

Note:
The ISO C standard does not require this, but it is required for
POSIX conformance.
</cite>

Comme Linux est POSIX, forcement ca marche. Par contre, en dehors d'un
systeme POSIX, vous prenez des risques.

A plus,

--
Bruno Ducrot

-- Which is worse: ignorance or apathy?
-- Don't know. Don't care.
nicolas.sitbon
Le #19842861
On 26 juin, 17:04, Bruno Ducrot
On 2009-06-12, ld wrote:
> Je suis entrain de mettre en place la gestion des plug-in dans COS et
> je suis tombé sur le problème de devoir convertir un pointeur void* en
> pointeur de fonction void (*)(void). Dans la documentation de dlym
> (Linux et Open Posix), il est recommandé de faire:

> void (*symbol)(void);

> *(void**) &symbol = dlsym(lib_handle, symbol_name);

> avec void *dlsym(void*, const char*), qui selon eux est valide. Mais
> avec gcc4 j'ai un magnifique

> warning: dereferencing type-punned pointer will break strict-aliasing
> rules

> pour éliminer le warning (que je ne veux pas désactiver) je passe p ar
> une variable intermédiaire

> void **tmp = (void**)&symbol;

> *tmp = dlsym(lib_handle, symbol_name);

> et le warning disparaît.

> Alors est-ce que le problème est résolu (et portable) ou j'ai
> seulement trompé gcc? Ca sent le UB à plein nez tout ca, non?

D'apres :

http://www.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html

<cite>
 2.12.3 Pointer Types

All function pointer types shall have the same representation as the
type pointer to void. Conversion of a function pointer to void * shall
not alter the representation. A void * value resulting from such a
conversion can be converted back to the original function pointer type,
using an explicit cast, without loss of information.

Note:
    The ISO C standard does not require this, but it is required for
POSIX conformance.
</cite>

Comme Linux est POSIX, forcement ca marche.  Par contre, en dehors d'un
systeme POSIX, vous prenez des risques.

A plus,

--
Bruno Ducrot

--  Which is worse:  ignorance or apathy?
--  Don't know.  Don't care.



Cette partie de la norme n'existe que dans le nouveau draft POSIX
2008, non encore implémenté, et est encore activement discuté par les
membres de l'opengroup.
J'attend moi aussi avec impatience LE pointeur de fonction générique
mais il faut encore patienter...
nicolas.sitbon
Le #19842941
On 26 juin, 17:04, Bruno Ducrot
On 2009-06-12, ld wrote:
> Je suis entrain de mettre en place la gestion des plug-in dans COS et
> je suis tombé sur le problème de devoir convertir un pointeur void* en
> pointeur de fonction void (*)(void). Dans la documentation de dlym
> (Linux et Open Posix), il est recommandé de faire:

> void (*symbol)(void);

> *(void**) &symbol = dlsym(lib_handle, symbol_name);

> avec void *dlsym(void*, const char*), qui selon eux est valide. Mais
> avec gcc4 j'ai un magnifique

> warning: dereferencing type-punned pointer will break strict-aliasing
> rules

> pour éliminer le warning (que je ne veux pas désactiver) je passe p ar
> une variable intermédiaire

> void **tmp = (void**)&symbol;

> *tmp = dlsym(lib_handle, symbol_name);

> et le warning disparaît.

> Alors est-ce que le problème est résolu (et portable) ou j'ai
> seulement trompé gcc? Ca sent le UB à plein nez tout ca, non?

D'apres :

http://www.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html

<cite>
 2.12.3 Pointer Types

All function pointer types shall have the same representation as the
type pointer to void. Conversion of a function pointer to void * shall
not alter the representation. A void * value resulting from such a
conversion can be converted back to the original function pointer type,
using an explicit cast, without loss of information.

Note:
    The ISO C standard does not require this, but it is required for
POSIX conformance.
</cite>

Comme Linux est POSIX, forcement ca marche.  Par contre, en dehors d'un
systeme POSIX, vous prenez des risques.

A plus,

--
Bruno Ducrot

--  Which is worse:  ignorance or apathy?
--  Don't know.  Don't care.



Cette partie de la norme n'apparaît que dans le nouveau draft POSIX
2008, non encore implémenté, et toujours sujet à discution chez les
membres de l'opengroup.
nicolas.sitbon
Le #19842931
On 13 juin, 01:40, ld
- Si dlsym n'est pas disponible, le code en question est remplacé par
un code qui lève une exception.



Lève une exception? c'est du C++?
Bruno Ducrot
Le #19843151
On 2009-07-28, nicolas.sitbon wrote:

Cette partie de la norme n'existe que dans le nouveau draft POSIX
2008, non encore implémenté, et est encore activement discuté par les
membres de l'opengroup.
J'attend moi aussi avec impatience LE pointeur de fonction générique
mais il faut encore patienter...



Pour une raison que j'ignore, j'etais persuade que ca faisait partie
de la norme et non du draft.

--
Bruno Ducrot

-- Which is worse: ignorance or apathy?
-- Don't know. Don't care.
Publicité
Poster une réponse
Anonyme