ILD

valgrind定位多线程程序退出时段错误
作者:Yuan Jianpeng 邮箱:yuanjp89@163.com
发布时间:2020-11-6 站点:Inside Linux Development

Valgrind tool suite提供一些debugging和profiling工具,来让你的程序跑的更快,更正确。其中最流行的工具是memcheck,它能检测C/C++程序内存相关的错误,这些错误可能导致程序奔溃和不可预测的行为。


最好使用-g -O0选项编译程序。这样valgrind的报告更准确。


valgrind尽可能设计成 non-intrusive,它直接执行要调试的程序,不需要修改代码或重新编译。使用下面的方法开始调试程序:

1
$ valgrind [valgrind-options] your-prog [your-prog-options]


最重要的选项是--tool,它指定要运行的valgrind工具。memcheck是默认的工具。程序运行在valgrind core提供的一个人造的(synthetic)CPU上。valgrind在执行指令前,将指令发送给tool,tool添加自己的指令,然后返还给core执行。memcheck工具检查每一条内存访问指令。因而可以获得非法的内存读写。大量的instrumentation code被添加,导致valgrind运行程序慢了10到50倍。


程序运行后,只有一个valgrind.bin进程,如下:

1
2
3
4
$ valgrind ./a.out
 
ps aux | grep a.out
yuanjia+ 10846  112  1.2 120364 50596 pts/4    Sl+  07:37   0:06 /usr/bin/valgrind.bin ./a.out


top可以看到原本的两个线程:

1
2
3
4
5
6
7
8
9
10
$ top -H -p `pidof valgrind.bin`
top - 07:40:04 up 21 days,  5:59,  8 users,  load average: 0.90, 0.36, 0.14
Threads:   2 total,   1 running,   1 sleeping,   0 stopped,   0 zombie
%Cpu(s): 50.2 us,  0.2 sy,  0.0 ni, 49.0 id,  0.0 wa,  0.0 hi,  0.3 si,  0.3 st
KiB Mem :  4039152 total,   287444 free,   495916 used,  3255792 buff/cache
KiB Swap:  4038652 total,  4034800 free,     3852 used.  3245980 avail Mem
 
  PID USER      PR  NI    VIRT    RES    SHR S %CPU %MEM     TIME+ COMMAND
10847 yuanjia+  20   0  120364  50596   4580 R 99.9  1.3   2:07.44 memcheck-amd64-
10846 yuanjia+  20   0  120364  50596   4580 S  0.0  1.3   0:00.95 memcheck-amd64-

但是线程名被修改了。


可以给valgrind.bin发送信号,这个信号就好像发送给a.out一样。当然不可以捕获信号只能发送给valgrind.bin。


memcheck工具可以:

1 检查非法内存读写,如堆内存越界读写,栈顶非法写、访问释放后的内存。

2 使用未定义的变量。

3 不正确的堆内存释放,如重复释放,释放非堆内存等。

4 memcpy等函数src和dst重叠。

5 传一个非法的size给分配函数。

6 内存泄漏。


测试程序代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <stdlib.h>
 
void f(void)
{
        int* x = malloc(10 * sizeof(int));
        x[10] = 0; // problem 1: heap block overrun
// problem 2: memory leak -- x not freed
 
int main(void)
{
        f();
        return 0;
}


这段程序越界访问,并且没有释放分配的内存。


选项:

--undef-value-errors=no,不检查未定义值访问。

--leak-check=no,不检查内存泄漏。

当定位堆异常时,通常不要做这两个检查,否则打印输出很多。


使用valgrind调试:

$ valgrind --undef-value-errors=no --leak-check=no ./a.out

==11481== Memcheck, a memory error detector

==11481== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.

==11481== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info

==11481== Command: ./a.out

==11481==

==11481== Invalid write of size 4

==11481==    at 0x108668: f (in /work/test/valgrid/a.out)

==11481==    by 0x108679: main (in /work/test/valgrid/a.out)

==11481==  Address 0x522d068 is 0 bytes after a block of size 40 alloc'd

==11481==    at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)

==11481==    by 0x10865B: f (in /work/test/valgrid/a.out)

==11481==    by 0x108679: main (in /work/test/valgrid/a.out)

==11481==

==11481==

==11481== HEAP SUMMARY:

==11481==     in use at exit: 40 bytes in 1 blocks

==11481==   total heap usage: 1 allocs, 0 frees, 40 bytes allocated

==11481==

==11481== For a detailed leak analysis, rerun with: --leak-check=full

==11481==


上述日志详细打印了,非法访问了哪个内存。这个内存是在哪里分配的,


参考资料:

https://www.valgrind.org/docs/manual/valgrind_manual.pdf


Copyright © linuxdev.cc 2017-2024. Some Rights Reserved.