2021年3月11日星期四

Is it defined behavior to place exotically aligned objects in the coroutine state?

Full question

Is it defined behavior to have an object b placed in the coroutine state (by e.g. having it as a parameter, or perserving it across a suspension point), where alignof(b) > __STDCPP_DEFAULT_NEW_ALIGNMENT__?

Example:

inline constexpr size_t large_alignment =      __STDCPP_DEFAULT_NEW_ALIGNMENT__ * 2;    struct alignas(large_alignment) behemoth {    void attack();    unsigned char data[large_alignment];  };    task<void> invade(task_queue &q) {    behemoth b{};    co_await submit_to(q);    b.attack();  }  

Explanation

When a coroutine is called, heap memory for the coroutine state is allocated via operator new.

This call to operator new may take one of the following forms:

  1. passing all arguments passed to the coroutine following the size requested, or if no such overloads can be found,
  2. passing just the size requested (like an ordinary new T).

Whichever form the call takes, note that it doesn't use the overloads accepting a std::align_val_t, which are necessary to allocate memory that must be aligned more than __STDCPP_DEFAULT_NEW_ALIGNMENT__. Therefore, if an object whose alignment is larger than __STDCPP_DEFAULT_NEW_ALIGNMENT__ must be saved in the coroutine state, there should be no way to guarantee that that object will end up properly aligned in memory.


Experimentation

Godbolt

async f(): Assertion `reinterpret_cast<uintptr_t>(&b) % 32ull == 0' failed.  

so it definitely doesn't work on GCC trunk (11.0.1 20210307). Replacing 32 with 16 (which equals __STDCPP_DEFAULT_NEW_ALIGNMENT__) eliminates this assertion failure.

godbolt.org cannot run Windows binaries, but the assertion fires with MSVC on my computer as well.

https://stackoverflow.com/questions/66546906/is-it-defined-behavior-to-place-exotically-aligned-objects-in-the-coroutine-stat March 09, 2021 at 08:29PM

没有评论:

发表评论