Je suis préoccupé par la sécurité des conversions de types Je suis en train de concevoir une interface abstraite, qui sera supportée par les plugins exportant un objet orienté C ABI , c.-à-d. des pointeurs vers des objets et des fonctions de style C de la forme func(void *this, ...)
plutôt que des fonctions membres de style C++, ils seront ensuite regroupés dans une structure représentant l'implémentation des objets. Cependant certains de mes cadres sous-jacents, utilisent l'héritage virtuel multiple.Transmettre un objet C++ (avec un héritage virtuel multiple possible) via un C ABI via le pointeur
Exemple simplifié
class A
{
public:
virtual void doA()
}
class B
{
public:
virtual void doB()
}
class C : public A, public B
{
public:
virtual void doA()
virtual void doB()
}
struct impA
{
(*doA)(void *self);
}
struct impB
{
(*doB)(void *self);
}
struct impC
{
(*doA)(void *self);
(*doB)(void *self);
}
void * AfromC(void *v) {
C*c = reinterpret_cast<C*>(v); // Known to be C* type
return static_cast<void*>(static_cast<A*>(c)); // method 1
return reinterpret_cast<void*>(static_cast<A*>(c)); // method 2
//method 3 & 4
C** c = static_cast<C**>(v); // Known to be C* type
return static_cast<void*>(&static_cast<A*>(*c)); // method 3
return static_cast<void*>(static_cast<A**>(c)); // method 4
}
/////////// main code
class A
{
public:
void doA() { imp.doA(self); }
private:
impA imp;
void *self;
}
class B
{
public:
void doB() { imp.doB(self); }
private:
impB imp;
void *self;
}
Tenir compte AfromC, j'ai 4 méthodes possibles d'obtenir un pointeur que je peux en toute sécurité passer par un C ABI, je veux connaître la contrepartie de ces différentes méthodes, ma préférence serait méthode 1.
Je ne suis pas sûr si toutes ces méthodes sont légales ou sûres.
Note: objet sera toujours l'accès par des fonctions dans le binaire dont ils sont créés/détruits leur retour/accepter d'autres objets manipulés par les types de données auto ou de style C (jusqu'à struct de POD)
Bien que j'ai trouvé mention de telles choses sur le net, elles concernent toutes des personnes ayant des problèmes à cause de la conversion en A* a= static_cast<A*>(static_cast<void*>(c)) // c -> C*
, ce qui est prévisible car cela ne corrige pas le vtable et les solutions sont d'utiliser le résumé. type de base (cela ne fonctionne pas pour moi car j'ai besoin de passer par le C ABI), mais j'ai aussi entendu parler de pointeurs virtuels étant plus grands que les pointeurs normaux d'où ma raison de considérer les méthodes 3 et 4, comme cela serait un pointeur normal vers le plus grand pointeur et donc sûr même pour les types avec des pointeurs plus grands.
Donc, ma question principale est la méthode 1 fonctionnera sans problème? Aussi, pourrais-je définir en toute sécurité une fonction de gabarit sur le modèle de template <typename T, typename U> void * void_cast(U v) { static_cast<void *>(static_cast<T>(v)); }
pour simplifier le code du plugin. Enfin si la méthode 1 est correcte pourquoi? et l'une des méthodes peut-elle être utilisée?
Pouvez-vous clarifier "mais va == vc n'est pas garanti" étant donné que je rends va à A * = static_cast (va), puis-je ensuite convertir ceci en un objet de type C soit static_cast (a) ou reinterpret_cast (a), étant donné que je sais que va avait été converti en y notre réponse d'un objet de type C, ou ce ne serait plus sûr après avoir coulé le type de vide? –
glenflet
"dereferencing a2 is Undefined Behavior" vous explique pourquoi vous pensez cela? D'après ce que je peux dire, dans une vue générique, 'a2' et' c2' dérivent identiquement de 'a' et' c', donc ils devraient être également UB - soit oui ou non, pas à mi-chemin. – dascandy
@glenflet: Aucune garantie pour cela ne peut être trouvée dans la norme. Et dans les implémentations utilisant vtables pour les fonctions virtuelles, il est courant que l'adresse de l'objet soit l'adresse de la vtable. Dans ce cas, static_cast effectue la correction de décalage, mais la valeur réelle de 'va' et' vc' est différente dans ce cas. Essayez simplement avec un débogueur et des sous-classes et des sous-classes ayant des fonctions virtuelles –