首页 > 其他分享 >转载:asan 使用

转载:asan 使用

时间:2023-03-27 23:24:29浏览次数:44  
标签:00 main memory fa fd 使用 asan 转载

https://blog.csdn.net/u013171226/article/details/126876335

https://www.osc.edu/resources/getting_started/howto/howto_use_address_sanitizer

1. make cflags

static: gcc test.c -o test -fsanitize=address -static-libasan -g

dynamic: gcc test.c -o test -fsanitizer=address -lasan -g

2.asan env

export ASAN_OPTIONS=halt_on_error=false:print_scariness=true:fast_unwind_on_malloc=true:detect_leak=1

ASAN_OPTIONS是Address-Sanitizier的运行选项环境变量。

# halt_on_error=0:检测内存错误后继续运行

# detect_leaks=1:使能内存泄露检测

# malloc_context_size=15:内存错误发生时,显示的调用栈层数为15

# log_path=/home/xos/asan.log:内存检查问题日志存放文件路径

# suppressions=$SUPP_FILE:屏蔽打印某些内存错误

除了上述常用选项,以下还有一些选项可根据实际需要添加:

# detect_stack_use_after_return=1:检查访问指向已被释放的栈空间

# handle_segv=1:处理段错误;也可以添加handle_sigill=1处理SIGILL信号

# quarantine_size=4194304:内存cache可缓存free内存大小4M
3. asan runtime does not com first initial library list

export LD_PRELOAD=/usr/lib/basan.so

 

Address Sanitizer is a tool developed by Google detect memory access error such as use-after-free and memory leaks. It is built into GCC versions >= 4.8 and can be used on both C and C++ codes. Address Sanitizer uses runtime instrumentation to track memory allocations, which mean you must build your code with Address Sanitizer to take advantage of it's features.

There is extensive documentation on the AddressSanitizer Github Wiki.

Memory leaks can increase the total memory used by your program. It's important to properly free memory when it's no longer required. For small programs, loosing a few bytes here and there may not seem like a big deal. However, for long running programs that use gigabytes of memory, avoiding memory leaks becomes increasingly vital. If your program fails to free the memory it uses when it no longer needs it, it can run out of memory, resulting in early termination of the application. AddressSanitizer can help detect these memory leaks.

Additionally, AddressSanitizer can detect use-after-free bugs. A use-after-free bug occurs when a program tries to read or write to memory that has already been freed. This is undefined behavior and can lead to corrupted data, incorrect results, and even program crashes.

Building With Address Sanitzer

We need to use gcc to build our code, so we'll load the gcc module:

1 module load gnu/9.1.0

The "-fsanitize=address" flag is used to tell the compiler to add AddressSanitizer.

Additionally, due to some environmental configuration settings on OSC systems, we must also statically link against Asan. This is done using the "-static-libasan" flag.

It's helpful to compile the code with debug symbols. AddressSanitizer will print line numbers if debug symbols are present. To do this, add the "-g" flag. Additionally, the "-fno-omit-frame-pointer" flag may be helpful if you find that your stack traces do not look quite correct.

In one command, this looks like:

1 gcc main.c -o main -fsanitize=address -static-libasan -g

Or, splitting into separate compiling and linking stages:

1 2 gcc -c main.c -fsanitize=address -g gcc main.o -o main -fsanitize=address -static-libasan

Notice that both the compilation and linking steps require the "-fsanitize-address" flag, but only the linking step requires "-static-libasan". If your build system is more complex, it might make sense to put these flags in CFLAGS and LDFLAGS environment variables.

And that's it!

Examples

No Leak

First, let's look at a program that has no memory leaks (noleak.c):

1 2 3 4 5 6 7 8 9 10 11 #include <stdio.h> #include <stdlib.h> #include <string.h>   int main(int argc, const char *argv[]) {     char *s = malloc(100);     strcpy(s, "Hello world!");     printf("string is: %s\n", s);     free(s);     return 0;  }

To build this we run:

1 gcc noleak.c -o noleak -fsanitize=address -static-libasan -g

And, the output we get after running it:

1 string is: Hello world!

That looks correct! Since there are no memory leaks in this program, AddressSanitizer did not print anything. But, what happens if there are leaks?

Missing free

Let's look at the above program again, but this time, remove the free call (leak.c):

1 2 3 4 5 6 7 8 9 10 #include <stdio.h> #include <stdlib.h> #include <string.h>   int main(int argc, const char *argv[]) {     char *s = malloc(100);     strcpy(s, "Hello world!");     printf("string is: %s\n", s);     return 0; }

Then, to build:

1 gcc leak.c -o leak -fsanitize=address -static-libasan

And the output:

1 2 3 4 5 6 7 8 9 10 11 string is: Hello world!   ================================================================= ==235624==ERROR: LeakSanitizer: detected memory leaks   Direct leak of 100 byte(s) in 1 object(s) allocated from:     #0 0x4eaaa8 in __interceptor_malloc ../../.././libsanitizer/asan/asan_malloc_linux.cc:144     #1 0x5283dd in main /users/PZS0710/edanish/test/asan/leak.c:6     #2 0x2b0c29909544 in __libc_start_main (/lib64/libc.so.6+0x22544)   SUMMARY: AddressSanitizer: 100 byte(s) leaked in 1 allocation(s).

This is a leak report from AddressSanitizer. It detected that 100 bytes were allocated, but never freed. Looking at the stack trace that it provides, we can see that the memory was allocated on line 6 in leak.c

Use After Free

Say we found the above leak in our code, and we wanted to fix it. We need to add a call to free. But, what if we add it in the wrong spot?

1 2 3 4 5 6 7 8 9 10 11 #include <stdio.h> #include <stdlib.h> #include <string.h>   int main(int argc, const char *argv[]) {     char *s = malloc(100);     free(s);     strcpy(s, "Hello world!");     printf("string is: %s\n", s);     return 0; }

The above (uaf.c) is clearly wrong. Albiet a contrived example, the allocated memory, pointed to by "s", was written to and read from after it was freed.

To Build:

1 gcc uaf.c -o uaf -fsanitize=address -static-libasan

Building it and running it, we get the following report from AddressSanitizer:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 ================================================================= ==244157==ERROR: AddressSanitizer: heap-use-after-free on address 0x60b0000000f0 at pc 0x00000047a560 bp 0x7ffcdf0d59f0 sp 0x7ffcdf0d51a0 WRITE of size 13 at 0x60b0000000f0 thread T0     #0 0x47a55f in __interceptor_memcpy ../../.././libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:790     #1 0x528403 in main /users/PZS0710/edanish/test/asan/uaf.c:8     #2 0x2b47dd204544 in __libc_start_main (/lib64/libc.so.6+0x22544)     #3 0x405f5c  (/users/PZS0710/edanish/test/asan/uaf+0x405f5c)   0x60b0000000f0 is located 0 bytes inside of 100-byte region [0x60b0000000f0,0x60b000000154) freed by thread T0 here:     #0 0x4ea6f7 in __interceptor_free ../../.././libsanitizer/asan/asan_malloc_linux.cc:122     #1 0x5283ed in main /users/PZS0710/edanish/test/asan/uaf.c:7     #2 0x2b47dd204544 in __libc_start_main (/lib64/libc.so.6+0x22544)   previously allocated by thread T0 here:     #0 0x4eaaa8 in __interceptor_malloc ../../.././libsanitizer/asan/asan_malloc_linux.cc:144     #1 0x5283dd in main /users/PZS0710/edanish/test/asan/uaf.c:6     #2 0x2b47dd204544 in __libc_start_main (/lib64/libc.so.6+0x22544)   SUMMARY: AddressSanitizer: heap-use-after-free ../../.././libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:790 in __interceptor_memcpy Shadow bytes around the buggy address:   0x0c167fff7fc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   0x0c167fff7fd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   0x0c167fff7fe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   0x0c167fff7ff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   0x0c167fff8000: fa fa fa fa fa fa fa fa fd fd fd fd fd fd fd fd =>0x0c167fff8010: fd fd fd fd fd fa fa fa fa fa fa fa fa fa[fd]fd   0x0c167fff8020: fd fd fd fd fd fd fd fd fd fd fd fa fa fa fa fa   0x0c167fff8030: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa   0x0c167fff8040: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa   0x0c167fff8050: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa   0x0c167fff8060: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa Shadow byte legend (one shadow byte represents 8 application bytes):   Addressable:           00   Partially addressable: 01 02 03 04 05 06 07    Heap left redzone:       fa   Freed heap region:       fd   Stack left redzone:      f1   Stack mid redzone:       f2   Stack right redzone:     f3   Stack after return:      f5   Stack use after scope:   f8   Global redzone:          f9   Global init order:       f6   Poisoned by user:        f7   Container overflow:      fc   Array cookie:            ac   Intra object redzone:    bb   ASan internal:           fe   Left alloca redzone:     ca   Right alloca redzone:    cb   Shadow gap:              cc ==244157==ABORTING

This is a bit intimidating. It looks like there's alot going on here, but it's not as bad as it looks. Starting at the top, we see what AddressSanitizer detected. In this case, a "WRITE" of 13 bytes (from our strcpy). Immediately below that, we get a stack trace of where the write occured. This tells us that the write occured on line 8 in uaf.c in the function called "main".

Next, AddressSanitizer reports where the memory was located. We can ignore this for now, but depending on your use case, it could be helpful information.

Two key pieces of information follow. AddressSanitizer tells us where the memory was freed (the "freed by thread T0 here" section), giving us another stack trace indicating the memory was freed on line 7. Then, it reports where it was originally allocated ("previously allocated by thread T0 here:"), line 6 in uaf.c.

This is likely enough information to start to debug the issue. The rest of the report provides details about how the memory is laid out, and exactly which addresses were accessed/written to. You probably won't need to pay too much attention to this section. It's a bit "down in the weeds" for most use cases.

Heap Overflow

AddresssSanitizer can also detect heap overflows. Consider the following code (overflow.c):

1 2 3 4 5 6 7 8 9 10 11 12 #include <stdio.h> #include <stdlib.h> #include <string.h> int main(int argc, const char *argv[]) {     // whoops, forgot c strings are null-terminated     // and not enough memory was allocated for the copy     char *s = malloc(12);     strcpy(s, "Hello world!");     printf("string is: %s\n", s);     free(s);     return 0; }

The "Hello world!" string is 13 characters long including the null terminator, but we've only allocated 12 bytes, so the strcpy above will overflow the buffer that was allocated. To build this:

1 gcc overflow.c -o overflow -fsanitize=address -static-libasan -g -Wall

Then, running it, we get the following report from AddressSanitizer:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 ==168232==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x60200000003c at pc 0x000000423454 bp 0x7ffdd58700e0 sp 0x7ffdd586f890 WRITE of size 13 at 0x60200000003c thread T0     #0 0x423453 in __interceptor_memcpy /apps_src/gnu/8.4.0/src/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:737     #1 0x5097c9 in main /users/PZS0710/edanish/test/asan/overflow.c:8     #2 0x2ad93cbd7544 in __libc_start_main (/lib64/libc.so.6+0x22544)     #3 0x405d7b  (/users/PZS0710/edanish/test/asan/overflow+0x405d7b)   0x60200000003c is located 0 bytes to the right of 12-byte region [0x602000000030,0x60200000003c) allocated by thread T0 here:     #0 0x4cd5d0 in __interceptor_malloc /apps_src/gnu/8.4.0/src/libsanitizer/asan/asan_malloc_linux.cc:86     #1 0x5097af in main /users/PZS0710/edanish/test/asan/overflow.c:7     #2 0x2ad93cbd7544 in __libc_start_main (/lib64/libc.so.6+0x22544)   SUMMARY: AddressSanitizer: heap-buffer-overflow /apps_src/gnu/8.4.0/src/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:737 in __interceptor_memcpy Shadow bytes around the buggy address:   0x0c047fff7fb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   0x0c047fff7fc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   0x0c047fff7fd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   0x0c047fff7fe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   0x0c047fff7ff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 =>0x0c047fff8000: fa fa 00 fa fa fa 00[04]fa fa fa fa fa fa fa fa   0x0c047fff8010: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa   0x0c047fff8020: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa   0x0c047fff8030: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa   0x0c047fff8040: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa   0x0c047fff8050: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa Shadow byte legend (one shadow byte represents 8 application bytes):   Addressable:           00   Partially addressable: 01 02 03 04 05 06 07    Heap left redzone:       fa   Freed heap region:       fd   Stack left redzone:      f1   Stack mid redzone:       f2   Stack right redzone:     f3   Stack after return:      f5   Stack use after scope:   f8   Global redzone:          f9   Global init order:       f6   Poisoned by user:        f7   Container overflow:      fc   Array cookie:            ac   Intra object redzone:    bb   ASan internal:           fe   Left alloca redzone:     ca   Right alloca redzone:    cb ==168232==ABORTING

This is similar to the use-after-free report we looked at above. It tells us that a heap buffer overflow occured, then goes on to report where the write happened and where the memory was originally allocated. Again, the rest of this report describes the layout of the heap, and probably isn't too important for your use case.

C++ Delete Mismatch

AddressSanitizer can be used on C++ codes as well. Consider the following (bad_delete.cxx):

1 2 3 4 5 6 7 8 9 10 11 #include <iostream> #include <cstring>   int main(int argc, const char *argv[]) {     char *cstr = new char[100];     strcpy(cstr, "Hello World");     std::cout << cstr << std::endl;       delete cstr;     return 0; }

What's the problem here? The memory pointed to by "cstr" was allocated with new[]. An array allocation must be deleted with the delete[] operator, not "delete".

To build this code, just use g++ instead of gcc:

1 g++ bad_delete.cxx -o bad_delete -fsanitize=address -static-libasan -g

And running it, we get the following output:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 Hello World ================================================================= ==257438==ERROR: AddressSanitizer: alloc-dealloc-mismatch (operator new [] vs operator delete) on 0x60b000000040     #0 0x4d0a78 in operator delete(void*, unsigned long) /apps_src/gnu/8.4.0/src/libsanitizer/asan/asan_new_delete.cc:151     #1 0x509ea8 in main /users/PZS0710/edanish/test/asan/bad_delete.cxx:9     #2 0x2b8232878544 in __libc_start_main (/lib64/libc.so.6+0x22544)     #3 0x40642b  (/users/PZS0710/edanish/test/asan/bad_delete+0x40642b)   0x60b000000040 is located 0 bytes inside of 100-byte region [0x60b000000040,0x60b0000000a4) allocated by thread T0 here:     #0 0x4cf840 in operator new[](unsigned long) /apps_src/gnu/8.4.0/src/libsanitizer/asan/asan_new_delete.cc:93     #1 0x509e5f in main /users/PZS0710/edanish/test/asan/bad_delete.cxx:5     #2 0x2b8232878544 in __libc_start_main (/lib64/libc.so.6+0x22544)   SUMMARY: AddressSanitizer: alloc-dealloc-mismatch /apps_src/gnu/8.4.0/src/libsanitizer/asan/asan_new_delete.cc:151 in operator delete(void*, unsigned long) ==257438==HINT: if you don't care about these errors you may set ASAN_OPTIONS=alloc_dealloc_mismatch=0 ==257438==ABORTING

This is similar to the other AddressSanitizer outputs we've looked at. This time, it tells us there's a mismatch between new and delete. It prints a stack trace for where the delete occured (line 9) and also a stack trace for where to allocation occured (line 5).

Performance

The documentation states:

This tool is very fast. The average slowdown of the instrumented program is ~2x

AddressSanitizer is much faster than tools that do similar analysis such as valgrind. This allows for usage on HPC codes.

However, if you find that AddressSanitizer is too slow for your code, there are compiler flags that can be used to disable it for specific functions. This way, you can use address sanitizer on cooler parts of your code, while manually auditing the hot paths.

The compiler directive to skip analyzing functions is:

1 __attribute__((no_sanitize_address)

标签:00,main,memory,fa,fd,使用,asan,转载
From: https://www.cnblogs.com/fellow1988/p/17263427.html

相关文章

  • Spring中使用JdbcTemplate操作数据库
    JDBC是Java提供的一种用于执行SQL语句的API,可以对多种关系型数据库(例如MySQL、Oracle等)进行访问。但在实际的企业级应用开发中,却很少有人直接使用原生的JDBCAPI......
  • django使用后台admin修改/删除记录的同时更新文件
    问题使用django自带admin后台删除表的时候,因为文件是存在服务器的,所以是只是删除了数据库的数据,而服务器的文件还存在解决models.py#模型类class......
  • 支付回调MQ消息的幂等处理及MD5字符串es中的使用及支付宝预授权完成
    支付回调MQ消息的幂等处理及MD5字符串es中的使用及支付宝预授权完成1.幂等的处理,根据对象的转json转md5作为key,退款的处理控制发送端?业务上比较难控制。支付异步通知,......
  • 入职第一天 Maven使用
     2012年11月26日,我入职了,虽然内心还是有点不舍得杭州X软的offer,但或许我是懂得感恩的人!我也是一个相信缘分的,这天我入职了,兴奋中带有不安,我甚至不知道叫前辈是名字好呢,还......
  • Spinner(列表选项框)的基本使用
    这一节是想给大家介绍一个Gallery(画廊)的一个控件,尽管我们可以不通过兼容使用Gallery,不过想想还是算了,因为Gallery在每次切换图片的时候,都需要重新创建视图,这样无疑会造成......
  • django中celery的使用
    创建django项目$django-adminstartprojectproj$cdproj$tree.├──manage.py└──proj├──__init__.py├──asgi.py├──settings.......
  • #创作者激励#使用OpenHarmonyNDK移植三方库Speexdsp
    【本文正在参加2023年第一期优质创作者激励计划】大家好,我是一名即将本科毕业的OpenHarmony开发者,去年暑假利用了两个月时间移植了一个语音处理的三方库Speexdsp到OpenHar......
  • java 并发库 Future 和 Collable的使用
    packageendual;importjava.util.concurrent.Callable;importjava.util.concurrent.ExecutionException;importjava.util.concurrent.ExecutorService;importjava.......
  • java wait() notyfy()的使用
    我们知道,并发的编程在企业中用的很多,对于并发的学习是很重要的。现在我们想从程序上给大家一个分析,在我写这个程序的时候,只知道wait()是线程等待,notify是唤醒线程,还有一个no......
  • Winform/Csharp中使用定时器+分页算法实现DataGridView自动分页显示(模拟大屏切换效果
    场景Winform中DataGridView设置前景色、单元格背景色、标题栏样式、禁止改变高宽、不显示空白行、清除选中样式、填充数据源、设置标题、设置单列宽度:https://blog.csdn.......