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.
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.
On 12 juin, 22:30, ld
pas de problème pour cette ligne.
^^^^^^^^
problème pré-supposé être un UB.
a+, ld.
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) ?
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
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é,
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.
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...
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...
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.
Lève une exception? c'est du C++?
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.