Boost logo

Boost :

Subject: Re: [boost] [optional] Strict Aliasing Warnings on Trunk
From: Patrick Horgan (phorgan1_at_[hidden])
Date: 2009-12-18 14:00:02


Dean Michael Berris wrote:
> I've recently been seeing this error more and more especially on GCC with -Wall:
>
> /home/dean/boost/boost/optional/optional.hpp:407: warning:
> dereferencing pointer ‘<anonymous>’ does break strict-aliasing rules
> /home/dean/boost/boost/optional/optional.hpp:427: note: initialized from here
>
> and:
>
> /home/dean/boost/boost/function/function_base.hpp:321: warning:
> dereferencing type-punned pointer will break strict-aliasing rules
> /home/dean/boost/boost/function/function_base.hpp:325: warning:
> dereferencing type-punned pointer will break strict-aliasing rules
>
> This is on Linux and GCC 4.4.1.
>
> I'm not an expert in this regard but is there a way to either silence
> or avoid these warnings? Anything you want me to try from my end?
>
> Thanks in advance and I hope this helps.
>
It's a fair bit dangerous to silence these since it's the compiler's way
of telling you that you're invoking undefined behavior, and that when
you turn on optimization your code isn't going to work as expected.

The following program generates 6 warnings about breaking
strict-aliasing rules, and many would dismiss them. The correct output
of the program is:

00000020
00200000

but when optimization is turned on it's:

00000020
00000020

THAT's what the warning is trying to tell you, that the optimizer is
going to do things that you don't like. In this case seeing that acopy
is set to a and never touched again, strict aliasing lets it optimize by
just returning the original value of a at the end.

uint32_t
swaphalves(uint32_t a)
{
    uint32_t acopy=a;
    uint16_t *ptr=(uint16_t*)&acopy;// can't use static_cast<>, not legal.
                                    // you should be warned by that.
    uint16_t tmp=ptr[0];
    ptr[0]=ptr[1];
    ptr[1]=tmp;
    return acopy;
}

int main()
{
    uint32_t a;
    a=32;
    cout << hex << setfill('0') << setw(8) << a << endl;
    a=swaphalves(a);
    cout << setw(8) << a << endl;
}

Here's the (annotated) x86 assembler generated by gcc 4.4.1 for swaphalves.

_Z10swaphalvesj:
    pushl %ebp
    movl %esp, %ebp
    subl $16, %esp
    movl 8(%ebp), %eax # get a in %eax
    movl %eax, -8(%ebp) # and store in in acopy
    leal -8(%ebp), %eax # now get eax pointing at acopy (ptr=&acopy)
    movl %eax, -12(%ebp) # save that ptr at -12(%ebp)
    movl -12(%ebp), %eax # get the ptr back in %eax
    movzwl (%eax), %eax # get 16 bits from ptr[0] in eax
    movw %ax, -2(%ebp) # store the 16 bits into tmp
    movl -12(%ebp), %eax # get the ptr back in eax
    addl $2, %eax # bump up by two to get to ptr[1]
    movzwl (%eax), %edx # get that 16 bits into %edx
    movl -12(%ebp), %eax # get ptr into eax
    movw %dx, (%eax) # store the 16 bits into ptr[1]
    movl -12(%ebp), %eax # get the ptr again
    leal 2(%eax), %edx # get the address of ptr[1] into edx
    movzwl -2(%ebp), %eax # get tmp into eax
    movw %ax, (%edx) # store into ptr[1]
    movl -8(%ebp), %eax # return original a.
    leave
    ret

Scary, isn't it? Of course you could use -fno-strict-aliasing to get
the right output, but the generated code won't be as good. A better way
to accomplish the same thing without the warning's or the incorrect
output is to define swaphalves like this:

uint32_t
swaphalves(uint32_t a)
{
    union swapem{
        uint32_t a;
        uint16_t b[2];
    };
    swapem s={a};
    uint16_t tmp;
    tmp=s.b[0];
    s.b[0]=s.b[1];
    s.b[1]=tmp;
    return s.a;
}

This follows the rules and helps the compiler generate MUCH better code:

_Z10swaphalvesj:
    pushl %ebp # save the original value of ebp
    movl %esp, %ebp # point ebp at the stack frame
    movl 8(%ebp), %eax # get a in eax
    popl %ebp # get the original ebp value back
    roll $16, %eax # swap the two halves of a and return it
    ret

Ignore strict aliasing warnings at your peril. But if you really want
to -Wno-strict-warnings will do it.

Patrick


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk