https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102268

            Bug ID: 102268
           Summary: Wrong code with aliasing union pointers
           Product: gcc
           Version: unknown
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c
          Assignee: unassigned at gcc dot gnu.org
          Reporter: davmac at davmac dot org
  Target Milestone: ---

The following code is adapted from an LLVM PR: 
https://bugs.llvm.org/show_bug.cgi?id=34632

The "test" function is called with all three pointers pointing to the same
union object. Note there are only reads from the active union object so this is
not a type-punning issue. I've also changed the original test case to show that
the issue is present even if changing the active union object requires
assignment directly to the corresponding union member, though it's not clear if
this should be necessary.

Runs ok with GCC 9.4; fails with every version since and on trunk.

--- begin ---
struct s1 {unsigned short x;};
struct s2 {unsigned short x;};
union s1s2 { struct s1 v1; struct s2 v2; };

static int read_s1x(struct s1 *p) { return p->x; }
static void write_s2x(struct s2 *p, int v) { p->x=v;}

int test(union s1s2 *p1, union s1s2 *p2, union s1s2 *p3)
{
  if (read_s1x(&p1->v1))
  {
    unsigned short temp;

    // Active member is v1, so this is fine:
    temp = p3->v1.x;
    struct s2 t2 = { temp };

    // now change active member to v2, and write to it:
    p3->v2 = t2;
    write_s2x(&p2->v2,1234);
    temp = p3->v2.x;

    // now change active member back to v1:
    struct s1 t1 = { temp };
    p3->v1 = t1;
  }
  return read_s1x(&p1->v1);
}
int test2(int x)
{
  union s1s2 q[2];
  struct s1 t1 =  { 4321 };
  q->v1 = t1; // ensure active member is v1
  return test(q,q+x,q+x);
}

int main(void)
{
  if(test2(0) == 4321) __builtin_abort();
}
--- end ---

Reply via email to