This is the mail archive of the mailing list for the GCC project.

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [PATCH]: Fix PR tree-optimization/21407

Dale Johannesen <> writes:

>> If i give you a pointer to a field, that would mean you could add or
>> subtract bytes and legally get at any other member of the structure,
>> containing structure, etc.
>> I was told by Geoff Keating, and others, that this is not legal in C.
>> Have I been misinformed?  That would be quite sad.
> There was quite a bit of discussion of this internal to Apple, and no
> agreement was reached.  Geoff strongly takes the position you say;
> Mike and I disagree.  The standard seems unclear.

There seem to be two different constructs being confused.

Construct 1:

 struct S
   int a;
   int b;

 void foo(int *x)
   x[1] = 23;

 void bar(struct S *s)
   foo (&s->a);

Construct 2:

 struct Base
   int a;
   int b;

 struct Derived
   int c;
   int d;
   struct Base b;
   int e;
   int f;

 void foo(struct Base *b)
   struct Derived *d = 
     (struct Derived *) ((char *)b) - offsetof(struct Derived, b);

   d->c = 23;

 void bar(struct Derived *d)
   foo (&d->b);

[In both cases, assume that the structure definitions are globally
visible, but 'foo' and 'bar' are in different translation units, and
we're not doing IMA.]

It is my opinion that construct 1 is not allowed by the standard - I
draw this opinion principally from 6.5.6p7,8: "&s->a" produces a
pointer which 'behaves the same as a pointer to the first element of
an array [of int] of length one', and foo() proceeds to access the
nonexistent element two of that array.

However, it is my opinion that construct 2 *is* allowed by the
standard.  Obviously nothing fishy is happening up till the first
statement of foo.  foo begins by converting b to a char*, which is an
escape hatch - everything aliases an array of char (6.5p7), and the
pointer is guaranteed to point to the first byte of Derived.b
(  We then subtract the offset in bytes of Derived.b from
the beginning of struct Derived (7.17p3) and convert back to a struct
Derived* - I read as guaranteeing that this operation recovers
the original pointer passed to bar, which can then be legitimately

On a practical note, I have never seen anyone use construct 1, but
construct 2 and/or variants appear in GCC's own code as well as in
other important bodies of software - as Mark says, this is how people
fake derived objects in C.  Thus, even if construct 2 is not allowed
by the letter of the standard, we cannot reasonably break it.

On another practical note, it appears impractical to distinguish the
two constructs from bar's point of view - in both cases, other members
of the structure are modified than the one that foo was given a
pointer to.  [One could rewrite foo_1 using the same construct as
foo_2, and its operation is then legitimate.]  I therefore come down
on the side of Mark, Dale, and Mike, in believing that the proposed
optimization is illegitimate.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]