Is casting flexible array member to another type undefined behavior?

Viewed 52

Can I cast flexible array member here to another type? Is it undefined behavior? If so, is there a way to make "buf" compatible with any possible type?

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>

struct test
{
    uint64_t a;
    uint64_t b;
    uint64_t c;
    uint64_t d;
    unsigned char buf[];
};

int func1()
{
    struct test *t = malloc(sizeof(*t) + 32);
    uint32_t *p = (uint32_t*) t->buf;
    p[0] = 3; 
    

    return 0;
}

2 Answers

C 2018 6.5 7 says:

An object shall have its stored value accessed only by an lvalue expression that has one of the following types:

— a type compatible with the effective type of the object,

— a qualified version of a type compatible with the effective type of the object,

— a type that is the signed or unsigned type corresponding to the effective type of the object,

— a type that is the signed or unsigned type corresponding to a qualified version of the effective type of the object,

— an aggregate or union type that includes one of the aforementioned types among its members (including, recursively, a member of a subaggregate or contained union), or

— a character type.

The type of the buf member is an array of unsigned char, and its elements have type unsigned char.

p[0] accesses memory with an lvalue of type uint32_t (because p was as uint32_t *p). Considering the list:

— uint32_t is not compatible with array of unsigned char or unsigned char.

— uint32_t is not a qualified version of a type compatible with array of unsigned char or unsigned char.

— uint32_t is not a signed or unsigned type corresponding to array of unsigned char or unsigned char.

— uint32_t is not a signed or unsigned type corresponding to a qualified version of array of unsigned char or unsigned char.

— uint32_t not an aggregate or union type that includes one of the aforementioned.

— uint32_t is not a character type.

Therefore, p[0] violates C 2018 6.5 7. Then, per C 2018 4 2:

If a "shall" or "shall not" requirement that appears outside of a constraint or runtime-constraint is violated, the behavior is undefined…

In addition to Eric Postpischil's answer, you also risk undefined behavior because your flexible array member does not guarantee alignment appropriate for the actual type used.

Per 6.3.2.3 Pointers, paragraph 7 of the C11 (draft) standard:

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 dereferencing the pointer isn't necessary to invoke undefined behavior - the mere act of converting the pointer to a different type is sufficient.

Related