Strict anti-aliasing and pointer to union fields

I have a question about anti-aliasing rules, unions and standards. Suppose we have the following code:

#include <stdio.h> union { int f1; short f2; } u = {0x1}; int * a = &u.f1; short * b = &u.f2; int main() { u.f1 = 1; *a += 1; u.f2 = 2; *b *= 2; printf( "%d %hd\n", *a, *b); return 0; } 

Now let's see how it works:

 $ gcc-5.1.0-x86_64 tc -O3 -Wall && ./a.out 2 4 $ gcc-5.1.0-x86_64 tc -O3 -Wall -fno-strict-aliasing && ./a.out 4 4 

We see that strict smoothing breaks dependencies. Moreover, it seems to be the correct code without violating the strict anti-aliasing rule.

  • So, in the case of union fields, what is the object at the address compatible with all types of union members?
  • If 1 is true, what should the compiler do with pointers to the members of the union? Is the problem a standard that allows this compiler behavior? If not, why?
  • Generally speaking, any compiler behavior with the correct code is unacceptable in any case. So, it seems that this is a compiler error (especially if the access to the unifying field is inside the functions, SA does not break the dependency).
+4
source share
2 answers

Standard C states that smoothing across unions is explicitly permitted.

However, check the following code:

 void func(int *a, short *b) { *a = 1; printf("%f\n", *b); } 

The goal of the strict anti-aliasing rule is that a and b should not be considered a pseudonym. However, you can call func(&u.f1, &u.f2); .

To solve this problem, common sense is to say that the “workaround resolution” that unions should avoid using a strict pseudonym rule applies only when union members are addressed by name.

The standard does not explicitly state this. It can be argued that “if a member used ...” (6.5.2.3) actually indicates that a “bypass” occurs only when accessing a member by name, but it is not 100% clear.

However, it is difficult to find an alternative and self-consistent interpretation. One possible alternative interpretation is along the lines in which the notation func(&u.f1, &u.f2) calls UB, because the overlapping objects are passed to a function that "knows" that it does not receive overlapping objects - kind of like breaking a restrict .

If we apply this first interpretation to your example, we would say that *a in your printf calls UB because the current object stored in this place is short , and 6.5.2.3 does not hit because we do not use a union member by name.

I would suggest, based on your published results, that gcc uses the same interpretation.

This has been discussed here, but I cannot find this thread right now.

+3
source

Technical Corrigendum C99 3 clarifies the order of the Pune based on the join method, stating in section 6.5.2.3:

If the element used to access the contents of the union object is not the same as the last element used to store the value in the object, the corresponding part of the object representation of the value is equal to reinterpreted as representing the object in a new type, as described in 6.2.6 (process , sometimes called "type ping").

See here from 1042 to 1044

+1
source

All Articles