jayjay
jayjay

Reputation: 1047

Is this a strict aliasing violation?

struct __packed element {
    char val;
};

void foo(struct element arr[4], uint32_t a) {
    uint32_t* i = (uint32_t*)arr;
    *i = a;
}

int main(void) {
    struct element arr[4] __aligned(4);

    foo(arr, 5);
    ...
}

Pretty much as the title, is this a strict aliasing violation in C?

Assuming that arr's stored type is struct element[4]

Upvotes: 2

Views: 131

Answers (2)

alain
alain

Reputation: 12047

It depends on how you will read element arr[4], and on how arr was allocated.

If you will read it as

uint32_t value = *(uint32_t*)arr;

and arr was either allocated dynamically (using malloc), or allocated as an int32_t object with automatic storage duration ("on the stack"), it's OK.
If this is the case, your write changes the effective type to int32_t.
But if you want to read using a type unrelated to uint32_t, and not a character type, it's undefined behavior.

Also, arr needs to be properly aligned for int32_t. (If it was obtained using malloc, it automatically is.)


After the question was edited, it becomes clear that it is indeed undefined behavior, because arr is allocated as follows:

struct element arr[4] __aligned(4);

Upvotes: 3

user694733
user694733

Reputation: 16043

Yes, this (*i = a) is a strict aliasing violation.

N1570 §6.5 p7:

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

  • 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.

None of the above requirements are met:

  • uint32_t is not compatible with effective type char.

  • No qualified types of char used.

  • uint32_t is not unsigned version of char.

  • struct element has no uint32_t members.

  • uint32_t is not a character type.

It would be legal if effective type of the original array would be uint32_t or it would be allocated with malloc for which effective type takes place at the assignment.

uint32_t arr;
foo((struct element*)&arr, 5); // Possible pointer conversion issues still apply

or

void * arr = malloc(4);
foo(arr, 5);

Note that uint32_t* i = (uint32_t*)arr might also lead to undefined behaviour, if converted address cannot be stored in uint32_t* type variable. But that is implementation specific, and thus depends on your platform.

Upvotes: 5

Related Questions