0

If I compile this code up to gcc 7.1 with -O2 -Wall (or -O3)

#include <stdio.h>

int main (void)
{
  char array [4] = {0x11,0x22,0x33,0x44};
  unsigned int u32 = *(unsigned int*)array; // intentionally invoking strict aliasing UB here
  printf("%x\n", u32);
  return 0;
}

Godbolt

Then I get I diagnostic about the undefined behavior:

warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]

This only happens when optimizations are enabled.

In 7.2 this warning disappeared and remains disabled to this day. What happened in 7.2 that made the warning go away? As usual with gcc, the change is completely undocumented - https://gcc.gnu.org/gcc-7/changes.html doesn't say a thing about changes to strict aliasing. Compiling with or without -fstrict-aliasing doesn't seem to matter either.

Was the behavior in 7.2 changed on purpose or is this a bug? Are there any known bug reports?

Lundin
  • 195,001
  • 40
  • 254
  • 396
  • indeed, no warning here with GCC 10.2, and no difference with `-Wextra -Wpedantic`, `-std=c99` or `-std=c11`, or between `-O` levels. following with interest and concern... – underscore_d Jan 22 '21 at 09:44
  • @lundin gcc was only issuing the warning if it was not sure that about the alignment e. If the compiler was sure that it will result in unaligned access - it is suppressing the warning and generating safe code. https://godbolt.org/z/vx5ePj – 0___________ Jan 22 '21 at 10:59
  • 1
    @0___________ Why would alignment have anything to do with strict aliasing? – Lundin Jan 22 '21 at 11:44
  • The warning is disabled even with `-Wstrict-aliasing=1` because one of the types is `char`. – Marc Glisse Jan 23 '21 at 12:08
  • 2
    @MarcGlisse The lvalue access is done through an incompatible type so that doesn't matter. – Lundin Jan 23 '21 at 14:44
  • 1
    I'm telling you what test the code in gcc does before printing the warning, not whether it is right or wrong. If you want gcc's behavior to change, you need to post on their bugzilla, not stackoverflow. – Marc Glisse Jan 23 '21 at 17:43
  • @MarcGlisse Ok so what you are saying is that the gcc devs misunderstood the exception to the rule, thinking it applies when you go from character type -> other type? Why did this change at 7.2 then, because it seemed to work ok until then? – Lundin Jan 25 '21 at 08:12
  • 1
    Or they understood the rules but made the warning more conservative, or it changed by accident and wasn't noticed because there was no test about it in their testsuite, or... To know why it changed, you would need to bisect the git revisions to find what patch changed it, use git blame to find some possible culprit (https://gcc.gnu.org/git/?p=gcc.git;a=commit;h=39aac208ab684854886fb72835c538ea1e11d8a1 ?), or ask them on their bugzilla. – Marc Glisse Jan 25 '21 at 08:24
  • 1
    @MarcGlisse Ok from what I can tell by that source is that they changed all warnings to the level equivalent to `-Wstrict-aliasing=1`, which would also silence this warning in versions <7.2. The change log says "Do not warn for accesses to alias-set zero memory" which doesn't make any sense in this case. – Lundin Jan 25 '21 at 08:46
  • In cases where a freshly-derived pointer of one type will be unconditionally equal to a pointer used to access or initialize the original type, gcc will recognize the pointer equivalence despite its willful blindness to cross-type derivation in general. Perhaps the warning is stifled in cases where the compiler consolidates operations on the equivalent pointers? – supercat Jan 25 '21 at 16:58
  • It looks pretty clearly like a bug. Your question indicates you couldn't find any on their tracker. Thus, it would be great if you could create one. – underscore_d Jan 26 '21 at 10:03
  • @underscore_d I'm not really that familiar with Bugzilla so I wouldn't know how to search through all bug report history to see if it's a known issue. – Lundin Jan 26 '21 at 10:08
  • 1
    @underscore_d: If the term "alias-set zero memory" refers to objects whose types are presumed capable of aliasing all other types, then the change would be as described by the change log. – supercat Jan 28 '21 at 23:32

1 Answers1

1

I think gcc's warning logic is treating accesses to a top-level character array via pointers of other types as though it were Standard-defined behavior, even though the Standard does not require such treatment, and even though gcc does not treat pointers which are formed by directly indexing such an array likewise. Change the type of the array to something other than a character type and gcc will squawk. Add a value which gcc cannot recognize as a constant (e.g. write a zero to a volatile object and read it back) to the address and gcc won't squawk with any array type, but won't reliably generate meaningful code either.

supercat
  • 77,689
  • 9
  • 166
  • 211
  • 1
    The question here is why they changed this behavior from a certain gcc version. It's undocumented and the Git change log only says "do not warn for accesses to alias-set zero memory", which isn't related to for example the code in the question. I'm leaning towards this being an accidental and unintended bug. The `-Wstrict-aliasing` was always of shaky quality overall. – Lundin Jan 26 '21 at 08:30
  • 1
    @Lundin: The warning behavior only seems to be different in situations where the array is of character type, a fact you hadn't mentioned in your question. I suspect that whoever changed the warning behavior did so because their interpretation of the Standard was that the "character-type exception" was applicable in that case, and/or because all decent compilers should handle it meaningfully even though the way the Standard is written wouldn't actually require them to do so. Thus, the warning really meant, if anything, "Warning: Low-quality-but-conforming compilers could break this code". – supercat Jan 26 '21 at 16:04
  • 1
    @Lundin: Also, while I'm not familiar with the internal terminology used by gcc, I strongly suspect the term "alias-set zero memory" is referring to objects of types that are presumed capable of aliasing all other types, i.e. character types or any other types that are marked, using suitable directives, as being able to alias everything. – supercat Jan 26 '21 at 16:06