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

--- Comment #29 from Martin Sebor <msebor at gcc dot gnu.org> ---
(In reply to rguent...@suse.de from comment #25)
> 
> Istr the proposal suggests a -fno-provenance option. How would we handle
> these cases with that?

The proposal is still being discussed and it's not clear how it will evolve or
if the option will survive.  I'm not sure if the handling of these cases would
be consistent under the option.  I imagine some would be expected to work as if
whole objects were just arrays of bytes once provenance were not considered
after some non-trivial pointer expression were involved, while others would
still be undefined because of the array rule which is unrelated to provenance
(e.g., indexing past the end of an array).  I haven't absorbed the proposals
enough yet to say for sure where the line is, and even the authors are still
forming their opinion on some of these cases.

(In reply to Bernd Edlinger from comment #26)
> Hmmm, does this imply that
> the "container_of" macro in linux/include/kernel.h will be broken:

The macro is broken today because it relies on undefined behavior: advancing a
pointer from one subobject to another.  The latest revision of the proposal
discusses some ideas that might make this and other similar examples work
(e.g., a "function" such as a built-in that would make the compiler either lose
the provenance of a pointer or assign it a different provenance without
changing its value).  Some people have suggested that casts might make it work.

This isn't new.  Just like it's not valid to take a pointer to one array and
advance it to the next and dereference it, it's not valid to take a pointer to
a struct member, advance it to point to another member, and then derefernce it.
 Given the following definition, the call f(2) is undefined and GCC eliminates
the test on that basis.  The same rule applies to struct members.

  char a[2][2];

  void f (int i)
  {
    char c = a[1][0];
    char *p = &a[0][i];
    *p = 1;             // can only change the array a[0], not a[1]
    if (c != a[1][0])   // folded to false because a[0][i] is only defined when
i is zero
      __builtin_abort ();
  }

To make it "work" this way you need to convince the compiler the
two-dimensional 2 X 2 matrix is really a one dimensional 4-element array.  The
following works with GCC but it's still undefined so I wouldn't recommend
relying on it.  I imagine making the pointer volatile would always work (but
it's still undefined).

void g (int i)
{
  char (*p)[4] = a;   // -Wincompatible-pointer-types here

  char c = (*p)[2];
  char *q = &(*p)[i];
  *q = 1;
  if (c != (*p)[2])   // not folded
    __builtin_abort ();
}

Reply via email to