https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114900

            Bug ID: 114900
           Summary: Overaligned locals in coroutines are not properly
                    aligned
           Product: gcc
           Version: 13.2.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: jankodedic2 at gmail dot com
  Target Milestone: ---

GCC 13.2.0 (x86-64)
Flags: -std=c++20
Godbolt link: https://godbolt.org/z/f3KGaGWW6

Overaligned locals in coroutines are not properly aligned. If a local variable
is marked with alignas(n), GCC seemingly does nothing about it. If a local
variable just has an overaligned type, GCC seems to overallocate to try and
align it correctly but alignment is still incorrect (overallocation is probably
the only solution until P2014 is resolved -
https://github.com/cplusplus/papers/issues/750).

Full example pasted below:

```
#include <coroutine>
#include <cstdlib>
#include <cstdint>
#include <iostream>

static constexpr std::size_t alignment = 1 << 13;

bool
is_aligned(void* p)
{
    return ((std::uintptr_t)p % alignment) == 0;
}

void* malloc_address = nullptr;
void* local_address = nullptr;

struct coro
{
    std::coroutine_handle<> coroutine_handle;

    struct promise_type
    {
        void*
        operator new(std::size_t n)
        {
            std::cout << "allocating " << n << " bytes\n";
            malloc_address = std::malloc(n);
            return malloc_address;
        }

        void
        operator delete(void* p)
        {
            std::free(p);
        }

        std::suspend_never
        initial_suspend()
        {
            return {};
        }

        coro
        get_return_object()
        {
            return {std::coroutine_handle<promise_type>::from_promise(*this)};
        }

        void
        return_void()
        {}

        void
        unhandled_exception()
        {}

        std::suspend_always
        final_suspend() noexcept
        {
            return {};
        }
    };
};

struct S
{
    alignas(alignment) int x = 42;
};

coro
foo()
{
#if 0
    alignas(alignment) int x = 42;
#else
    S x;
#endif

    local_address = &x;
    std::cout << "is aligned? " << is_aligned(local_address) << std::endl;
    co_return;
}

int
main()
{
    std::cout << "max align: " << alignof(std::max_align_t) << std::endl;
    auto c = foo();
    std::cout << "malloc_address: " << malloc_address << std::endl;
    std::cout << "local_address: " << local_address << std::endl;
    std::cout << "difference: " << ((char*)local_address -
(char*)malloc_address) << std::endl;
}
```

Reply via email to