Re: std::aligned_storage and [[gnu::may_alias]]

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

 



On 20 June 2017 at 22:20, Avi Kivity wrote:
> Does std::aligned_storage need a [[gnu::may_alias]] attribute?
>
>
> According to
> http://en.cppreference.com/w/cpp/language/reinterpret_cast#Type_aliasing, it
> is not legal to cast a char array into another type (that is not a relative
> of char*).

That's not what it says. The cast to a different type is always
allowed, but you can't access the object through the resulting pointer
(i.e. you can't dereference it) except in the specified cases.

> According to the example in
> http://en.cppreference.com/w/cpp/types/aligned_storage, it's perfectly all
> right to cast std::aligned_storage::data to some arbitrary T; and it would
> be hard to find a use for aligned_storage without it.

In that example (and other typical uses of aligned_storage) you store
an object of type T, and then access that object through a pointer of
type T*, so there's no aliasing violation.

> std::function uses [[gnu::may_alias]] in a situation where
> std::aligned_storage may be used.

It uses that char buffer for a very specific situation, where the type
being stored is trivially-copyable, which means that it can be
mempcy'd.

IIRC we added the attribute to the std::function storage so that using
std::swap on that buffer (which just compiles to memcpying the raw
bytes) would work, and "swap" the dynamic types contained in the
buffers. Without that attribute the compiler considered the swap to be
simply copy bytes, but not change the dynamic types stored in those
bytes. I'm not sure whether the compiler has now (GCC 8) been changed,
so that POD structs containing arrays of unsigned char and arrays of
std::byte get special treatment, and are implicitly "may_alias". If so
we could change the array to unsigned char and remove the attribute.
I'd rather not mess with it, given the subtleties of the aliasing
rules and past bugs in this area.

> Is this a problem in libstdc++, the standard, or my understanding of the
> strict aliasing rules?

The two cases aren't directly comparable, because the aligned_storage
example doesn't perform a copy of the aligned_storage data, and it
isn't only used for trivially-copyable types. If the example was
changed to do:

static_vector<std::string, 10> v2 = v1;
v2[0];

Then it would be all kinds of undefined behaviour, because v2 would
simply copy the bytes, but would not contain "live" objects of type T
in the buffer. So no constructors for the T objects would have been
run (and then to make things worse, the static_vector's destructor
would destroy non-existent T objects).

Similarly, this would be undefined:

static_vector<std::string, 10> v2;
std::swap(v1, v2);

To make the copy construction valid the static_vector example would
need to be extended with a copy constructor that used placement new to
construct objects in the buffer, and for the swap case an assignment
operator would also be needed.

Even if the may_alias attribute was added to aligned_storage, the copy
constructor would still be necessary when it contains
non-trivially-copyable objects, so wouldn't really help in general.
When using aligned_storage you need to be careful what you do with
that POD buffer, not just copy it as a POD. For std::function we can
get away with more, because we know only trivially-copyable types are
stored in the buffer.

Somebody should probably edit the cppreference.com example to give
static_vector a deleted copy constructor, to prevent it being used in
undefined ways.



[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