[llvm-bugs] [Bug 48470] New: clang-analyzer-cplusplus.NewDeleteLeaks false positive in C++17 with std::unique_pointer in std::tuple

via llvm-bugs llvm-bugs at lists.llvm.org
Thu Dec 10 04:21:58 PST 2020


https://bugs.llvm.org/show_bug.cgi?id=48470

            Bug ID: 48470
           Summary: clang-analyzer-cplusplus.NewDeleteLeaks false positive
                    in C++17 with std::unique_pointer in std::tuple
           Product: clang
           Version: 11.0
          Hardware: PC
                OS: Linux
            Status: NEW
          Severity: enhancement
          Priority: P
         Component: Static Analyzer
          Assignee: dcoughlin at apple.com
          Reporter: andrei at ethereum.org
                CC: dcoughlin at apple.com, llvm-bugs at lists.llvm.org

For the following code the warning is generated about potential memory leak of
unique_ptr's data returnd in a tuple and put into a struct, but also some
warning about vector's data leaked, I believe both are false positives.

This is the most minimal code I was able to produce, the issues disappear when
I delete anything inside fn().

#include <memory>
#include <vector>

struct I
{
    std::unique_ptr<unsigned> m;
};

static std::tuple<std::unique_ptr<unsigned>, unsigned> alloc1()
{
    return {std::make_unique<unsigned>(1), 0};
}

static std::tuple<std::unique_ptr<unsigned>, unsigned> alloc2()
{
    const std::vector<unsigned> v1;
    const std::vector<unsigned> v2;

    if (v1.size() == 1)
    {
        if (v1[0] > 0)
            throw 1;

        return {std::make_unique<unsigned>(1), 0};
    }
    else if (v2.size() == 1)
    {
        if (v2[0] > 0)
            throw 2;

        return {std::make_unique<unsigned>(1), 0};
    }
    else
        return {std::unique_ptr<unsigned>{}, 0};
}

struct V
{
    unsigned m;
    V(unsigned v) : m{v} {}
};

static V check(unsigned index)
{
    const std::vector<unsigned> v1;
    const std::vector<unsigned> v2;
    if (index >= v2.size() + v1.size())
        return {0u};
    else if (index < v2.size())
        return {v2[index]};
    else
        return {v1[index - v2.size()]};
}

static void fn()
{
    auto [m1, ignore1] = alloc1();
    I i2{std::move(m1)};

    std::vector<unsigned> v1;
    for (auto const& _ : std::vector<unsigned>{})
        v1.emplace_back(0);

    auto [m2, ignore2] = alloc2();
    auto [m3, ignore3] = alloc2();

    auto buff{std::make_unique<int[]>(100)};
    for (const auto& data : std::vector<unsigned>{})
    {
        if (check(data).m > *m2)
            throw 3;
    }
    for (const auto& data : std::vector<unsigned>{})
    {
        if (check(data).m > *m3)
            throw 4;
    }
}


% clang-tidy a.cpp  -- -std=c++17
2 warnings generated.
/home/andrei/dev/a.cpp:58:10: warning: Potential leak of memory pointed to by
'._M_head_impl._M_t._M_t._M_head_impl'
[clang-analyzer-cplusplus.NewDeleteLeaks]
    I i2{std::move(m1)};
         ^
/home/andrei/dev/a.cpp:57:26: note: Calling 'alloc1'
    auto [m1, ignore1] = alloc1();
                         ^
/home/andrei/dev/a.cpp:11:13: note: Calling 'make_unique<unsigned int, int>'
    return {std::make_unique<unsigned>(1), 0};
            ^
/usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/unique_ptr.h:962:30:
note: Memory is allocated
    { return unique_ptr<_Tp>(new _Tp(std::forward<_Args>(__args)...)); }
                             ^
/home/andrei/dev/a.cpp:11:13: note: Returned allocated memory
    return {std::make_unique<unsigned>(1), 0};
            ^
/home/andrei/dev/a.cpp:57:26: note: Returned allocated memory
    auto [m1, ignore1] = alloc1();
                         ^
/home/andrei/dev/a.cpp:58:10: note: Potential leak of memory pointed to by
'._M_head_impl._M_t._M_t._M_head_impl'
    I i2{std::move(m1)};
         ^
/home/andrei/dev/a.cpp:73:29: warning: Potential leak of memory pointed to by
'._M_head_impl._M_t._M_t._M_head_impl'
[clang-analyzer-cplusplus.NewDeleteLeaks]
    for (const auto& data : std::vector<unsigned>{})
                            ^
/home/andrei/dev/a.cpp:64:26: note: Calling 'alloc2'
    auto [m2, ignore2] = alloc2();
                         ^
/home/andrei/dev/a.cpp:19:9: note: Assuming the condition is true
    if (v1.size() == 1)
        ^
/home/andrei/dev/a.cpp:19:5: note: Taking true branch
    if (v1.size() == 1)
    ^
/home/andrei/dev/a.cpp:21:13: note: Assuming the condition is false
        if (v1[0] > 0)
            ^
/home/andrei/dev/a.cpp:21:9: note: Taking false branch
        if (v1[0] > 0)
        ^
/home/andrei/dev/a.cpp:24:17: note: Calling 'make_unique<unsigned int, int>'
        return {std::make_unique<unsigned>(1), 0};
                ^
/usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/bits/unique_ptr.h:962:30:
note: Memory is allocated
    { return unique_ptr<_Tp>(new _Tp(std::forward<_Args>(__args)...)); }
                             ^
/home/andrei/dev/a.cpp:24:17: note: Returned allocated memory
        return {std::make_unique<unsigned>(1), 0};
                ^
/home/andrei/dev/a.cpp:64:26: note: Returned allocated memory
    auto [m2, ignore2] = alloc2();
                         ^
/home/andrei/dev/a.cpp:70:9: note: Taking false branch
        if (check(data).m > *m2)
        ^
/home/andrei/dev/a.cpp:73:29: note: Potential leak of memory pointed to by
'._M_head_impl._M_t._M_t._M_head_impl'
    for (const auto& data : std::vector<unsigned>{})


https://godbolt.org/z/ceG3ce

-- 
You are receiving this mail because:
You are on the CC list for the bug.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-bugs/attachments/20201210/d9a963f6/attachment.html>


More information about the llvm-bugs mailing list