发出 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 编译器选项。
当我编译这个简单的测试程序时,我从 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 编译器选项。