Memory leak with g++ 11 if parameter construction throws

Viewed 66

If I compile the following code with g++ (version 8.5.3 and also 11.2), memory leaks are shown, which I don't understand.

#include <string>
#include <vector>
#include <filesystem>
#include <iostream>


auto getV() -> std::string {
        return "string from function";
}

auto getP() -> std::filesystem::path {
        throw std::string{"exception"};
}

auto getA( const std::vector<std::string>& p ) {
        auto a = std::vector<std::string>{
                "--t",
                getV(),
                "--a",
                ( getP() / "test" ).string(),
                "--",
        };
        a.insert(a.end(), p.begin(), p.end());
        return a;
}

auto main() -> int {
        try {
                getA({"v1", "v2"});
        } catch ( const std::string& s ) {
                std::cerr << "Caught: " << s << std::endl;
        }
        return 0;
}

Nothing special for compiling the code:

$ g++ -fsanitize=address -Wall -Wextra -std=c++17 -g a.cpp -lstdc++fs

valgrind as well as the GCC address sanitizer show:

$ ./a.out 
Caught: exception

=================================================================
==13329==ERROR: LeakSanitizer: detected memory leaks

Direct leak of 21 byte(s) in 1 object(s) allocated from:
    #0 0x7f72e4591c17 in operator new(unsigned long) ../../../../gcc-11.2.0/libsanitizer/asan/asan_new_delete.cpp:99
    #1 0x40505d in void std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_construct<char const*>(char const*, char const*, std::forward_iterator_tag) /opt/gnu/gcc/include/c++/11.2.0/bits/basic_string.tcc:219
    #2 0x403ff9 in std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string<std::allocator<char> >(char const*, std::allocator<char> const&) /opt/gnu/gcc/include/c++/11.2.0/bits/basic_string.h:539
    #3 0x402754 in getV[abi:cxx11]() /workspace/a.cpp:8
    #4 0x402aa8 in getA(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > const&) /workspace/a.cpp:22
    #5 0x403427 in main /workspace/a.cpp:30
    #6 0x7f72e3818554 in __libc_start_main (/lib64/libc.so.6+0x22554)

Direct leak of 17 byte(s) in 1 object(s) allocated from:
    #0 0x7f72e4591c17 in operator new(unsigned long) ../../../../gcc-11.2.0/libsanitizer/asan/asan_new_delete.cpp:99
    #1 0x40505d in void std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_construct<char const*>(char const*, char const*, std::forward_iterator_tag) /opt/gnu/gcc/include/c++/11.2.0/bits/basic_string.tcc:219
    #2 0x403ff9 in std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string<std::allocator<char> >(char const*, std::allocator<char> const&) /opt/gnu/gcc/include/c++/11.2.0/bits/basic_string.h:539
    #3 0x402ad9 in getA(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > const&) /workspace/a.cpp:22
    #4 0x403427 in main /workspace/a.cpp:30
    #5 0x7f72e3818554 in __libc_start_main (/lib64/libc.so.6+0x22554)

SUMMARY: AddressSanitizer: 38 byte(s) leaked in 2 allocation(s).

This is from GCC 11.2 wherease GCC 8.5.3 actually has 1 leaks more. If I compile the exact same code using clang, there are no leaks. I also tried https://www.onlinegdb.com/ and it has the leaks as well.

Can anyone shed some more light on what's going on here? Is this a compiler bug in GCC or am I doing something wrong? If it is me, is there a way to detect such problems at compile time?

1 Answers
Related