Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use of redefining void pointer to pointer to an anonymous structure?

Tags:

c

uefi

I was working with UEFI driver-related code, and I came across this:

/* 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;

The full source code is in this path http://dox.ipxe.org/include_2ipxe_2efi_2efi_8h_source.html

This is my first encounter with anonymous structure, and I couldn't make out the logic of redefining a void * to a pointer to an anonymous structure. What kind of a hack the "bizzare sabotage attempt" hints at?

like image 696
achoora Avatar asked Dec 14 '16 10:12

achoora


People also ask

What is one reason you would use a void pointer?

Why do we use a void pointer in C programs? We use the void pointers to overcome the issue of assigning separate values to different data types in a program. The pointer to void can be used in generic functions in C because it is capable of pointing to any data type.

Can a void pointer point to a pointer?

A void pointer is a pointer that can point to any type of object, but does not know what type of object it points to. A void pointer must be explicitly cast into another type of pointer to perform indirection. A null pointer is a pointer that does not point to an address.

What do you mean by a void pointer is it possible to dereference a void pointer justify your answer?

A void pointer cannot be dereferenced. We get a compilation error if we try to dereference a void pointer. This is because a void pointer has no data type associated with it. There is no way the compiler can know what type of data is pointed to by the void pointer.

Can we assign a void pointer to an int type pointer?

In the above example, an int variable x is declared first. The void* pointer in C++ can point to any data type and typecast that data type without explicitly typecasting. It does not have any return value. A void* pointer can point to an int, float, or char and typecasts to that specific data type.


2 Answers

The library is using information hiding on the internal data object behind the address held in an EFI_HANDLE. But in doing so, they're making the code more susceptible to accidental bugs.

In C, void* is transparently cast to any other non-void* non-const data pointer type without warning (it's by language design).

Using a non-void pointer type ensures an EFI_HANDLE is only used where EFI_HANDLE belongs. The compiler's type-checking kicks you in the groin when you pass it somewhere else that isn't EFI_HANDLE , but rather a pointer to something else.

Ex: As void*, this will compile without warning or error

#include <string.h>

#define EFI_HANDLE void*

int main()
{
    EFI_HANDLE handle = NULL;

    strcpy(handle, "Something");
}

Changing the alias to:

typedef struct {} *EFI_HANDLE;

will reap the ensuing "incompatible pointer type" compile-time error.

Finally, as an anonymous struct, there is no pointless structure tag name adding to the already-polluted name space that you can use (accidently or nefariously).

like image 94
WhozCraig Avatar answered Sep 19 '22 13:09

WhozCraig


That isn't an anonymous structure, but a struct without a tag.

An anonymous structure can only exist as a member of another struct,
and it must also not have a tag1.

Defining a struct without any members is not allowed. The code you're looking at is using a compiler extension that permits this.

The library is doing this to hide the definition of the structure from the user, while maintaining type safety.

However there is a much better way to do this. If you have a hidden structure definition, you can still define an opaque pointer to it, that has a type, so it is type safe:

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

1 (Quoted from: ISO/IEC 9899:201x 6.7.2.1 Structure and union specifiers 13)
An unnamed member whose type specifier is a structure specifier with no tag is called an anonymous structure; an unnamed member whose type specifier is a union specifier with no tag is called an anonymous union. The members of an anonymous structure or union are considered to be members of the containing structure or union. This applies recursively if the containing structure or union is also anonymous

like image 41
2501 Avatar answered Sep 22 '22 13:09

2501