以下针对C++中常见的内存问题,使用Address Sanitizer和Valgrind进行调试
Linux环境 CentOS 7.9
Valgrind安装
1
2
|
yum install valgrind
valgrind --version
|
ASAN安装
Valgrind的使用
valgrind是一套工具集,最常用的工具是memcheck
先编译,带-g
,然后运行
valgrind [选项] 可执行程序 [程序参数]
,比如valgrind --leak-check=yes ./your_program
常用的选项有
- –leak-check=yes:启用内存泄漏检测
- –leak-check=full:显示更详细的内存泄漏信息
- –show-leak-kinds=all:显示所有类型的内存泄漏
- –track-origins=yes:跟踪未初始化内存的来源
- –vgdb=yes:启用调试模式,可配合 gdb 使用
假设C代码为
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
#include <stdlib.h>
// 有内存泄漏的函数
void leak_memory() {
int *ptr = malloc(10 * sizeof(int)); // 分配内存但未释放
ptr[0] = 42; // 使用内存
// 没有free(ptr),导致内存泄漏
}
// 正常的内存分配和释放
void normal_memory() {
int *ptr = malloc(5 * sizeof(int));
if (ptr != NULL) {
ptr[0] = 100;
free(ptr); // 正确释放内存
}
}
int main() {
leak_memory();
normal_memory();
return 0;
}
|
编译它 gcc test.c -o test -g
,运行valgrind --leak-check=full ./test
(注意此处不能写test,要写./test,让它实际运行起来)
输出的结果为
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
==5322== Memcheck, a memory error detector
==5322== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==5322== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info
==5322== Command: ./test
==5322==
==5322==
==5322== HEAP SUMMARY:
==5322== in use at exit: 40 bytes in 1 blocks
==5322== total heap usage: 2 allocs, 1 frees, 60 bytes allocated
==5322==
==5322== 40 bytes in 1 blocks are definitely lost in loss record 1 of 1
==5322== at 0x4C29F73: malloc (vg_replace_malloc.c:309)
==5322== by 0x40058E: leak_memory (test.c:5)
==5322== by 0x4005E1: main (test.c:20)
==5322==
==5322== LEAK SUMMARY:
==5322== definitely lost: 40 bytes in 1 blocks
==5322== indirectly lost: 0 bytes in 0 blocks
==5322== possibly lost: 0 bytes in 0 blocks
==5322== still reachable: 0 bytes in 0 blocks
==5322== suppressed: 0 bytes in 0 blocks
==5322==
==5322== For lists of detected and suppressed errors, rerun with: -s
==5322== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
|
信息解读
- HEAP SUMMARY:显示堆内存使用概况,这里显示有 40 字节未释放,总共分配2次,一共分配60字节
- definitely lost:确定的内存泄漏,40 字节,位于leak_memory函数的第 5 行
- LEAK SUMMARY:汇总各类内存泄漏情况
内存泄露类型
- definitely lost:确定的内存泄漏,必须修复
- indirectly lost:间接泄漏,通常是由于指向它的指针被泄漏导致
- possibly lost:可能的泄漏,需要进一步检查
- still reachable:仍然可访问的内存,通常不需要修复
当修复上述代码后,使用Valgrind检测结果为
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
==5428== Memcheck, a memory error detector
==5428== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==5428== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info
==5428== Command: ./test
==5428==
==5428==
==5428== HEAP SUMMARY:
==5428== in use at exit: 0 bytes in 0 blocks
==5428== total heap usage: 2 allocs, 2 frees, 60 bytes allocated
==5428==
==5428== All heap blocks were freed -- no leaks are possible
==5428==
==5428== For lists of detected and suppressed errors, rerun with: -s
==5428== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
|
ASAN的使用
注意ASAN在检测不到内存问题时,无输出
在编译时添加flag
1
2
3
4
|
# GCC或Clang通用
-fsanitize=address # 启用AddressSanitizer
-g # 保留调试信息(用于定位错误位置)
-fno-omit-frame-pointer # 优化栈跟踪显示(可选,推荐添加)
|
比如
1
2
|
# 编译多个文件(链接时也需要添加ASan标志)
g++ -fsanitize=address -g -fno-omit-frame-pointer -o app file1.cpp file2.cpp
|
然后直接运行可执行文件即可
比如有如下C代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
#include <stdlib.h>
// 有内存泄漏的函数
void leak_memory() {
int *ptr = malloc(10 * sizeof(int)); // 分配内存但未释放
ptr[0] = 42; // 使用内存
// 没有free(ptr),导致内存泄漏
}
// 正常的内存分配和释放
void normal_memory() {
int *ptr = malloc(5 * sizeof(int));
if (ptr != NULL) {
ptr[0] = 100;
free(ptr); // 正确释放内存
}
}
int main() {
leak_memory();
normal_memory();
return 0;
}
|
编译并执行它 gcc -fsanitize=address -g -fno-omit-frame-pointer -o test test.c && ./test
ASAN无法检测出错误
比如如下代码
1
2
3
4
5
6
7
8
9
10
11
|
#include <stdlib.h>
int main() {
int *ptr = (int*)malloc(4);
int *pp = (int*)malloc(4);
free(ptr);
free(pp);
*ptr = 10;
*pp = 20;
return 0;
}
|
因为asan在检测到内存泄漏后就会停止,如果要检测出所有的内存错误,可以通过设置 ASAN_OPTIONS 环境变量中的 halt_on_error=0 选项实现
export ASAN_OPTIONS="halt_on_error=0:detect_leaks=1"
但是程序一旦遇到内存错误,就是不稳定的,后续检测出的内存错误可能是之前引起的,所以一般只检测最先出现的内存错误
执行./test,输出
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
|
=================================================================
==7806== ERROR: AddressSanitizer: heap-use-after-free on address 0x60040000dff0 at pc 0x400770 bp 0x7fff72479600 sp 0x7fff724795f0
WRITE of size 4 at 0x60040000dff0 thread T0
#0 0x40076f (/root/test+0x40076f)
#1 0x7f6356c2c554 (/usr/lib64/libc-2.17.so+0x22554)
#2 0x400638 (/root/test+0x400638)
0x60040000dff0 is located 0 bytes inside of 4-byte region [0x60040000dff0,0x60040000dff4)
freed by thread T0 here:
#0 0x7f6356fedff9 (/usr/lib64/libasan.so.0.0.0+0x15ff9)
#1 0x40072c (/root/test+0x40072c)
#2 0x7f6356c2c554 (/usr/lib64/libc-2.17.so+0x22554)
previously allocated by thread T0 here:
#0 0x7f6356fee119 (/usr/lib64/libasan.so.0.0.0+0x16119)
#1 0x40070e (/root/test+0x40070e)
#2 0x7f6356c2c554 (/usr/lib64/libc-2.17.so+0x22554)
Shadow bytes around the buggy address:
0x0c00ffff9ba0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c00ffff9bb0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c00ffff9bc0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c00ffff9bd0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c00ffff9be0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
=>0x0c00ffff9bf0: fa fa fa fa fa fa fa fa fa fa fd fa fa fa[fd]fa
0x0c00ffff9c00: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c00ffff9c10: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c00ffff9c20: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c00ffff9c30: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c00ffff9c40: 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
Heap righ redzone: fb
Freed Heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack partial redzone: f4
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
ASan internal: fe
==7806== ABORTING
|
其中heap-use-after-free
,表明内存错误类型
WRITE of size 4 at 0x60040000dff0
表示写4字节
freed by thread T0 here
表示在此处被释放
previously allocated by thread T0 here
表示在此处分配内存
at pc 0x400770
表示在此地址产生错误
通过addr2line -e test 0x400770
可以查看地址对应的代码位置,输出为
1
2
|
root@iZbp1cqyppyocyfsztmoftZ:~$ addr2line -e test 0x400770
/root/test.c:8
|
两者对比
特性 |
ASan |
Valgrind (memcheck) |
速度 |
快(2-3 倍慢于原始程序) |
慢(10-50 倍慢于原始程序) |
内存开销 |
大(2-3 倍内存使用) |
更大(5-10 倍内存使用) |
检测范围 |
支持更多内存错误(如溢出) |
支持内存泄漏和部分错误 |
使用方式 |
编译时插入检测代码 |
运行时拦截内存操作 |
适合场景 |
开发阶段快速检测 |
发布前全面检测 |
内存泄露
1
2
3
4
5
|
void func() {
int* p = new int[100]; // 堆上分配100个int的数组
p[0] = 10; // 使用内存
// 错误:未执行delete[] p; 函数结束后p销毁,但堆内存未释放
}
|
ASAN调试结果
无信息输出
Valgrind调试结果
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
==8327== Memcheck, a memory error detector
==8327== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==8327== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info
==8327== Command: ./test
==8327==
==8327==
==8327== HEAP SUMMARY:
==8327== in use at exit: 400 bytes in 1 blocks
==8327== total heap usage: 1 allocs, 0 frees, 400 bytes allocated
==8327==
==8327== 400 bytes in 1 blocks are definitely lost in loss record 1 of 1
==8327== at 0x4C2AC38: operator new[](unsigned long) (vg_replace_malloc.c:433)
==8327== by 0x40069E: func() (test.cpp:6)
==8327== by 0x4006B7: main (test.cpp:13)
==8327==
==8327== LEAK SUMMARY:
==8327== definitely lost: 400 bytes in 1 blocks
==8327== indirectly lost: 0 bytes in 0 blocks
==8327== possibly lost: 0 bytes in 0 blocks
==8327== still reachable: 0 bytes in 0 blocks
==8327== suppressed: 0 bytes in 0 blocks
==8327==
==8327== For lists of detected and suppressed errors, rerun with: -s
==8327== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
|
访问野指针
1
2
3
4
5
6
|
void func() {
int* p = new int(5);
delete p; // 释放p指向的内存,但p本身未置空
// 错误:p已成野指针,再访问其指向的内存(此时为“垃圾内存”)
*p = 10; // 行为未定义:可能崩溃、修改其他变量数据
}
|
ASAN调试结果
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
|
root@iZbp1cqyppyocyfsztmoftZ:~$ ./test
=================================================================
==9244== ERROR: AddressSanitizer: heap-use-after-free on address 0x60040000dff0 at pc 0x400993 bp 0x7ffcfec78040 sp 0x7ffcfec78030
WRITE of size 4 at 0x60040000dff0 thread T0
#0 0x400992 (/root/test+0x400992)
#1 0x4009a7 (/root/test+0x4009a7)
#2 0x7f958947e554 (/usr/lib64/libc-2.17.so+0x22554)
#3 0x400838 (/root/test+0x400838)
0x60040000dff0 is located 0 bytes inside of 4-byte region [0x60040000dff0,0x60040000dff4)
freed by thread T0 here:
#0 0x7f958a05c379 (/usr/lib64/libasan.so.0.0.0+0x12379)
#1 0x40095b (/root/test+0x40095b)
#2 0x4009a7 (/root/test+0x4009a7)
#3 0x7f958947e554 (/usr/lib64/libc-2.17.so+0x22554)
previously allocated by thread T0 here:
#0 0x7f958a05c139 (/usr/lib64/libasan.so.0.0.0+0x12139)
#1 0x40090e (/root/test+0x40090e)
#2 0x4009a7 (/root/test+0x4009a7)
#3 0x7f958947e554 (/usr/lib64/libc-2.17.so+0x22554)
Shadow bytes around the buggy address:
0x0c00ffff9ba0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c00ffff9bb0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c00ffff9bc0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c00ffff9bd0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c00ffff9be0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
=>0x0c00ffff9bf0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa[fd]fa
0x0c00ffff9c00: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c00ffff9c10: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c00ffff9c20: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c00ffff9c30: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c00ffff9c40: 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
Heap righ redzone: fb
Freed Heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack partial redzone: f4
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
ASan internal: fe
==9244== ABORTING
root@iZbp1cqyppyocyfsztmoftZ:~$ addr2line -e test 0x400993
/root/test.cpp:9
|
Valgrind调试结果
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
|
==9173== Memcheck, a memory error detector
==9173== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==9173== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info
==9173== Command: ./test
==9173==
==9173== Invalid write of size 4
==9173== at 0x400709: func() (test.cpp:9)
==9173== by 0x400719: main (test.cpp:15)
==9173== Address 0x5a25040 is 0 bytes inside a block of size 4 free'd
==9173== at 0x4C2B51D: operator delete(void*) (vg_replace_malloc.c:586)
==9173== by 0x400704: func() (test.cpp:7)
==9173== by 0x400719: main (test.cpp:15)
==9173== Block was alloc'd at
==9173== at 0x4C2A593: operator new(unsigned long) (vg_replace_malloc.c:344)
==9173== by 0x4006EE: func() (test.cpp:6)
==9173== by 0x400719: main (test.cpp:15)
==9173==
==9173==
==9173== HEAP SUMMARY:
==9173== in use at exit: 0 bytes in 0 blocks
==9173== total heap usage: 1 allocs, 1 frees, 4 bytes allocated
==9173==
==9173== All heap blocks were freed -- no leaks are possible
==9173==
==9173== For lists of detected and suppressed errors, rerun with: -s
==9173== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
|
数组越界
1
2
3
4
5
6
7
8
|
void func() {
int arr[5] = {1,2,3,4,5}; // 数组下标范围0-4
// 错误:下标5超出数组边界,访问了数组后面的“无关内存”
arr[5] = 6;
// 更隐蔽的情况:动态数组越界
int* p = new int[7];
p[10] = 20; // 同样越界,破坏堆内存结构 可能导致delete失效
}
|
ASAN调试结果
只显示出最开始的数组越界的错误
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
|
=================================================================
==9998== ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7fffb7660554 at pc 0x400a79 bp 0x7fffb7660500 sp 0x7fffb76604f0
WRITE of size 4 at 0x7fffb7660554 thread T0
#0 0x400a78 (/root/test+0x400a78)
#1 0x400af0 (/root/test+0x400af0)
#2 0x7fb9d1fd3554 (/usr/lib64/libc-2.17.so+0x22554)
#3 0x4007f8 (/root/test+0x4007f8)
Address 0x7fffb7660554 is located at offset 52 in frame <func> of T0's stack:
This frame has 1 object(s):
[32, 52) 'arr'
HINT: this may be a false positive if your program uses some custom stack unwind mechanism or swapcontext
(longjmp and C++ exceptions *are* supported)
Shadow bytes around the buggy address:
0x100076ec4050: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x100076ec4060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x100076ec4070: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x100076ec4080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x100076ec4090: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x100076ec40a0: 00 00 00 00 f1 f1 f1 f1 00 00[04]f4 f3 f3 f3 f3
0x100076ec40b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x100076ec40c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x100076ec40d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x100076ec40e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x100076ec40f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
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
Heap righ redzone: fb
Freed Heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack partial redzone: f4
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
ASan internal: fe
==9998== ABORTING
root@iZbp1cqyppyocyfsztmoftZ:~$ addr2line -e test 0x7fffb7660554
??:0
root@iZbp1cqyppyocyfsztmoftZ:~$ addr2line -e test 0x400a79
/root/test.cpp:9
|
Valgrind调试结果
代码中有2个错误,前面是数组越界,后面是数组越界+内存泄露
从valgrind可以看出只显示出第二个错误
在最后2 errors from 2 contexts表明一共存在两个错误,都属于后面那个大错误
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
|
==9890== Memcheck, a memory error detector
==9890== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==9890== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info
==9890== Command: ./test
==9890==
==9890== Invalid write of size 4
==9890== at 0x4006D5: func() (test.cpp:12)
==9890== by 0x4006E5: main (test.cpp:18)
==9890== Address 0x5a25068 is 12 bytes after a block of size 28 alloc'd
==9890== at 0x4C2AC38: operator new[](unsigned long) (vg_replace_malloc.c:433)
==9890== by 0x4006C8: func() (test.cpp:11)
==9890== by 0x4006E5: main (test.cpp:18)
==9890==
==9890==
==9890== HEAP SUMMARY:
==9890== in use at exit: 28 bytes in 1 blocks
==9890== total heap usage: 1 allocs, 0 frees, 28 bytes allocated
==9890==
==9890== 28 bytes in 1 blocks are definitely lost in loss record 1 of 1
==9890== at 0x4C2AC38: operator new[](unsigned long) (vg_replace_malloc.c:433)
==9890== by 0x4006C8: func() (test.cpp:11)
==9890== by 0x4006E5: main (test.cpp:18)
==9890==
==9890== LEAK SUMMARY:
==9890== definitely lost: 28 bytes in 1 blocks
==9890== indirectly lost: 0 bytes in 0 blocks
==9890== possibly lost: 0 bytes in 0 blocks
==9890== still reachable: 0 bytes in 0 blocks
==9890== suppressed: 0 bytes in 0 blocks
==9890==
==9890== For lists of detected and suppressed errors, rerun with: -s
==9890== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
|
重复释放
1
2
3
4
5
6
|
void func() {
int* p = new int(10);
delete p; // 第一次释放,p指向的内存已回收
// 错误:再次释放同一块内存
delete p;
}
|
ASAN调试结果
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
|
root@iZbp1cqyppyocyfsztmoftZ:~$ ./test
=================================================================
==10180== ERROR: AddressSanitizer: attempting double-free on 0x60040000dff0:
#0 0x7f7524f6b379 (/usr/lib64/libasan.so.0.0.0+0x12379)
#1 0x400967 (/root/test+0x400967)
#2 0x400972 (/root/test+0x400972)
#3 0x7f752438d554 (/usr/lib64/libc-2.17.so+0x22554)
0x60040000dff0 is located 0 bytes inside of 4-byte region [0x60040000dff0,0x60040000dff4)
freed by thread T0 here:
#0 0x7f7524f6b379 (/usr/lib64/libasan.so.0.0.0+0x12379)
#1 0x40095b (/root/test+0x40095b)
#2 0x400972 (/root/test+0x400972)
#3 0x7f752438d554 (/usr/lib64/libc-2.17.so+0x22554)
previously allocated by thread T0 here:
#0 0x7f7524f6b139 (/usr/lib64/libasan.so.0.0.0+0x12139)
#1 0x40090e (/root/test+0x40090e)
#2 0x400972 (/root/test+0x400972)
#3 0x7f752438d554 (/usr/lib64/libc-2.17.so+0x22554)
==10180== ABORTING
root@iZbp1cqyppyocyfsztmoftZ:~$ addr2line -e test 0x60040000dff0
??:0
root@iZbp1cqyppyocyfsztmoftZ:~$ addr2line -e test 0x400967
/root/test.cpp:9
root@iZbp1cqyppyocyfsztmoftZ:~$ addr2line -e test 0x400972
/root/test.cpp:14
root@iZbp1cqyppyocyfsztmoftZ:~$ addr2line -e test 0x40095b
/root/test.cpp:7
root@iZbp1cqyppyocyfsztmoftZ:~$ addr2line -e test 0x40090e
/root/test.cpp:6
|
Valgrind调试结果
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
|
==10122== Memcheck, a memory error detector
==10122== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==10122== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info
==10122== Command: ./test
==10122==
==10122== Invalid free() / delete / delete[] / realloc()
==10122== at 0x4C2B51D: operator delete(void*) (vg_replace_malloc.c:586)
==10122== by 0x400710: func() (test.cpp:9)
==10122== by 0x40071B: main (test.cpp:14)
==10122== Address 0x5a25040 is 0 bytes inside a block of size 4 free'd
==10122== at 0x4C2B51D: operator delete(void*) (vg_replace_malloc.c:586)
==10122== by 0x400704: func() (test.cpp:7)
==10122== by 0x40071B: main (test.cpp:14)
==10122== Block was alloc'd at
==10122== at 0x4C2A593: operator new(unsigned long) (vg_replace_malloc.c:344)
==10122== by 0x4006EE: func() (test.cpp:6)
==10122== by 0x40071B: main (test.cpp:14)
==10122==
==10122==
==10122== HEAP SUMMARY:
==10122== in use at exit: 0 bytes in 0 blocks
==10122== total heap usage: 1 allocs, 2 frees, 4 bytes allocated
==10122==
==10122== All heap blocks were freed -- no leaks are possible
==10122==
==10122== For lists of detected and suppressed errors, rerun with: -s
==10122== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
|
参考
https://zhuanlan.zhihu.com/p/703368720
使用心得
结合使用,各有优劣