Boost logo

Boost :

Subject: Re: [boost] [beast] Formal review
From: Andrey Semashev (andrey.semashev_at_[hidden])
Date: 2017-07-12 01:19:29


On Wed, Jul 12, 2017 at 2:33 AM, Gavin Lambert via Boost
<boost_at_[hidden]> wrote:
> On 11/07/2017 21:30, Andrey Semashev wrote:
>>
>> You can cast both ways. The casted-from-char pointer can be used as long
>> as the underlying object, in the C++ object model, matches the pointed type.
>> In other words, this is fine:
>>
>> std::size_t* p1 = new std::size_t[10];
>> char* p2 = reinterpret_cast< char* >(p1);
>> std::size_t* p3 = reinterpret_cast< std::size_t* >(p2);
>> assert(p1 == p3);
>> p3[0] = 10; // ok
>>
>> In Beast's case we (and compiler) cannot tell whether the pointers refer
>> to std::size_t objects. For compiler that means it has to assume the objects
>> exist and thus prevent any optimizations that would contradict it.
>
> I'm not an expert, but I believe that strictly according to the standard it
> is UB to cast from a char* to any other pointer type, regardless.

It's not, according to [expr.static.cast]/13 and [expr.reinterpret.cast]/7.

> (It's also important to note that the standard only permits casting to
> "char*" -- not "unsigned char*" or "uint8_t*".)

As noted above, you can cast between any of these types. It is what
you can do with the resulting pointers that is restricted.

Character types (and std::byte since C++17 - which, BTW, has unsigned
char as the base type) are special because storage and object
representation are expressed with these types. See [intro.object]/3,
[basic.types]/4. There are also multiple other places where the spec
allows to obtain a pointer to storage expressed as a pointer to one of
the character types or std::byte.

> Having said that, as long as you are careful to only do so with POD types
> (or at least types that cannot have a vtable) and only when the alignment
> requirements of the type are met, then most compilers should probably let
> you get away with it, because it's far too useful functionality to ban
> outright.

The nature of the type (POD or not) is not significant - all objects
obey the same object model.

> In the example above, since you're starting with a "real" type and then
> casting to char* and back you're guaranteed to meet the alignment
> requirements, so it should be reasonably safe.
>
> You can still run afoul of strict aliasing if you pass both pointers to
> other methods, however (but passing only one should be safe). Hopefully the
> compiler is smart enough to notice that they're aliased as long as you stay
> within the same method.

If you break strict aliasing rules you are in the UB land. The
compiler is not required to notice anything - it simply follows the
assumption that the rules are not violated. The end result is likely
misbehaving code.


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