cundefined-behaviortype-punning

cast char * to void **


Suppose I have:

char * bufPtr = ...; // points into a char array with at least sizeof(void *) chars remaining
void *ptr1 = ...;
void *ptr2;

Assuming that bufPtr is properly aligned, are the lines

*(void **)bufPtr = ptr1; // (1)
ptr2 = *(void **)bufPtr; // (2)

legal? I know that char * can alias anything, but does that allowance go the other direction?

UPDATE: The codebase I'm working on is in C, so that's the language I'm most interested in (if I can only get the answer for one). I thought C and C++ would be similar in this regard, but maybe I was wrong about that.


Solution

  • I know that char * can alias anything, but does that allowance go the other direction?

    TLDR:

    No. You can not treat [un[signed]] char data as any other type without violating strict aliasing.

    However, untyped memory is different. You can treat untyped memory a new type via assignment.

    Full Answer:

    Given char *bufptr, casting to a void ** with

    (void **)bufPtr
    

    potentially violates 6.3.2.3 Pointers, paragraph 7:

    A pointer to an object type may be converted to a pointer to a different object type. If the resulting pointer is not correctly aligned for the referenced type, the behavior is undefined.

    Note that the pointer does not have to be dereferenced to invoke undefined behavior - merely creating a misaligned pointer is enough to invoke undefined behavior.

    Assigning value to the dereferenced pointer with

    *(void **)bufPtr = ptr1;
    

    may or may not violate strict aliasing, depending on what bufptr actually points to.

    From comments moved to chat, the memory has been characterized as "untyped". In that case, such an assignment does not violate strict aliasing.

    However, the history of the use of that memory may impact whether or not the memory remains untyped. See Does C strict aliasing make untyped static memory pools impossible?. Note in particular this answer:

    Such an allocator is unimplementable in strictly conforming C, which is C code that does not rely on an unspecified, undefined, or implementation-defined behavior (and does not exceed any minimum implementation limit). It is entirely possible to write such an allocator in conforming C, which is C with extensions.

    I'd compile the allocator code with -fno-strict-aliasing and -fno-ipa-strict-aliasing if using GCC, or an equivalent if not. See https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html#index-fstrict-aliasing.