Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does inheritance via unwinding violate strict aliasing rule?

I have a struct X which inherits from struct Base. However, in my current setup, due to alignment, size of X is 24B:

typedef struct {
    double_t a;
    int8_t b;
} Base;

typedef struct {
    Base base;
    int8_t c;
} X;

In order to save the memory, I'd like to unwind the Base struct, so I created struct Y which contains fields from Base (in the same order, always at the beginning of the struct), so the size of the struct is 16B:

typedef struct {
    double_t base_a;
    int8_t base_b;
    int8_t c;
} Y;

Then I'm going to use instance of struct Y in a method which expects a pointer to Base struct:

void print_base(Base* b)
{
  printf("%f %d\n", b->a, b->b);
}
// ...
Y data;
print_base((Base*)&data);

Does the code above violates the strict aliasing rule, and causes undefined behavior?

like image 659
Marcin Kolny Avatar asked Dec 08 '17 08:12

Marcin Kolny


1 Answers

First, Base and Y are not compatible types as defined by the standard 6.2.7, all members must match.

To access an Y through a Base* without creating a strict aliasing violation, Y needs to be "an aggregate type" (it is) that contains a Base type among its members. It does not.

So it is a strict aliasing violation and furthermore, since Y and Base are not compatible, they may have different memory layouts. Which is kind of the whole point, you made them different types for that very reason :)

What you can do in situations like this, is to use unions with struct members that share a common initial sequence, which is a special allowed case. Example of valid code from C11 6.5.2.3:

union {
  struct {
    int alltypes;
  } n;
  struct {
    int type;
    int intnode;
  } ni;
  struct {
    int type;
    double doublenode;
  } nf;
} u;

u.nf.type = 1;
u.nf.doublenode = 3.14;
/* ... */
if (u.n.alltypes == 1)
  if (sin(u.nf.doublenode) == 0.0)
like image 165
Lundin Avatar answered Nov 13 '22 15:11

Lundin