2016-12-14 3 views
17

je travaillais avec UEFI code lié pilote, et je suis tombé sur ceci:Utilisation de redéfinir le pointeur vide pour pointer vers une structure anonyme?

/* EFI headers define EFI_HANDLE as a void pointer, which renders type 
* checking somewhat useless. Work around this bizarre sabotage 
* attempt by redefining EFI_HANDLE as a pointer to an anonymous 
* structure. 
*/ 
#define EFI_HANDLE STUPID_EFI_HANDLE 
#include <ipxe/efi/Uefi/UefiBaseType.h> 
#undef EFI_HANDLE 
typedef struct {} *EFI_HANDLE; 

Le code source est dans ce chemin http://dox.ipxe.org/include_2ipxe_2efi_2efi_8h_source.html

Ceci est ma première rencontre avec une structure anonyme, et je ne pouvait pas faire la logique de redéfinir un void * à un pointeur vers une structure anonyme. Quel genre de piratage la "tentative de sabotage de bizzare" fait allusion?

+1

Détail intéressant est aussi '# define' et' # undef' autour de '# include'. Cela suggère que header utilise '# define' au lieu de' typedef', ce qui pourrait indiquer qu'il y a aussi d'autres WTF dans le code. Cela pourrait expliquer le ton agressif passif du commentaire ... – user694733

Répondre

19

La bibliothèque utilise les informations cachant sur l'objet de données interne derrière l'adresse contenue dans un EFI_HANDLE. Mais ce faisant, ils font le code plus sensibles aux bugs accidentels.

En C, void* est transparente pour une fonte autre non void* type pointeur de données non-const sans avertissement (il est par la conception du langage). L'utilisation d'un type de pointeur non vide permet d'utiliser EFI_HANDLE uniquement lorsque EFI_HANDLE appartient. La vérification de type du compilateur vous donne un coup de pied dans l'aine quand vous le passez ailleurs que ce n'est pas EFI_HANDLE, mais plutôt un pointeur vers quelque chose d'autre.

Ex: Comme void*, ce compilera sans avertissement ni erreur

#include <string.h> 

#define EFI_HANDLE void* 

int main() 
{ 
    EFI_HANDLE handle = NULL; 

    strcpy(handle, "Something"); 
} 

Changer l'alias:

typedef struct {} *EFI_HANDLE; 

récoltera le qui a suivi "type pointeur incompatible" erreur de compilation. Enfin, en tant que structure anonyme, il n'y a pas de nom de balise de structure inutile qui s'ajoute à l'espace de nom déjà pollué que vous pouvez utiliser (accidentellement ou de façon néfaste).

+0

Il peut même vous botter à plusieurs reprises, en fonction de vos paramètres de compilation – StoryTeller

+1

@StoryTeller Javascript a aussi cette fonctionnalité. http://softwareengineering.stackexchange.com/a/11812/168891 –

+0

Je ne suis pas sûr de comprendre correctement. Si vous faites cela, quels types _can_ '* EFI_HANDLE' pointent maintenant? –

7

Ce n'est pas une structure anonyme, mais une structure sans balise.

Une structure anonyme ne peut exister en tant que membre d'une autre struct,
et il doit aussi ne pas avoir une étiquette .

La définition d'une structure sans aucun membre n'est pas autorisée. Le code que vous regardez utilise une extension de compilateur qui le permet.

La bibliothèque le fait pour cacher la définition de la structure à l'utilisateur, tout en maintenant la sécurité du type.

Cependant, il existe une bien meilleure façon de procéder.Si vous avez une définition de structure cachée, vous pouvez toujours définir un pointeur opaque à lui, qui a un type, il est donc SÛR type:

struct hidden //defined in a file and not exposed 
{ 
    int a; 
}; 

void Hidden(struct hidden*); 
void Other(struct other*); 
struct hidden* a = NULL; //doesn't see the definition of struct hidden 
Hidden(a); //it may be used 
Other(a); //compiler error 

(Cité par: ISO/CEI 9899: 201x 6.7.2.1 Spécificateurs de structure et d'union 13)
Un membre sans nom dont le spécificateur de type est un spécificateur de structure sans étiquette est appelé structure anonyme ; un membre sans nom dont le spécificateur de type est un spécificateur d'union avec no tag s'appelle une union anonyme. Les membres d'une structure ou union anonyme sont considérés comme membres de la structure ou de l'union contenant. Cela s'applique de manière récursive si la structure ou l'union contenant est également anonyme

+2

Il convient de mentionner que dans les anciennes versions de la norme C, la «structure anonyme» n'existait pas en tant que terme distinct. Pour ces versions, "anonyme" serait juste interprété comme le mot anglais ordinaire signifiant "sans nom", ce qui pour les types de structure semble parfaitement juste à interpréter comme "sans étiquette". – hvd