Clang 分析器潜在内存泄漏 - 误报
Clang analyzer potential memory leak - false positive
我的代码库中有一个静态函数的实现,在它上运行clang-tidy
时,我注意到静态分析器指向可能的内存泄漏,当我非常确定代码是正确的时。(我已经用消毒剂验证过(。我认为这很可能是由于静态分析器缺少某些分支语句,但我不是 100% 确定。
这是代码的精简版本:
#include <array>
#include <functional>
#include <utility>
struct SmallFunction {
struct Base {
virtual ~Base() = default;
virtual void destroy() = 0;
};
template <typename T>
struct Inner : Base {
Inner(T&& f) : f_(std::move(f)) {}
void destroy() override { f_.~T(); }
T f_;
};
template <typename T>
SmallFunction(T&& f) : empty(false) {
static_assert(sizeof(T) <= 32);
new (storage) Inner<T>(std::forward<T>(f));
}
~SmallFunction() {
if (!empty) {
reinterpret_cast<Base*>(storage)->destroy();
}
}
bool empty = true;
alignas(8) char storage[40]; // 32 + 8
};
int main() {
std::array<char, 64> large;
auto lambda = [large] {};
std::function<void()> f = lambda;
SmallFunction sf = std::move(f);
}
这是叮叮当当的分析:
/home/ce/example.cpp:39:1: warning: Potential memory leak [clang-analyzer-cplusplus.NewDeleteLeaks]
}
^
/home/ce/example.cpp:37:29: note: Calling constructor for 'function<void ()>'
std::function<void()> f = lambda;
^
/opt/compiler-explorer/gcc-9.2.0/lib/gcc/x86_64-linux-gnu/9.2.0/../../../../include/c++/9.2.0/bits/std_function.h:675:2: note: Taking true branch
if (_My_handler::_M_not_empty_function(__f))
^
/opt/compiler-explorer/gcc-9.2.0/lib/gcc/x86_64-linux-gnu/9.2.0/../../../../include/c++/9.2.0/bits/std_function.h:677:6: note: Calling '_Base_manager::_M_init_functor'
_My_handler::_M_init_functor(_M_functor, std::move(__f));
^
/opt/compiler-explorer/gcc-9.2.0/lib/gcc/x86_64-linux-gnu/9.2.0/../../../../include/c++/9.2.0/bits/std_function.h:223:4: note: Calling '_Base_manager::_M_init_functor'
{ _M_init_functor(__functor, std::move(__f), _Local_storage()); }
^
/opt/compiler-explorer/gcc-9.2.0/lib/gcc/x86_64-linux-gnu/9.2.0/../../../../include/c++/9.2.0/bits/std_function.h:252:39: note: Memory is allocated
{ __functor._M_access<_Functor*>() = new _Functor(std::move(__f)); }
^
/opt/compiler-explorer/gcc-9.2.0/lib/gcc/x86_64-linux-gnu/9.2.0/../../../../include/c++/9.2.0/bits/std_function.h:223:4: note: Returned allocated memory
{ _M_init_functor(__functor, std::move(__f), _Local_storage()); }
^
/opt/compiler-explorer/gcc-9.2.0/lib/gcc/x86_64-linux-gnu/9.2.0/../../../../include/c++/9.2.0/bits/std_function.h:677:6: note: Returned allocated memory
_My_handler::_M_init_functor(_M_functor, std::move(__f));
^
/home/ce/example.cpp:37:29: note: Returning from constructor for 'function<void ()>'
std::function<void()> f = lambda;
^
/home/ce/example.cpp:39:1: note: Potential memory leak
}
^
1 warning generated.
这是启用了叮当整洁的神螺栓链接。
来自clang-tidy的报告肯定有点奇怪,可能需要一些澄清。
它对Inner<T>
的放置新感到不安,而没有看到匹配的显式析构函数调用。 您有这种奇怪的destroy()
方法,甚至没有必要,因为Base
析构函数是虚拟的,隐式Inner
析构函数将清理Inner::f_
。
这可以通过以下方式轻松解决:
- 将
bool SmallFunction::empty
替换为Base *SmallFunction::value
,并将放置 - new 的结果存储在其中。(这不是绝对必要的,但我发现代码流程更好,不需要reinterpret_cast
,而且由于编译器可以进行类型检查,因此更容易正确。 - 在
SmallFunction::~SmallFunction
中,将destroy
调用替换为value->~Base()
。 - 删除
destroy()
方法;它不是必需的。
这满足了叮当声整洁(见这里(。
我不认为有内存泄漏,但有一个对象(Inner<T>
(被构造并且从未被破坏。我看不到任何后果,但以正确的方式做事并没有什么坏处 - 无论如何,它使静态分析器的工作更容易。
相关文章:
- 并行块(线程清理器)之外的 OpenMP 中的争用条件;误报?
- 在映射中使用结构作为键,忽略 == 运算符,误报
- Clang 分析器潜在内存泄漏 - 误报
- 未定义的行为或误报
- C++ UBSAN 对派生对象产生误报
- 解释瓦尔格林德输出(可能的误报?
- 从特征匹配/单应性中过滤掉误报 – OpenCV
- Bloom过滤器误报
- 通过shared_ptr同步:线程清理器误报
- 多边形汤 - elipsoid碰撞误报(Kasper fauerby)
- 误报警告PVS Studio:V808类型的对象是创建但未使用的
- 误报警告 PVS 工作室:V821 性能降低。'rhs'变量可以在较低级别的范围内构造
- 禁用 Eclipse 的错误发现。(科丹误报)
- 如何避免 CFile查找文件扩展名超过三个字符的误报
- 用户泄漏、libc++泄漏或误报
- ThreadSanitizer说我的Atomic Inc / Dec有数据竞争,误报
- 在自定义异常中仍可访问(误报?
- Eclipse 索引器显示误报语义错误
- 使用clang的ThreadSanitizer和TBB避免误报
- 向量<unique_ptr>上is_copy_constructible的误报