<html>
    <head>
      <base href="https://bugs.llvm.org/">
    </head>
    <body><table border="1" cellspacing="0" cellpadding="8">
        <tr>
          <th>Bug ID</th>
          <td><a class="bz_bug_link 
          bz_status_NEW "
   title="NEW - clang-analyzer-cplusplus.NewDeleteLeaks false positive in C++17 with std::unique_pointer in std::tuple"
   href="https://bugs.llvm.org/show_bug.cgi?id=48470">48470</a>
          </td>
        </tr>

        <tr>
          <th>Summary</th>
          <td>clang-analyzer-cplusplus.NewDeleteLeaks false positive in C++17 with std::unique_pointer in std::tuple
          </td>
        </tr>

        <tr>
          <th>Product</th>
          <td>clang
          </td>
        </tr>

        <tr>
          <th>Version</th>
          <td>11.0
          </td>
        </tr>

        <tr>
          <th>Hardware</th>
          <td>PC
          </td>
        </tr>

        <tr>
          <th>OS</th>
          <td>Linux
          </td>
        </tr>

        <tr>
          <th>Status</th>
          <td>NEW
          </td>
        </tr>

        <tr>
          <th>Severity</th>
          <td>enhancement
          </td>
        </tr>

        <tr>
          <th>Priority</th>
          <td>P
          </td>
        </tr>

        <tr>
          <th>Component</th>
          <td>Static Analyzer
          </td>
        </tr>

        <tr>
          <th>Assignee</th>
          <td>dcoughlin@apple.com
          </td>
        </tr>

        <tr>
          <th>Reporter</th>
          <td>andrei@ethereum.org
          </td>
        </tr>

        <tr>
          <th>CC</th>
          <td>dcoughlin@apple.com, llvm-bugs@lists.llvm.org
          </td>
        </tr></table>
      <p>
        <div>
        <pre>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>{})


<a href="https://godbolt.org/z/ceG3ce">https://godbolt.org/z/ceG3ce</a></pre>
        </div>
      </p>


      <hr>
      <span>You are receiving this mail because:</span>

      <ul>
          <li>You are on the CC list for the bug.</li>
      </ul>
    </body>
</html>