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:
- passing all arguments passed to the coroutine following the size requested, or if no such overloads can be found,
- 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
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
没有评论:
发表评论