Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does access through pointer change strict aliasing semantics?

With these definitions:

struct My_Header { uintptr_t bits; }

struct Foo_Type { struct My_Header header; int x; }
struct Foo_Type *foo = ...;

struct Bar_Type { struct My_Header header; float x; }
struct Bar_Type *bar = ...;

Is it correct to say that this C code ("case one"):

foo->header.bits = 1020;

...is actually different semantically from this code ("case two"):

struct My_Header *alias = &foo->header;
alias->bits = 1020;

My understanding is that they should be different:

  • Case One considers the assignment unable to affect the header in a Bar_Type. It only is seen as being able to influence the header in other Foo_Type instances.

  • Case Two, by forcing access through a generic aliasing pointer, will cause the optimizer to realize all bets are off for any type which might contain a struct My_Header. It would be synchronized with access through any pointer type. (e.g. if you had a Foo_Type which was pointing to what was actually a Bar_Type, it could access through the header and reliably find out which it had--assuming that's something the header bits could tell you.)

This relies on the optimizer not getting "smart" and making case two back into case one.

like image 633
HostileFork says dont trust SE Avatar asked Aug 14 '18 16:08

HostileFork says dont trust SE


1 Answers

The code bar->header.bits = 1020; is exactly identical to struct My_Header *alias = &bar->header; alias->bits = 1020;.

The strict aliasing rule is defined in terms of access to objects through lvalues:

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

The only things that matter are the type of the lvalue, and the effective type of the object designated by the lvalue. Not whether you stored some intermediate stages of the lvalue's derivation in a pointer variable.


NOTE: The question was edited since the following text was posted. The following text applies to the original question where the space was allocated by malloc, not the current question as of August 23.

Regarding whether the code is correct or not. Your code is equivalent to Q80 effective_type_9.c in N2013 rev 1571, which is a survey of existing C implementations with an eye to drafting improved strict aliasing rules.

Q80. After writing a structure to a malloc’d region, can its members be accessed via a pointer to a different structure type that has the same leaf member type at the same offset?

The stumbling block is whether the code (*bar).header.bits = 1020; sets the effective type of only the int bits; or of the entire *bar. And accordingly, whether reading (*foo).header.bits reads an int, or does it read the entire *foo?

Reading only an int would not be a strict aliasing violation (it's OK to read int as int); but reading a Bar_Struct as Foo_Struct would be a violation.

The authors of this paper consider the write to set the effective type for the entire *bar, although they don't give their justification for that, and I do not see any text in the C Standard to support that position.

It seems to me there's no definitive answer currently for whether or not your code is correct.

like image 170
M.M Avatar answered Nov 15 '22 04:11

M.M