Aliasing: Aliasing refers to the situation where the same memory location can be accessed using different names.
For Example, if a function takes two pointers A and B which have the same value, then the name A aliases the name B i.e., we say the pointers A and B alias each other.
Below is the program to illustrate aliasing in C:
In the above program, the value of data is 20. When this variable is aliased to function gfg() then the changes made to memory location referred by pointer ‘b’, got reflected in ‘a’ as well. This is done because they referred to the same memory location.
GCC compiler makes an assumption that pointers of different types will never point to the same memory location i.e., alias of each other. Strict aliasing rule helps the compiler to optimize the code. The Strict Aliasing rule is enabled by default on optimization levels 2 and beyond, and when one tries to compile a program with aforementioned details the compiler throws warnings, though the program still compiles and can be executed, the output of such a program remains unpredictable.
In the above code, the compiler can not optimize the code to directly return 10, since both pointers ptr1 and ptr2 could be an alias of each other. In that case, it would return 11, not 10.
Even if we are sure that both pointers are not an alias of each other, then also optimization could not be performed by the compiler. Now, to solve this problem strict aliasing rule has been introduced. It ensures compiler that pointers of different types can not be an alias of each other.
Here code can be optimized directly to return 10 since the compiler knows for sure that both pointers would not be an alias of each other. Here, we can observe that the compilers can leverage strict-aliasing rules to generate better-optimized code.
Note: Since, both C and C++ allow casting between pointer types, which will eventually create aliases and thus, violate the compiler’s assumption.
Another example program that violates the strict aliasing rule:
The above code simply left shifts the value of variable val by 16 bits, by swapping the lower 16 bits to the higher 16 bits and setting the higher 16 bits to 0, however here we use __uint16_t pointer ptr to create an alias of ‘val’, this violates the strict aliasing rule, and this may lead to different outputs on different levels of optimizations (i.e. O1, O2 and O3) on a compiler.
How To Bypass the Strict Aliasing Rules?:
Although the rules are implemented to prevent unexpected behavior, the rules can be bypassed by ignoring the warnings and explicitly using the -fno-strict-aliasing tag while compiling, this ensures no rules are enforced even when level O3, O2 optimizations are applied.