<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 - Static analyzer temp-dtor-inlining doesn't appear to escape by-value function parameters"
   href="https://bugs.llvm.org/show_bug.cgi?id=37459">37459</a>
          </td>
        </tr>

        <tr>
          <th>Summary</th>
          <td>Static analyzer temp-dtor-inlining doesn't appear to escape by-value function parameters
          </td>
        </tr>

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

        <tr>
          <th>Version</th>
          <td>trunk
          </td>
        </tr>

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

        <tr>
          <th>OS</th>
          <td>All
          </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>george.burgess.iv@gmail.com
          </td>
        </tr>

        <tr>
          <th>CC</th>
          <td>llvm-bugs@lists.llvm.org
          </td>
        </tr></table>
      <p>
        <div>
        <pre>It looks like the analyzer assumes that, given

void foo(std::unique_ptr<int> i);

void bar() {
  auto x = std::make_unique<int>();
  int *i = x.get();
  foo(std::move(x));
  *i = 99;
}

...`i` is always freed after the call to `foo` completes, so the store to *i is
broken. However, if we change `foo` to take a `std::unique_ptr<int> &&`, the
analyzer assumes that it can't know what happened to `x` during the call, and
doesn't warn.

Since the unique_ptr passed to `foo` can be stashed away in a global, class
member, etc. I think the analyzer should be more conservative with code like
the above.

Test-case:

$ cat /tmp/sa-test.cpp
// Stripped down unique_ptr<int>
struct IntPtr {
  IntPtr(): i(new int) {}
  IntPtr(IntPtr &&o): i(o.i) { o.i = nullptr; }
  ~IntPtr() { delete i; }

  int *i;
};

struct Foo {
  Foo(IntPtr);
  void bar();

  IntPtr i;
};

void bar() {
  IntPtr ptr;
  int *i = ptr.i;
  Foo f(static_cast<IntPtr &&>(ptr));
  *i = 99;
  f.bar();
}

$ clang-tidy /tmp/sa-test.cpp -- -Xclang -analyzer-config -Xclang
'c++-temp-dtor-inlining=false' -std=c++11

$ clang-tidy /tmp/sa-test.cpp -- -std=c++11
1 warning generated.
/tmp/sa-test.cpp:20:6: warning: Use of memory after it is freed
[clang-analyzer-cplusplus.NewDelete]
  *i = 99;
     ^
/tmp/sa-test.cpp:17:10: note: Calling default constructor for 'IntPtr'
  IntPtr ptr;
         ^
/tmp/sa-test.cpp:2:15: note: Memory is allocated
  IntPtr(): i(new int) {}
              ^
/tmp/sa-test.cpp:17:10: note: Returning from default constructor for 'IntPtr'
  IntPtr ptr;
         ^
/tmp/sa-test.cpp:19:35: note: Calling '~IntPtr'
  Foo f(static_cast<IntPtr &&>(ptr));
                                  ^
/tmp/sa-test.cpp:4:15: note: Memory is released
  ~IntPtr() { delete i; }
              ^
/tmp/sa-test.cpp:19:35: note: Returning from '~IntPtr'
  Foo f(static_cast<IntPtr &&>(ptr));
                                  ^
/tmp/sa-test.cpp:20:6: note: Use of memory after it is freed
  *i = 99;
     ^</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>