Re: Help with understanding strict aliasing rules

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Martin Lucina writes:
 > Hello all,
 > 
 > I'm having trouble understanding the infamous "dereferencing type-punned
 > pointer will break strict-aliasing rules" warnings from GCC.
 > 
 > I've read both of the following articles:
 > 
 > 1) http://www.cellperformance.com/mike_acton/2006/06/understanding_strict_aliasing.html
 > 2) http://mail-index.netbsd.org/tech-kern/2003/08/11/0001.html

This paragraph is good:

<< The most common warning you will see is probably "dereferencing type-
punned pointer will break strict-aliasing rules".  The place where it
warns is in general not wrong -- what gcc tries to tell you is that you
will break the aliasing rules when you dereference the pointer later
(unless you cast it back to its original type first).  This warning
should be interpreted as saying that your interfaces are badly designed,
and the correct way to avoid the warning is to redesign them in a way
where you do not need to cast between conflicting types.  (Even if you
often can make this warning go away by changing void** to void*...) >>

Please read the actual standard too.  The rules about pointer type
conversions are at 6.3.2.3.  The appropriate paragraphs are paragraphs
1 and 7.

http://www.open-std.org/JTC1/SC22/WG14/www/docs/n1124.pdf.

 > but am still no wiser as to why the code I'm having trouble with is
 > producing these warnings.  I think the code is legitimate and is not
 > actually violating the strict aliasing rules, and have found a "fix" to
 > make the warnings go away.  Comparing the generated assembler with and
 > without the "fix" shows the same code, and it looks OK to me.
 > 
 > However, I'd like to be 100% sure about this, so I'm asking here.
 > 
 > The following short examples demonstrate my problem:
 > 
 > ----Exhibit A
 > #include <stdio.h>
 > #include <stdlib.h>
 > 
 > typedef struct {
 >     int foo;
 >     int bar;
 > } item_t;
 > 
 > int return_item (void **item);
 > 
 > int return_item (void **item)
 > {
 >     void *mem;
 > 
 >     mem = malloc (1);
 >     if (mem) {
 >         *item = mem;
 >         return 0;
 >     }
 >     else
 >         return 1;
 > }
 > 
 > int main (int argc, char *argv[])
 > {
 >     item_t *item;
 > 
 >     if (return_item ((void **)&item) == 0) {
 >         printf ("%p\n", item);
 >         free (item);
 >     }
 > 
 >     return 0;
 > }

Here, you have declared item as a pointer to item_t.  Because of that,
the compiler knows that any dereference of item_t must be an item.
So, gcc will warn you if the type system might be violated by your
code.  This is a warning, not an error: gcc is telling you that
something bad _might_ happen.

gcc has no way to know that a version of return_item might not look
like this:

int return_item (void **item)
{
   thing *thing_p = ... ;

   *item = thing_p;

which of course would not warn.
   
 > ----Exhibit B
 > #include <stdio.h>
 > #include <stdlib.h>
 > 
 > typedef struct {
 >     int foo;
 >     int bar;
 > } item_t;
 > 
 > int return_item (void **item);
 > 
 > int return_item (void **item)
 > {
 >     void *mem;
 > 
 >     mem = malloc (1);
 >     if (mem) {
 >         *item = mem;
 >         return 0;
 >     }
 >     else
 >         return 1;
 > }
 > 
 > int main (int argc, char *argv[])
 > {
 >     item_t *item;
 >     void *item_temp;
 > 
 >     if (return_item (&item_temp) == 0) {
 >         item = item_temp;
 >         printf ("%p\n", item);
 >         free (item);
 >     }
 > 
 >     return 0;
 > }
 > ----
 > 
 > The code is a generic example of the problem.  The real code that is
 > producing the problem is a hashing API which hashes (void *) and hence
 > uses (void **) as an out parameter type.  
 > 
 > Exhibit A produces a warning as follows:
 > 
 > [nodbug:mato]$ gcc -O2 -Wall -o aliasing-test aliasing-test.c
 > aliasing-test.c: In function `main':
 > aliasing-test.c:28: warning: dereferencing type-punned pointer will break strict-aliasing rules
 > 
 > I'm using gcc version 3.3.5 (Debian 1:3.3.5-13) but the problem persists
 > even when tested with GCC 4.x on newer systems.
 > 
 > Exhibit B is my proposed "fix".  Can anyone advise if the code in
 > Exhibit A is legitimate, i.e. whether or not it's really violating the
 > strict aliasing rules as defined by the C standard?  If not, then I
 > guess the warning is spurious and I can safely use the fix.

gcc warns when it sees

   (foo*)&a

when foo is not type-compatible with the type of a.  (See Section
6.2.7 for the real definition of compatible.)

Andrew.

[Index of Archives]     [Linux C Programming]     [Linux Kernel]     [eCos]     [Fedora Development]     [Fedora Announce]     [Autoconf]     [The DWARVES Debugging Tools]     [Yosemite Campsites]     [Yosemite News]     [Linux GCC]

  Powered by Linux