GCC strict aliasing pitfall

In some cases of badly written C/C++ code, the behaviour of a program may depend on the optimization level that was used to compile the code because GCC applies strict aliasing optimizations when compiling with -O2 or higher. According to GCC docs, the effect of -fstrict-aliasing is:

Allow the compiler to assume the strictest aliasing rules applicable to the language being compiled. For C (and C++), this activates optimizations based on the type of expressions. In particular, an object of one type is assumed never to reside at the same address as an object of a different type, unless the types are almost the same.

This means that GCC’s optimizer treats pointers of different types that point to the same memory address as fully independent variables.

In the following example code, a float pointer *f is created as an alternative way to access the integer variable i. That is flawed code, of course, but even from experienced programmers I’ve heard the opinion that it would work nevertheless in two cases: Setting a floating point variable to integer zero is deemed to be safe on architectures adhering to IEEE 754 (which are most) because the binary representation of an IEEE 754 floating point zero is identical to that of an integer zero. In a similar vein, using the wrong type to access a memory location is considered safe, if the variable is casted back to the correct type in some other place of the code. This is not correct, as will be illustrated below:

#include <iostream>

int main() {
  int i = 3;
  float *f = (float*) &i;

  std::cout << i << " -> ";

  *f = 0.;
  std::cout << i << std::endl;
}

The naively expected output of that program would be 3 -> 0, and that’s exactly what is displayed when running an executable compiled with -O0 or -O1. However compiling with -O2 or higher, the assignment to *f is dropped because there is no subsequent read access to that variable, resulting in the output of 3 -> 3:

$ g++ strict-aliasing-test.cc
$ ./a.out
3 -> 0
$ g++ -O2 strict-aliasing-test.cc
$ ./a.out
3 -> 3

This issue is cured by -fno-strict-aliasing:

$ g++ -O2 -fno-strict-aliasing strict-aliasing-test.cc
$ ./a.out
3 -> 0

GCC docs specify that strict aliasing is enabled as parts of -O2, -O3 and -Os compiler switches for versions 3.3–4.5, however I’d guess that this is true for earlier versions, too, although the GCC docs aren’t explicit about it.

The bottom line:

Especially when working with legacy code, it’s hard to be certain that aliasing bugs are not hidden somewhere, so I’d consider it prudent practice to disable strict aliasing optimization by adding the -fno-strict-aliasing compiler flag.

Dieser Beitrag wurde unter Computing abgelegt und mit , , , , verschlagwortet. Setze ein Lesezeichen auf den Permalink.

2 Antworten auf GCC strict aliasing pitfall

  1. zerodtkjoe sagt:

    Thanks for the info

  2. Patrick sagt:

    I try to cover everything about this in a white paper I did originally for the boost development wiki. It’s available around the net in various forms but the most recent version is at Understanding C/C++ Strict Aliasing. Hope this helps. Patrick

Hinterlasse eine Antwort

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind markiert *

CAPTCHA-Bild

*

Du kannst folgende HTML-Tags benutzen: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>