Leakage message from sanitizer for program that does not allocate anything

49 views Asked by At

I have some code that does almost nothing, but it does so in a convoluted way. Most importantly, it does not allocate anything. All data is on the stack. It works just fine with many versions of gcc and clang, both on my computer as well as with Godbolds compiler explorer. It does not matter if I compile with -std=20 or -std=17. This is how I compile.

g++  -std=c++17  -g -O0  -fsanitize=address -fno-omit-frame-pointer  leaking_memory.cpp 

However, if I replace the default copy ctor of arena_ptr with a manual implementation, then the sanitizer will report a memory leakage. I can reproduce this with different version of gcc and clang on my computer. I can also reproduce this with different version of gcc on Godbold but not clang. Crucially, I am not able to reproduce this error without copying an arena_ptr into a lambda capture (see function f below). This I would like to understand. Here is my code:

#include <memory>
#include <memory_resource>
#include <functional>

struct arena {
    alignas(64) std::byte memory_[1000000] = {std::byte{}};
    std::byte *pos_ = memory_;
    template<typename T, typename... Args>
    T *new_object(Args &&...args) {
        auto *ptr = new (pos_) T(std::forward<Args>(args)...);
        pos_ += sizeof(T) + (size_t(pos_) % 8UL);
        return ptr;
    }
};

arena * a_ptr = nullptr;

template<typename T>
struct arena_ptr {
    T *value_ptr_ = nullptr;
    explicit arena_ptr(T *value_ptr_) : value_ptr_(value_ptr_) {}
    arena_ptr() = delete;
    arena_ptr(arena_ptr const &) = default;
    //inline arena_ptr(arena_ptr const &other) : value_ptr_(other.value_ptr_) {}
    arena_ptr(arena_ptr &&) = delete;
    arena_ptr &operator=(arena_ptr const &) = delete;
    arena_ptr &operator=(arena_ptr &&) = delete;
    ~arena_ptr() = default;
};

template<typename T, typename... Args>
arena_ptr<T> make_arena_ptr(Args &&...args) {
    T *ptr = a_ptr->new_object<T>(std::forward<Args>(args)...);
    return arena_ptr(ptr);
}

struct TT {};

struct CC {
    using PP = std::function<bool()>;
    PP pp;
    CC(CC const &) = default;
    explicit CC(PP pp) : pp(std::move(pp)) {}
};

auto f(arena_ptr<TT> left) {
    auto f = [left]() { return true; };
    return make_arena_ptr<CC>(f);
}

auto g() {
    auto int_number = []() { return make_arena_ptr<TT>(); };
    return f(int_number());
}

int main() {
    arena a;
    a_ptr = &a;
    auto program = g();
}

And this is the output when I use the manual ctor definition of the arena_ptr:

=================================================================
==1==ERROR: LeakSanitizer: detected memory leaks
Direct leak of 8 byte(s) in 1 object(s) allocated from:
    #0 0x7f2af4f9c528 in operator new(unsigned long) (/opt/compiler-explorer/gcc-13.1.0/lib64/libasan.so.8+0xdb528) (BuildId: c9b24be17e4cbd04bdb4891782c4425e47a9259a)
    #1 0x401b44 in _M_create<f(arena_ptr<TT>)::<lambda()>&> /opt/compiler-explorer/gcc-13.1.0/include/c++/13.1.0/bits/std_function.h:161
    #2 0x401a25 in _M_init_functor<f(arena_ptr<TT>)::<lambda()>&> /opt/compiler-explorer/gcc-13.1.0/include/c++/13.1.0/bits/std_function.h:215
    #3 0x401961 in function<f(arena_ptr<TT>)::<lambda()>&> /opt/compiler-explorer/gcc-13.1.0/include/c++/13.1.0/bits/std_function.h:449
    #4 0x40172f in new_object<CC, f(arena_ptr<TT>)::<lambda()>&> /app/example.cpp:10
    #5 0x401607 in make_arena_ptr<CC, f(arena_ptr<TT>)::<lambda()>&> /app/example.cpp:35
    #6 0x4012f1 in f(arena_ptr<TT>) /app/example.cpp:54
    #7 0x401467 in g() /app/example.cpp:59
    #8 0x4015a8 in main /app/example.cpp:65
    #9 0x7f2af491a082 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x24082) (BuildId: 1878e6b475720c7c51969e69ab2d276fae6d1dee)

SUMMARY: AddressSanitizer: 8 byte(s) leaked in 1 allocation(s).
0

There are 0 answers