C++ coroutine leaking memory and frame

Viewed 434

I'm experimenting with coroutines in C++ using cppcoro. But Address Sanitizer seems always unhappy that I'm leaking memory. Why? I've never allocated anything using raw new/delete and have never cause a circular dependency with shared_ptr.

#include <cppcoro/task.hpp>
#include <cppcoro/sync_wait.hpp>
#include <iostream>


class A {
public:
    A() { std::cerr << "A ctor\n"; }
    ~A() { std::cerr << "A dtor\n"; }
};


int main()
{
    auto getACoro = []() -> cppcoro::task<std::shared_ptr<A>> {
        co_return std::make_shared<A>();
    };

    auto foo = [getACoro]() -> cppcoro::task<> {
        co_await getACoro();
        co_return;
    };

    auto coro = [&foo]() -> cppcoro::task<> {
        co_await foo();
    };
    cppcoro::sync_wait(coro());
}

Compile with: g++ -std=c++20 -focorutines main.cpp -o main -lcppcoro -g -O -fsanitize=address

Then address sanitizer complains with:

=================================================================
==274677==ERROR: LeakSanitizer: detected memory leaks

Indirect leak of 88 byte(s) in 1 object(s) allocated from:
    #0 0x7ff558d7af41 in operator new(unsigned long) /build/gcc/src/gcc/libsanitizer/asan/asan_new_delete.cpp:99
    #1 0x560128e69267 in operator() /home/marty/Documents/experiments/cpp/main.cpp:47
    #2 0x560128e69267 in main::{lambda()#3}::operator()() const [clone .actor] /home/marty/Documents/experiments/cpp/main.cpp:50

Indirect leak of 80 byte(s) in 1 object(s) allocated from:
    #0 0x7ff558d7af41 in operator new(unsigned long) /build/gcc/src/gcc/libsanitizer/asan/asan_new_delete.cpp:99
    #1 0x560128e6878e in operator() /home/marty/Documents/experiments/cpp/main.cpp:43
    #2 0x560128e6878e in main::{lambda()#2}::operator()() const [clone .actor] /home/marty/Documents/experiments/cpp/main.cpp:45
    #3 0x560128f7b997  (/home/marty/Documents/experiments/cpp/main+0x145997)

Indirect leak of 24 byte(s) in 1 object(s) allocated from:
    #0 0x7ff558d7af41 in operator new(unsigned long) /build/gcc/src/gcc/libsanitizer/asan/asan_new_delete.cpp:99
    #1 0x560128e71168 in __gnu_cxx::new_allocator<std::_Sp_counted_ptr_inplace<A, std::allocator<A>, (__gnu_cxx::_Lock_policy)2> >::allocate(unsigned long, void const*) /usr/include/c++/10.2.0/ext/new_allocator.h:115
    #2 0x560128e71168 in std::allocator<std::_Sp_counted_ptr_inplace<A, std::allocator<A>, (__gnu_cxx::_Lock_policy)2> >::allocate(unsigned long) /usr/include/c++/10.2.0/bits/allocator.h:173
    #3 0x560128e71168 in std::allocator_traits<std::allocator<std::_Sp_counted_ptr_inplace<A, std::allocator<A>, (__gnu_cxx::_Lock_policy)2> > >::allocate(std::allocator<std::_Sp_counted_ptr_inplace<A, std::allocator<A>, (__gnu_cxx::_Lock_policy)2> >&, unsigned long) /usr/include/c++/10.2.0/bits/alloc_traits.h:460
    #4 0x560128e71168 in std::__allocated_ptr<std::allocator<std::_Sp_counted_ptr_inplace<A, std::allocator<A>, (__gnu_cxx::_Lock_policy)2> > > std::__allocate_guarded<std::allocator<std::_Sp_counted_ptr_inplace<A, std::allocator<A>, (__gnu_cxx::_Lock_policy)2> > >(std::allocator<std::_Sp_counted_ptr_inplace<A, std::allocator<A>, (__gnu_cxx::_Lock_policy)2> >&) /usr/include/c++/10.2.0/bits/allocated_ptr.h:97
    #5 0xbe0b47d5ffffffff  (<unknown module>)

SUMMARY: AddressSanitizer: 192 byte(s) leaked in 3 allocation(s).

As far I can tell. The shared_ptr should have destructed right after co_await getACoro();. Why is it considered leaked? And why are the coroutine frames leaking?

Compiler: GCC 10.2 OS: Linux

0 Answers
Related