title: gcc, strict-aliasing, and casting through a union
body: <p>Do you have any horror stories to tell?  The GCC Manual recently added a warning regarding -fstrict-aliasing and casting a pointer through a union:</p>
  
  <blockquote>
    <p>[...] Taking the address, casting the resulting pointer and dereferencing the result has <strong><em>undefined behavior</em></strong> [emphasis added], even if the cast uses a union type, e.g.:</p>
  </blockquote>
  
  <pre><code>    union a_union {
          int i;
          double d;
      };
  
      int f() {
          double d = 3.0;
          return ((union a_union *)&amp;d)-&gt;i;
      }
  </code></pre>
  
  <p>Does anyone have an example to illustrate this undefined behavior?</p>
  
  <p>Note this question is <em>not</em> about what the C99 standard says, or does not say.  It is about the actual functioning of <strong>gcc</strong>, and other existing compilers, today.</p>
  
  <p>I am only guessing, but one potential problem may lie in the setting of <code>d</code> to 3.0.  Because <code>d</code> is a temporary variable which is never directly read, and which is never read via a 'somewhat-compatible' pointer, the compiler may not bother to set it.  And then f() will return some garbage from the stack.</p>
  
  <p>My simple, naive, attempt fails. For example:</p>
  
  <pre><code>#include &lt;stdio.h&gt;
  
  union a_union {
      int i;
      double d;
  };
  
  int f1(void) {
      union a_union t;
      t.d = 3333333.0;
      return t.i; // gcc manual: 'type-punning is allowed, provided...' (C90 6.3.2.3)
  }
  
  int f2(void) {
      double d = 3333333.0;
      return ((union a_union *)&amp;d)-&gt;i; // gcc manual: 'undefined behavior' 
  }
  
  int main(void) {
      printf("%d\n", f1());
      printf("%d\n", f2());
      return 0;
  }
  </code></pre>
  
  <p>works fine, giving on CYGWIN:</p>
  
  <pre><code>-2147483648
  -2147483648
  </code></pre>
  
  <p>Looking at the assembler, we see that <strong>gcc</strong> completely optimizes <code>t</code> away:  <code>f1()</code> simply stores the pre-calculated answer:</p>
  
  <pre><code>movl    $-2147483648, %eax
  </code></pre>
  
  <p>while <code>f2()</code> pushes 3333333.0 onto the <em>floating-point</em> stack, and then extracts the return value:</p>
  
  <pre><code>flds   LC0                 # LC0: 1246458708 (= 3333333.0) (--&gt; 80 bits)
  fstpl  -8(%ebp)            # save in d (64 bits)
  movl   -8(%ebp), %eax      # return value (32 bits)
  </code></pre>
  
  <p>And the functions are also inlined (which seems to be the cause of some subtle strict-aliasing bugs) but that is not relevant here.  (And this assembler is not that relevant, but it adds corroborative detail.)</p>
  
  <p>Also note that taking addresses is obviously wrong (or <em>right</em>, if you are trying to illustrate undefined behavior). For example, just as we know this is wrong:</p>
  
  <pre><code>extern void foo(int *, double *);
  union a_union t;
  t.d = 3.0;
  foo(&amp;t.i, &amp;t.d); // undefined behavior
  </code></pre>
  
  <p>we likewise know this is wrong:</p>
  
  <pre><code>extern void foo(int *, double *);
  double d = 3.0;
  foo(&amp;((union a_union *)&amp;d)-&gt;i, &amp;d); // undefined behavior
  </code></pre>
  
  <p>For background discussion about this, see for example:</p>
  
  <p><a href="http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1422.pdf" rel="noreferrer">http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1422.pdf</a><br>
  <a href="http://gcc.gnu.org/ml/gcc/2010-01/msg00013.html" rel="noreferrer">http://gcc.gnu.org/ml/gcc/2010-01/msg00013.html</a><br>
  <a href="http://davmac.wordpress.com/2010/02/26/c99-revisited/" rel="noreferrer">http://davmac.wordpress.com/2010/02/26/c99-revisited/</a><br>
  <a href="http://cellperformance.beyond3d.com/articles/2006/06/understanding-strict-aliasing.html" rel="noreferrer">http://cellperformance.beyond3d.com/articles/2006/06/understanding-strict-aliasing.html</a><br>
  ( = <a href="https://www.google.fr/search?q=The%20memory%20referred%20to%20by%20sp%20is%20an%20alias%20of%20arg%20because%20they%20refer%20to%20the%20same%20address%20in%20memory.%20In%20C99%2C%20it%20is%20illegal%20to%20create%20an%20alias%20of%20a%20different%20type%20than%20the%20original.%20This%20is%20often%20refered%20to%20as%20the%20strict%20aliasing%20rule.%20The%20rule%20is%20enabled%20by%20default%20in%20GCC%20at%20optimization%20levels%20at%20or%20above%20O2.%20Although%20the%20above%20example%20would%20compile%2C%20the%20results%20are%20undefined.%20More%20than%20likely%2C%20arg%20would%20be%20returned%20unchanged%20because%20a%20pointer%20to%20uint16_t%20cannot%20be%20an%20alias%20to%20a%20pointer%20to%20uint32_t%20when%20applying%20the%20strict%20aliasing%20rule.&amp;oq=The%20memory%20referred%20to%20by%20sp%20is%20an%20alias%20of%20arg%20because%20they%20refer%20to%20the%20same%20address%20in%20memory.%20In%20C99%2C%20it%20is%20illegal%20to%20create%20an%20alias%20of%20a%20different%20type%20than%20the%20original.%20This%20is%20often%20refered%20to%20as%20the%20strict%20aliasing%20rule.%20The%20rule%20is%20enabled%20by%20default%20in%20GCC%20at%20optimization%20levels%20at%20or%20above%20O2.%20Although%20the%20above%20example%20would%20compile%2C%20the%20results%20are%20undefined.%20More%20than%20likely%2C%20arg%20would%20be%20returned%20unchanged%20because%20a%20pointer%20to%20uint16_t%20cannot%20be%20an%20alias%20to%20a%20pointer%20to%20uint32_t%20when%20applying%20the%20strict%20aliasing%20rule" rel="noreferrer">search page on Google</a> then view cached page )</p>
  
  <p><a href="https://stackoverflow.com/questions/98650/what-is-the-strict-aliasing-rule">What is the strict aliasing rule?</a><br>
  <a href="https://stackoverflow.com/questions/2771023/c99-strict-aliasing-rules-in-c-gcc/2771041#2771041">C99 strict aliasing rules in C++ (GCC)</a>  </p>
  
  <p>In the first link, draft minutes of an ISO meeting seven months ago, one participant notes in section 4.16:</p>
  
  <blockquote>
    <p>Is there anybody that thinks the rules are clear enough? No one is really able to interpret them.</p>
  </blockquote>
  
  <p><em>Other notes:</em> My test was with gcc 4.3.4, with -O2; options -O2 and -O3 imply -fstrict-aliasing.  The example from the GCC Manual assumes sizeof(double) <strong>>=</strong> sizeof(int); it doesn't matter if they are unequal.</p>
  
  <p>Also, as noted by Mike Acton in the cellperformace link, <code>-Wstrict-aliasing=2</code>, but <em>not</em> <code>=3</code>, produces <code>warning: dereferencing type-punned pointer might break strict-aliasing rules</code> for the example here.</p>