Potential memory leak if a tuple of a unique pointer is captured in lambda

578 Views Asked by At

clang-tidy and scan-build warn about a potential memory leak in this code:

#include <tuple>
#include <memory>

int main()
{
    auto lambda = [tuple = std::make_tuple(std::make_unique<int>(42))] {};
}
$ clang-tidy main.cpp -checks="clang*"
1 warning generated.
/foo/main.cpp:7:1: warning: Potential leak of memory pointed to by field '_M_head_impl' [clang-analyzer-cplusplus.NewDeleteLeaks]
}
^
/foo/main.cpp:6:44: note: Calling 'make_unique<int, int>'
    auto lambda = [tuple = std::make_tuple(std::make_unique<int>(42))] {};
                                           ^~~~~~~~~~~~~~~~~~~~~~~~~
/usr/bin/../lib/gcc/x86_64-redhat-linux/11/../../../../include/c++/11/bits/unique_ptr.h:962:30: note: Memory is allocated
    { return unique_ptr<_Tp>(new _Tp(std::forward<_Args>(__args)...)); }
                             ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/foo/main.cpp:6:44: note: Returned allocated memory
    auto lambda = [tuple = std::make_tuple(std::make_unique<int>(42))] {};
                                           ^~~~~~~~~~~~~~~~~~~~~~~~~
/foo/main.cpp:7:1: note: Potential leak of memory pointed to by field '_M_head_impl'
}
^

Is there anything I do not see, or is it a false positive?


Environment: clang 13.0.0, gcc 11.3.1.

Compile commands:

[
{
  "directory": "/foo",
  "command": "/usr/bin/g++ -std=c++17 /foo/main.cpp",
  "file": "/foo/main.cpp"
}
]

Notes: the issue is reproducible with -std=c++17 and -std=c++20, but not with -std=c++14.

2

There are 2 best solutions below

1
Jeryl Vaz On BEST ANSWER

An unsolved bug in clang-tidy: https://github.com/llvm/llvm-project/issues/55219

It doesn't have anything to do with tuples or smart pointers as seen in the simplified reproduction in this comment.

14
Aconcagua On

The lambda gets destructed after running out of scope, together with it is capture – and as the tuple is captured by value it gets destructed as well, together with it the smart pointer and thus the object stored there.

Try this to see:

#include <iostream>
#include <memory>
#include <tuple>

struct S
{
    S() { std::cout << "constructed" << std::endl; }
    ~S() { std::cout << "destructed" << std::endl; }
};

int main()
{
    auto lambda = [tuple = std::make_tuple(std::make_unique<S>())] {};
    return 0;
}

See on godbolt.

So apparently a false positive...