泄漏和地址之间有什么区别



我在项目中使用-fsanitize=leak-fsanitize=address。我以为leak会发现内存泄漏(不删除内存),address会发现wrw内存访问。但地址也表示没有删除内存。那么,-fsanitize=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-支持选项列表的时间标志。该选项不能与-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++标准很好地定义的。当临时代码的生存期结束时,如果临时代码存在于内存中,优化编译器可以自由地将其堆栈空间与其他临时代码或其生存期不重叠的作用域局部变量一起重用。然而,一些遗留代码依赖于旧编译器的行为,在旧编译器中,临时代码的堆栈空间不被重用,激进的堆栈重用可能导致运行时错误。此选项用于控制临时堆栈重用优化。

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

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

因此,基本上跟踪内存泄漏所需的90%的信息都可以用于寻址消毒剂。所以它也可以跟踪这些。

你之所以不使用地址清理程序来查找内存泄漏,是因为它做了很多其他事情。

LeakSanitizer是一个内存泄漏检测器,集成到AddressSanitizer中

如果您只需要泄漏检测,并且不想承受ASan的速度减慢,您可以使用-fsanitize=leak而不是-fsanitise=address进行构建。这将把你的程序与运行库链接起来,运行库只包含LeakSanitizer工作所需的基本必需品。不会应用编译时检测。

ASAN_OPTIONS=detect_leaks=1 clang/gcc-fsanitize=地址-g

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

或与llvm:相同

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

但是:使用--sanitize=泄漏接缝运行,使不同的选项可通过LSAN_OPTION使用,如果运行--sanitize=address,则这些选项不可使用或被忽略。这就是我对其中一个环境变量运行help=1的结果。

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

最新更新