<table border="1" cellspacing="0" cellpadding="8">
<tr>
<th>Issue</th>
<td>
<a href=https://github.com/llvm/llvm-project/issues/58981>58981</a>
</td>
</tr>
<tr>
<th>Summary</th>
<td>
clang-analyzer: NewDelete potential leak in shared_ptr (false positive?)
</td>
</tr>
<tr>
<th>Labels</th>
<td>
new issue
</td>
</tr>
<tr>
<th>Assignees</th>
<td>
</td>
</tr>
<tr>
<th>Reporter</th>
<td>
syyyr
</td>
</tr>
</table>
<pre>
Hi,
I have this kind of program:
```cpp
#include <memory>
struct A;
struct PtrWrapper
{
std::shared_ptr<A> m_sp;
PtrWrapper(A* t)
: m_sp(t)
{
}
};
struct MyClass {
MyClass()
: m_ptr(nullptr)
{
}
MyClass at();
PtrWrapper m_ptr;
};
struct A {
MyClass at()
{
return MyClass();
}
};
MyClass MyClass::at()
{
return m_ptr.m_sp != nullptr ? m_ptr.m_sp->at() : MyClass();
}
```
Running this code through clang-tidy with the `clang-analyzer-cplusplus.NewDeleteLeaks` check produces this warning:
```
<source>:33:1: warning: Potential leak of memory pointed to by field '_M_pi' [clang-analyzer-cplusplus.NewDeleteLeaks]
}
^
<source>:32:9: note: '?' condition is true
return m_ptr.m_sp != nullptr ? m_ptr.m_sp->at() : MyClass();
^
<source>:32:33: note: Calling 'A::at'
return m_ptr.m_sp != nullptr ? m_ptr.m_sp->at() : MyClass();
^~~~~~~~~~~~~~~~
<source>:26:10: note: Calling default constructor for 'MyClass'
return MyClass();
^~~~~~~~~
<source>:16:5: note: Calling constructor for 'PtrWrapper'
: m_ptr(nullptr)
^~~~~~~~~~~~~~
<source>:9:7: note: Calling constructor for 'shared_ptr<A>'
: m_sp(t)
^~~~~~~
/opt/compiler-explorer/gcc-snapshot/lib/gcc/x86_64-linux-gnu/13.0.0/../../../../include/c++/13.0.0/bits/shared_ptr.h:214:25: note: Calling constructor for '__shared_ptr<A, __gnu_cxx::_S_atomic>'
shared_ptr(_Yp* __p) : __shared_ptr<_Tp>(__p) { }
^~~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-snapshot/lib/gcc/x86_64-linux-gnu/13.0.0/../../../../include/c++/13.0.0/bits/shared_ptr_base.h:1469:17: note: Calling constructor for '__shared_count<__gnu_cxx::_S_atomic>'
: _M_ptr(__p), _M_refcount(__p, typename is_array<_Tp>::type())
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-snapshot/lib/gcc/x86_64-linux-gnu/13.0.0/../../../../include/c++/13.0.0/bits/shared_ptr_base.h:928:4: note: Calling constructor for '__shared_count<__gnu_cxx::_S_atomic>'
: __shared_count(__p)
^~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-snapshot/lib/gcc/x86_64-linux-gnu/13.0.0/../../../../include/c++/13.0.0/bits/shared_ptr_base.h:917:16: note: Memory is allocated
_M_pi = new _Sp_counted_ptr<_Ptr, _Lp>(__p);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-snapshot/lib/gcc/x86_64-linux-gnu/13.0.0/../../../../include/c++/13.0.0/bits/shared_ptr_base.h:928:4: note: Returning from constructor for '__shared_count<__gnu_cxx::_S_atomic>'
: __shared_count(__p)
^~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-snapshot/lib/gcc/x86_64-linux-gnu/13.0.0/../../../../include/c++/13.0.0/bits/shared_ptr_base.h:1469:17: note: Returning from constructor for '__shared_count<__gnu_cxx::_S_atomic>'
: _M_ptr(__p), _M_refcount(__p, typename is_array<_Tp>::type())
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-snapshot/lib/gcc/x86_64-linux-gnu/13.0.0/../../../../include/c++/13.0.0/bits/shared_ptr.h:214:25: note: Returning from constructor for '__shared_ptr<A, __gnu_cxx::_S_atomic>'
shared_ptr(_Yp* __p) : __shared_ptr<_Tp>(__p) { }
^~~~~~~~~~~~~~~~~~~~~~
<source>:9:7: note: Returning from constructor for 'shared_ptr<A>'
: m_sp(t)
^~~~~~~
<source>:16:5: note: Returning from constructor for 'PtrWrapper'
: m_ptr(nullptr)
^~~~~~~~~~~~~~
<source>:26:10: note: Returning from default constructor for 'MyClass'
return MyClass();
^~~~~~~~~
<source>:32:33: note: Returned allocated memory
return m_ptr.m_sp != nullptr ? m_ptr.m_sp->at() : MyClass();
^~~~~~~~~~~~~~~~
<source>:33:1: note: Potential leak of memory pointed to by field '_M_pi'
}
^
1 warning generated.
```
Is this a false positive? If I change the ternary to an if/else statement, the warning disappears (the generated assembly doesnẗ change however).
I have reproduced this on the Compiler Explorer: https://godbolt.org/z/MqoTh9xd6
</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJztWd1vozgQ_2vIi5UofCTAQx7y0eoqbU-r3ZVO94QcMMFXx-Zs0zb719_YQEhS2rRV1WvvFhE3sfHMb748w3Qtst3sN-p4S2e8csbzK1TgW4J0QRW6oTxDIkelFBuJt44_r59xpuP6TsuymfF8ylNWZQQ5_nJLtkLuHP-iWbSj0rJKNZo7_uJo4quWf0hclkQ2T4fNOoJL6cxw9eeqwJJkSakl0IeJC7RNVLmn1e04IOdFgGuOtOPF3bq5gB6MloAXHS8fcXfCVYtpdcKqAX-9WzKs1PG2ZhJo93LeWim8iFeM2W9n2R8QRVg3dP1Fn9AN9T3Yx4DPeyF31PsRmUsSXUl-IqT_PK21bNrN1rTHPI_4NbysTCNjL-R4ruOvUKM70OflweoQ_KKlZlXdD7IDeDi2Pl3__FZxTvmmjoNUZCYipKg2BUoZ5puhptkO3VFdwDz4PISCncYcs91PIodpySplPqPfyd2KMKLJF4JvFDyJ0oKkNyaosiolqmZxh6Xh9zDEmp_-UolKpsQElT_3fRhcI2G3D30VmnBNMUMMOJm4reMQlYJyTTKkBVrvUE4Jy0CPYXKdlBD3IXImi-ein6xOVTi56EfowRAbWBxgmb_ACaxl-KWCZ1RTwREIDu5Ieh3sjY2Ojq8ncVv17oEvMWPGFQD6vPPY8F8A_dhlhAlfcvdJ7k2NT437JM9IjiumjeHq40NIlMMHtLDHHfYjPntavFCcPuSuQT7pA94D-DA_PIL53CH9auX3gTcxEj4T-4Mk-KQIj2S45-FvsvqlKGH3ZSq2JWVwMJD7kglpdHe5SdOh4rhUhTCPMLquJ2G8j6bJNBiCGNX9cMMrmHL90Xg0hi-j0cOhKR0MI8db2LvbsKYa_Oayk31UGG91AzM-1-pJcqI7b4mSBKAl6f19HdTJ9wRrsaVpn14PdntR8mdp6ookKdvoPSGf_Cgtkah9JFwcJ_MnrhfH8qeyXbLGilgDusHUuL77XN_fqzgVFddGyS8wn7XRdWs-axTrAdeJJHlNsJlfIr0rCcdbAskpwVLiXWdQy8isN-fYU2H1NqZ82_tTOEYMuvXnwbu5xTGBvXucGPb1tvwcSrdxaBPpXuvXdfUINRqoX6QYSsg-d7dlJLKlDrlDyfey1mR3GH41UQfB9uXoUDxTBLxf7HwO-zwMim-2sjJhkUux_RUb75up3kP7vxLWB_aPR6vQF3jG_6cYPfPOc15n7_7qc-4V8zzkj_am2fOCfyLEB3_P7-nN1AKQrCtRmqbXf60703X8WtFf2-57rIHntr1EtCGcSKPLUW8v8qppWWKUY6YI8FNU01tidHiVoyuUFphviG2MaiI5BkyABXNEczhCidmjNNDfEpPGlvbBlndGlQkZLBUy4QsrezQILEC2a7ZDmSCKOxeus5g7cdjyK8QduTXBFre4D_-hIUnTcM1q9IJbvssmp6CLNqeAagutS9uc9i5NNhHZWjA9EnIDv37C5_pv8aOI77NpzWFAZu50GgW-F0XxIJv5WezHeKCpZmR23Fk11PctVdDckQkpPzjajfgP9AuyDSrJZicAqS6q9QjSo8mA7Lb9MwSJ_yKpyYtUqYqYBDaJ4sgdFLOApIGbpV7oTUMycT038oPMT9NgmpP1xI8HDK_BUjNnAmnQM5W9JQHfnclqQGfe2PNc1w1c3w-CeDTOg3wcBhHxgzAdx7kTjMkWUzYyOIzmBnJmIa2rjYJFRpVW3SJYlm44IZYd0MeVLoScqd1uJweW8cwC_wczyVv8">