Boost logo

Boost :

Subject: Re: [boost] [interest] underlying type library
From: Marshall Clow (mclow.lists_at_[hidden])
Date: 2011-08-22 09:20:47


On Aug 22, 2011, at 5:55 AM, Sebastian Redl wrote:
> On 22.08.2011 13:04, Julian Gonggrijp wrote:
>>
>> Have we not identified the cases for which an
>> invalid result will be obtained? Can we therefore not maintain --
>> making use of the semantical definition of move_raw and restricting
>> ourselves to the set of unproblematic types -- that bitwise copying is
>> a safe implementation of move_raw even though in a very strict
>> juridical sense it may be undefined behaviour?
> Absolutely not.
> http://blog.llvm.org/2011/05/what-every-c-programmer-should-know.html
> Undefined behavior isn't just about "a very strict juridical sense" of things. Compilers are allowed to assume that UB doesn't happen. If you memcpy over a non-POD, the compiler is allowed to assume the whole branch containing the memcpy is dead code - it cannot ever be reached, because reaching it would invoke UB. Let's say you have this:
>
> if (x != 42) {
> memcpy(&nonpod, &source, size);
> } else {
> other_code();
> }
> std::cout << x << std::endl;
>
> The behavior of the memcpy is undefined. As such, the compiler can generate any code it wants for this branch - like the code of the second branch, thus eliminating the branching entirely.
> But not only that. In fact, because the compiler will assume that the program is valid, and entering the memcpy branch would invoke UB, it can deduce that x cannot possibly be anything but 42! That is, the std::cout could output "42" even if you set x to something other than 42, because the optimizer replaced all occurrences of x with the constant 42.
>
> Now, I don't know any compiler that is actually that strict, especially with memcpy, but my point is that *there is no such thing as benign undefined behavior*.

I do (and it's gcc)

Consider the following code:

void do_something ( int *foo ) {
        log ( "do_something ( %d )", *foo );
        if ( foo == NULL ) {
        // #1 block of code
                }
        else {
        // #2 block of code
                }
        }

Under higher optimization levels (-02 and above), gcc will not generate code for the test for NULL (and the associated block #1). It will generate code that looks like this instead:

void do_something ( int *foo ) {
        log ( "do_something ( %d )", *foo );
// #2 block of code
        }

This behavior is enabled by default, and can be disabled with the -fno-delete-null-pointer-checks option.
The reasoning behind this (as far as I can tell) is that:
* The program indirected the pointer foo on the first line of do_something.
* If that pointer is NULL, then the behavior of the program is undefined.
==> Therefore, we can assume that the pointer is != NULL, and omit the test.

-- Marshall

Marshall Clow Idio Software <mailto:mclow.lists_at_[hidden]>

A.D. 1517: Martin Luther nails his 95 Theses to the church door and is promptly moderated down to (-1, Flamebait).
        -- Yu Suzuki


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