泄漏和地址有什么区别?

9

我在项目中使用了 -fsanitize=leak-fsanitize=address。 我原以为leak可以找到内存泄漏(未释放的内存),而address可以找到错误的内存访问。 但是address也会报告未删除的内存泄漏。那么,-fsanitize=leak 的作用是什么呢?

3个回答

10

解释

地址(Address)检测器会执行一些额外的操作,例如检查是否在写入越界内存。泄漏(Leak)检测器仅检查您是否忘记了释放内存。

文档

您可以在gcc 程序插桩选项页面阅读相关内容。

-fsanitize=address

启用AddressSanitizer,一种快速的内存错误检测工具。指令中添加仪表信息以检测越界和使用后释放的错误。该选项启用-fsanitize-address-use-after-scope。更多详细信息请参见https://github.com/google/sanitizers/wiki/AddressSanitizer。运行时行为可以使用ASAN_OPTIONS环境变量来影响。当设置为help=1时,在插桩程序启动时会显示可用选项。有关支持的选项列表,请参见https://github.com/google/sanitizers/wiki/AddressSanitizerFlags#run-time-flags。此选项不能与-fsanitize=thread组合使用。

-fsanitize=leak

启用LeakSanitizer,一种内存泄漏检测工具。此选项仅对可执行文件的链接有影响,并且该可执行文件链接到覆盖malloc和其他分配器函数的库。更多详细信息请参见https://github.com/google/sanitizers/wiki/AddressSanitizerLeakSanitizer。运行时行为可以使用LSAN_OPTIONS环境变量来影响。此选项不能与-fsanitize=thread组合使用。

-fsanitize-address-use-after-scope

启用本地变量的消毒以检测使用后范围错误。该选项将-fstack-reuse设置为none

-fstack-reuse=reuse-level

文档可以在代码生成选项页面中找到。

这个选项控制用户声明的本地/自动变量和编译器生成的临时变量的堆栈空间重用。reuse_level可以是'all'、'named_vars'或'none'。'all'启用所有本地变量和临时变量的堆栈重用,'named_vars'仅启用用户定义的具有名称的本地变量的重用,'none'完全禁用堆栈重用。默认值为“all”。当程序扩展了由语言定义的作用域局部变量或编译器生成的临时变量的生命周期时,需要该选项。当变量的生命周期结束,并且如果变量存在于内存中,则优化编译器可以自由地将其堆栈空间与其他临时变量或生命周期不重叠的作用域局部变量进行重用。延长局部生命周期的遗留代码可能会破坏堆栈重用优化。
例如:
int *p;
{
  int local1;

  p = &local1;
  local1 = 10;
  ....
}

{
  int local2;
  local2 = 20;
  ....
}

if (*p == 10) // out of scope use of local1
{

}

另一个例子:

struct A {
  A(int k) : i(k), j(k) { }
  int i;
  int j;
};

A *ap;

void foo(const A& ar) {
  ap = &ar;
}

void bar() {
  foo(A(10)); // temp object's lifetime ends when foo returns

  {
     A a(20);
     ....
  }

  ap->i += 10; // ap references out of scope temp whose space
               // is reused with a. What is the value of ap->i?
}

C++标准明确定义了编译器生成的临时对象的生命周期。当临时对象的生命周期结束,并且临时对象位于内存中时,优化编译器有权将其栈空间与其他生命周期不重叠的临时对象或局部变量的栈空间进行重用。然而,一些旧代码依赖于旧编译器的行为,这些编译器不会重新使用临时对象的栈空间,激进的栈重用可能导致运行时错误。此选项用于控制临时栈重用优化。


3
为了找到内存泄漏,工具需要查看所有分配内存的地方,标记它们,跟踪它们何时被删除,并查看程序结束时是否有任何未删除的内存。
为了找到内存写入访问违规,工具需要(除其他事项外)查看您分配内存的所有位置,标记它们并跟踪它们何时被删除。这是必要的,因为它将使分配变得更大,以便可以在其周围放置保护来检测您何时进行不受限制的写入。
因此,用于跟踪内存泄漏所需的信息基本上可用于地址消毒剂。因此,也可以跟踪这些信息。
您不使用地址消毒剂仅查找内存泄漏的原因是它执行了很多其他操作

2
LeakSanitizer是一个内存泄漏检测器,它被集成到AddressSanitizer中。
如果您只需要泄漏检测,并且不想承受ASan的减速,可以使用-fsanitize=leak而不是-fsanitize=address进行构建。这将链接您的程序到运行时库,其中仅包含LeakSanitizer工作所需的必要内容。不会应用任何编译时插装。
ASAN_OPTIONS=detect_leaks=1 clang/gcc -fsanitize=address -g

https://github.com/google/sanitizers/wiki/AddressSanitizerLeakSanitizer

或者同样来自 LLVM:

https://clang.llvm.org/docs/LeakSanitizer.html

但是使用--sanitize=leak运行似乎会使得通过LSAN_OPTION可用的不同选项,这些选项在运行--sanitize=address时不可用或被忽略。这是我通过将help=1运行到一个环境变量中发现的。
同时启用两者--sanitize=leak,address (--sanitize=address,leak)没有效果。Leak选项本身仍然被LSAN_OPTIONS=help=1忽略,但打印出ASAN_OPTIONS--->它似乎确实是因为address包括了leak(大部分或全部)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接