发出 SIGINT 以停止循环时如何获取地址消毒器的输出

How get output of address sanitizer when emiting SIGINT to halt a loop

当我编译这个简单的测试程序时,我从 address sanitizer 得到了明显的泄漏报告,但是当我编译同一个程序但有一个无限循环,并中断它时,我没有得到任何报告 SIGINT输出。

检查 asm 输出,malloc 没有优化掉(如果可能的话)

这是地址清理程序的预期行为吗?我在其他开发中没有遇到这个问题。

工作示例:

#include <stdlib.h>
int main(void)
{
    char *a = malloc(1024);
    return 1;
}

不工作(用 SIGINT 杀死):

#include <stdlib.h>
int main(void)
{
    char *a = malloc(1024);
    for(;;);
    return 1;
}

编译:gcc test.c -o test -fsanitize=address

我在一个完整的程序中遇到了这个问题,但我将它简化为这个最小的例子。

负责打印该错误输出的代码称为析构函数 (fini) 过程。由于您的程序在未调用任何进程析构函数的情况下终止(由于 SIGINT),因此您不会得到任何错误打印输出。

我尝试了很多方法,使用 exit()abort() 调用,这个有效:

#include <stdlib.h>
#include <signal.h>
#include <stdio.h>
#include <setjmp.h>

jmp_buf jmpbuf;
void handler (int signum) {    
        printf("handler %d \n", signum);
        // we jump from here to main()
        // and then call return
        longjmp(jmpbuf, 1);
}

int main(int argc, char *argv[])
{
    if (setjmp(jmpbuf)) { 
        // we are in signal context here
        return 2;
    }
    signal(SIGINT, handler);
    signal(SIGTERM, handler);

    char *a = malloc(1024);
    while (argc - 1);
    return 1;
}

结果:

> gcc file.c -fsanitize=address && timeout 1 ./a.out arg
handler 15 

=================================================================
==12970==ERROR: LeakSanitizer: detected memory leaks

Direct leak of 1024 byte(s) in 1 object(s) allocated from:
    #0 0x7f4798c9bd99 in __interceptor_malloc /build/gcc/src/gcc/libsanitizer/asan/asan_malloc_linux.cc:86
    #1 0x5569e64e0acd in main (/tmp/a.out+0xacd)
    #2 0x7f479881206a in __libc_start_main (/usr/lib/libc.so.6+0x2306a)

SUMMARY: AddressSanitizer: 1024 byte(s) leaked in 1 allocation(s).

我猜地址清理函数是在 main returns 之后执行的。

__lsan_do_leak_check() 可以帮助您避免在@KamilCuk 的回答中使用 longjmp:

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <sanitizer/lsan_interface.h>

void handler (int signum) {
   __lsan_do_leak_check();
}

int main(int argc, char *argv[])
{
   signal(SIGINT, handler);
   char *a = malloc(1024);
   a=0;
   printf("lost pointer\n");
   for(;;);
   return 1;
}

演示:

clang test.c -fsanitize=address -fno-omit-frame-pointer -g -O0 -o test && ./test
lost pointer
  C-c C-c
=================================================================
==29365==ERROR: LeakSanitizer: detected memory leaks

Direct leak of 1024 byte(s) in 1 object(s) allocated from:
    #0 0x4c9ca3 in malloc (/home/bjacob/test+0x4c9ca3)
    #1 0x4f9187 in main /home/bjacob/test.c:13:14
    #2 0x7fbc9898409a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2409a)

SUMMARY: AddressSanitizer: 1024 byte(s) leaked in 1 allocation(s).

注意我添加了 a=0 来创建泄漏。

我还添加了一个printf。没有那个 printf,就不会打印泄漏错误。我怀疑编译器优化了变量“a”的使用,尽管我使用了 -O0 编译器选项。