泄漏和地址有什么区别?

What is the difference between leak and address?

我在我的项目中使用 -fsanitize=leak-fsanitize=address。我认为 leak 发现内存泄漏(不删除内存)并且 address 发现 wring 内存访问。但是 address 也说明了未删除的内存。那么,出于什么目的需要 -fsanitize=leak

为了找到内存泄漏,该工具需要查看您分配内存的所有位置,标记它们,跟踪它们何时被删除,并查看在程序结束时是否还有未删除的。

为了找到内存写入访问冲突,该工具需要(除其他事项外)查看您分配内存的所有位置、标记它们并跟踪它们何时被删除。这是必要的,因为它会使分配更大,这样它就可以在它们周围设置警卫以检测您何时进行疯狂写入。

因此,基本上 90% 的跟踪内存泄漏所需的信息都可用于解决消毒程序。所以它也可以跟踪那些。

您不使用地址清理程序来查找内存泄漏的原因是它会执行 whole lot of other stuff.

说明

地址清理程序会做一些额外的事情,比如检查你是否正在写入越界的内存。泄漏消毒剂只是检查您是否忘记释放内存。

文档

您可以在 gcc program instrumentation options 页面上阅读这些内容。

-fsanitize=address

启用 AddressSanitizer,一种快速内存错误检测器。内存访问指令用于检测越界和释放后使用错误。该选项启用 -fsanitize-address-use-after-scope。有关受支持选项的列表,请参阅 https://github.com/google/sanitizers/wiki/AddressSanitizer for more details. The run-time behavior can be influenced using the ASAN_OPTIONS environment variable. When set to help=1, the available options are shown at startup of the instrumented program. See 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

可以在 code gen options page.

上找到文档

此选项控制堆栈 space 重用用户声明的 local/auto 变量和编译器生成的临时变量。 reuse_level 可以是“全部”、“named_vars”或“none”。 “all”为所有局部变量和临时变量启用堆栈重用,“named_vars”仅启用用户定义的具有名称的局部变量的重用,“none”完全禁用堆栈重用。默认值为“全部”。当程序延长作用域局部变量的生命周期或编译器生成的临时变量超出语言定义的端点时,需要该选项。当一个变量的生命周期结束时,如果该变量存在于内存中,优化编译器可以自由地将其堆栈 space 与其他临时变量或范围不与其重叠的局部变量重用。延长本地生命周期的遗留代码可能会破坏堆栈重用优化。

例如,

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++ 标准明确定义了编译器生成的临时文件的生命周期。当临时文件的生命周期结束时,如果临时文件存在于内存中,则优化编译器可以自由地将其堆栈 space 与其他临时文件或生存范围不与其重叠的局部变量重用。然而,一些遗留代码依赖于旧编译器的行为,其中临时堆栈 space 未被重用,激进的堆栈重用会导致 运行 时间错误。此选项用于控制临时堆栈重用优化。

LeakSanitizer is a memory leak detector which is integrated into AddressSanitizer.

If you just need leak detection, and don't want to bear the ASan slowdown, you can build with -fsanitize=leak instead of -fsanitize=address. This will link your program against a runtime library containing just the bare necessities required for LeakSanitizer to work. No compile-time instrumentation will be applied.

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 seams 通过 LSAN_OPTION 使不同的选项可用,如果你 运行 --sanitze=address,则这些选项不可用或被忽略。这就是我通过 运行nit help=1 找到的环境变量之一。

使用 --sanitize=leak,address (--sanitize=address,leak) 启用两者都没有效果。泄漏选项本身仍然被 LSAN_OPTIONS=help=1 忽略,但打印 ASAN_OPTIONS --> 它确实是因为地址包含泄漏(大部分或全部)。