Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Aliasing array with pointer-to-struct without violating the standard

Reading this I understood that you can alias structures (without violating the standard, that is) if they have compatible members, i.e given the following struct:

typedef struct {
    uint32_t a;
    uint32_t b;
} Frizzly;

The following would break aliasing rules:

uint32_t foo(uint16_t *i) {
    Frizzly *f = (Frizzly *)i;
    return f->a;
}

But the following would not:

uint32_t foo(uint32_t *i) {
    Frizzly *f = (Frizzly *)i;
    return f->b;
}

because the "aggregrate type" in question contains types compatible with the pointer that that we're casting into it, i.e. a pointer to type uint32_t can be casted into a struct that contains members (or a member) of type uint32_t without breaking aliasing rules.

First, did I understand this correctly?

Secondly, does the ordering and types of the (other) variables within the struct matter? Say, if Frizzly was defined as follows:

typedef struct {
    uint16_t b[2];
    uint32_t a;
}

After the cast in the second example, b is now backed by memory of incompatible (uint32_t) type. Is the cast still valid (or rather, accessing the values through the casted pointer)? Will changes to either element of a alter the value of first element of i (and the other way around) as though strict aliasing were disabled?

Also, if the above is valid, what if I had a struct like so:

typedef struct {
    void *m;
    uint16_t hooah[4];
} Bar;

The following cast would, if I'm correct, break aliasing rules:

void test(char *boo, size_t dee) {
    Bar *bar = (Bar *)(boo + dee);
    do_other_stuff(bar);
}

Could I make the cast valid simply by adding a single unsigned char member into the struct? In other words, casting pointers of incompatible types generally breaks aliasing rules, but since a cast from a pointer to a struct containing a member of type X into a pointer to X is an exception, can any cast from pointer-to-X to aggregrate-Y made valid simply by adding a (possibly dummy) member of type X into Y?

(I didn't actually test the above code snippets in a compiler.)

EDIT:

I know my wording and examples might be rather poor, so I'll try to rephrase the question: if I understood correctly, it is legal for a pointer-to-struct to alias an array of elements of type 'X' as long as the struct contains members of type 'X'. Now, when dereferencing a member of the struct, does the member have to be of the type 'X', or are exceptions to the strict aliasing rules made for all members of the struct regardless of their types as long as there is one member of the appropriate type?

like image 562
jaymmer - Reinstate Monica Avatar asked Jun 09 '13 06:06

jaymmer - Reinstate Monica


People also ask

What is pointer aliasing in C?

Pointer aliasing is a hidden kind of data dependency that can occur in C, C++, or any other language that uses pointers for array addresses in arithmetic operations. Array data identified by pointers in C can overlap, because the C language puts very few restrictions on pointers.

How does c++ handle aliasing?

In both C and C++ the standard specifies which expression types are allowed to alias which types. The compiler and optimizer are allowed to assume we follow the aliasing rules strictly, hence the term strict aliasing rule.

Is there aliasing in C?

In C, C++, and some other programming languages, the term aliasing refers to a situation where two different expressions or symbols refer to the same object.


1 Answers

According to ISO/IEC9899/TC2 section 6.7.2.1, paragraph 13:

A pointer to a structure object, suitably converted, points to its initial member (or if that member is a bit-field, then to the unit in which it resides), and vice versa

So as long as you are casting the struct pointer to the pointer type of the first member it should not violate strict aliasing (specified in section 6.5 paragraph 7) an element may also be accessed via

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)

but this only works in the other direction (accessing a member via a struct pointer, not accessing a struct via a member pointer)

like image 196
Joe Avatar answered Oct 11 '22 18:10

Joe