Bug 94337 - Incorrect "dereferencing type-punned pointer will break strict-aliasing rules" warning
Summary: Incorrect "dereferencing type-punned pointer will break strict-aliasing rules...
Status: UNCONFIRMED
Alias: None
Product: gcc
Classification: Unclassified
Component: c (show other bugs)
Version: 10.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords: diagnostic
Depends on:
Blocks:
 
Reported: 2020-03-26 02:03 UTC by Vincent Lefèvre
Modified: 2024-09-29 22:15 UTC (History)
0 users

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Vincent Lefèvre 2020-03-26 02:03:46 UTC
Consider the following example.

#include <stdio.h>

struct s1
{
  int a;
};

struct s2
{
  int a, b;
};

int main (void)
{
  union {
    struct s1 m1[1];
    struct s2 m2[1];
  } u;

  (u.m2)->b = 17;
  printf ("%d\n", ((struct s2 *) (struct s1 *) u.m2)->b);
  printf ("%d\n", ((struct s2 *) u.m1)->b);
  return 0;
}

zira:~> gcc-10 tst.c -o tst -O2 -Wstrict-aliasing
tst.c: In function ‘main’:
tst.c:22:20: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
   22 |   printf ("%d\n", ((struct s2 *) u.m1)->b);
      |                   ~^~~~~~~~~~~~~~~~~~~

But there is no type-punning here. All accesses are done via struct s2. Everything else is pointer conversions, which are not related to the aliasing rules.
Comment 1 Richard Biener 2020-03-26 07:03:40 UTC
The warning only looks at the single expression it quotes which isn't really
enough to discover you are doing right.  It tries to be helpful - if you know
better then disable the warning.
Comment 2 Vincent Lefèvre 2020-03-26 09:12:13 UTC
Why not having a level with no false positives? This would avoid to disable the warning globally.

IMHO, using it when a union is involved is likely to generate false positives.
Comment 3 Vincent Lefèvre 2024-09-29 21:58:17 UTC
Hmm... The code might actually be invalid, but I'm not sure. In all the accesses, the effective type is the union type. But the C standard does not say what happens when one takes the member of a union type.

* If the effective type remains the same (a union), then using any pointer cast to another type would be invalid, but this could be unintuitive and break a lot of code (and GCC should have emitted a warning for both printf lines).

* I suspect that the effective type is locally[*] changed to the type implied by the type of the union member (this would be consistent with the GCC warning). However, it seems that there is nothing about that in the C standard, probably because the above example is really a corner case.

[*] not sure how this is supposed to mean precisely.
Comment 4 Vincent Lefèvre 2024-09-29 22:15:24 UTC
(In reply to Vincent Lefèvre from comment #3)
> * If the effective type remains the same (a union), then using any pointer
> cast to another type would be invalid, but this could be unintuitive and
> break a lot of code (and GCC should have emitted a warning for both printf
> lines).

Well, not the pointer cast itself, but an access to the memory after a conversion of the pointer type (even in the case where the pointer type matches the type of the member, as in ((struct s2 *) u.m2)->b).

Note: the code example is derived from experimental GNU MPFR code (ubf2 branch) as an attempt to avoid aliasing issues in the current code without breaking the API or introducing drawbacks.