【linux】Valgrind工具集详解(七):Memcheck(内存错误检测器)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u010168781/article/details/83749609

一、概述

Memcheck是一个内存错误检测器。它可以检测C和C ++程序中常见的以下问题:
1、非法内存:如越界、释放后继续访问;
2、使用未初始化的值;
3、释放内存错误:如double-free(同一内存上执行了两次free)、或者 malloc、new、new[] 与 free、delete、delete[]错配使用
4、memcpy函数(或其它相关函数)中src和dst指针重叠;
5、分配函数时,传递的size参数非法,如果是一个负数;
6、内存泄漏。

像这样的问题很难通过其他方式找到,经常长时间未被发现,然后造成偶然的,难以诊断的崩溃。

二、Memcheck中错误消息的含义详解

1、Invalid read of size 4

含义:非法读取或写入错误。
例子,main.c源码如下

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

int main()
{
	int *x = (int *)malloc(sizeof(int)*10);
	int i;
	for(i=0; i<=10; ++i)
	{
		x[i] = i;//当i=10时,越界,非法访问
	}
}

编译:gcc -g main.c
内存错误检查:valgrind --tool=memcheck ./a.out
错误信息如下

==20979== Memcheck, a memory error detector
==20979== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==20979== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==20979== Command: ./a.out
==20979== Parent PID: 17485
==20979== 
==20979== Invalid write of size 4
==20979==    at 0x400563: main (main.c:10)
==20979==  Address 0x5200068 is 0 bytes after a block of size 40 alloc'd
==20979==    at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==20979==    by 0x40053E: main (main.c:6)
==20979== 
==20979== 
==20979== HEAP SUMMARY:
==20979==     in use at exit: 40 bytes in 1 blocks
==20979==   total heap usage: 1 allocs, 0 frees, 40 bytes allocated
==20979== 
==20979== LEAK SUMMARY:
==20979==    definitely lost: 40 bytes in 1 blocks
==20979==    indirectly lost: 0 bytes in 0 blocks
==20979==      possibly lost: 0 bytes in 0 blocks
==20979==    still reachable: 0 bytes in 0 blocks
==20979==         suppressed: 0 bytes in 0 blocks
==20979== Rerun with --leak-check=full to see details of leaked memory
==20979== 
==20979== For counts of detected and suppressed errors, rerun with: -v
==20979== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
2、Conditional jump or move depends on uninitialised value(s)

含义:使用未初始化的值。
经常会遇到这个错误。
例子
main.c源码如下

#include <stdio.h>

int main()
{
	int x;
	printf("x = %d\n",x); //此处访问未初始化的值,错误
}

编译:gcc -g main.c
内存错误检查:valgrind --tool=memcheck ./a.out
错误信息如下

==21182== Memcheck, a memory error detector
==21182== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==21182== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==21182== Command: ./a.out
==21182== Parent PID: 17485
==21182== 
==21182== Conditional jump or move depends on uninitialised value(s)
==21182==    at 0x4E814CE: vfprintf (vfprintf.c:1660)
==21182==    by 0x4E8B3D8: printf (printf.c:33)
==21182==    by 0x400548: main (main.c:6)
==21182== 
==21182== Use of uninitialised value of size 8
==21182==    at 0x4E8099B: _itoa_word (_itoa.c:179)
==21182==    by 0x4E84636: vfprintf (vfprintf.c:1660)
==21182==    by 0x4E8B3D8: printf (printf.c:33)
==21182==    by 0x400548: main (main.c:6)
==21182== 
==21182== Conditional jump or move depends on uninitialised value(s)
==21182==    at 0x4E809A5: _itoa_word (_itoa.c:179)
==21182==    by 0x4E84636: vfprintf (vfprintf.c:1660)
==21182==    by 0x4E8B3D8: printf (printf.c:33)
==21182==    by 0x400548: main (main.c:6)
==21182== 
==21182== Conditional jump or move depends on uninitialised value(s)
==21182==    at 0x4E84682: vfprintf (vfprintf.c:1660)
==21182==    by 0x4E8B3D8: printf (printf.c:33)
==21182==    by 0x400548: main (main.c:6)
==21182== 
==21182== Conditional jump or move depends on uninitialised value(s)
==21182==    at 0x4E81599: vfprintf (vfprintf.c:1660)
==21182==    by 0x4E8B3D8: printf (printf.c:33)
==21182==    by 0x400548: main (main.c:6)
==21182== 
==21182== Conditional jump or move depends on uninitialised value(s)
==21182==    at 0x4E8161C: vfprintf (vfprintf.c:1660)
==21182==    by 0x4E8B3D8: printf (printf.c:33)
==21182==    by 0x400548: main (main.c:6)
==21182== 
==21182== 
==21182== HEAP SUMMARY:
==21182==     in use at exit: 0 bytes in 0 blocks
==21182==   total heap usage: 0 allocs, 0 frees, 0 bytes allocated
==21182== 
==21182== All heap blocks were freed -- no leaks are possible
==21182== 
==21182== For counts of detected and suppressed errors, rerun with: -v
==21182== Use --track-origins=yes to see where uninitialised values come from
==21182== ERROR SUMMARY: 6 errors from 6 contexts (suppressed: 0 from 0)

可以加上选项 “–track-origins=yes”来查找,未初始化的来源,但会使Memcheck运行的更慢;
如加上选项 “–track-origins=yes”后打印信息如下

==21210== Memcheck, a memory error detector
==21210== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==21210== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==21210== Command: ./a.out
==21210== Parent PID: 17485
==21210== 
==21210== Conditional jump or move depends on uninitialised value(s)
==21210==    at 0x4E814CE: vfprintf (vfprintf.c:1660)
==21210==    by 0x4E8B3D8: printf (printf.c:33)
==21210==    by 0x400548: main (main.c:6)
==21210==  Uninitialised value was created by a stack allocation
==21210==    at 0x40052D: main (main.c:4)
==21210== 
==21210== Use of uninitialised value of size 8
==21210==    at 0x4E8099B: _itoa_word (_itoa.c:179)
==21210==    by 0x4E84636: vfprintf (vfprintf.c:1660)
==21210==    by 0x4E8B3D8: printf (printf.c:33)
==21210==    by 0x400548: main (main.c:6)
==21210==  Uninitialised value was created by a stack allocation
==21210==    at 0x40052D: main (main.c:4)
==21210== 
==21210== Conditional jump or move depends on uninitialised value(s)
==21210==    at 0x4E809A5: _itoa_word (_itoa.c:179)
==21210==    by 0x4E84636: vfprintf (vfprintf.c:1660)
==21210==    by 0x4E8B3D8: printf (printf.c:33)
==21210==    by 0x400548: main (main.c:6)
==21210==  Uninitialised value was created by a stack allocation
==21210==    at 0x40052D: main (main.c:4)
==21210== 
==21210== Conditional jump or move depends on uninitialised value(s)
==21210==    at 0x4E84682: vfprintf (vfprintf.c:1660)
==21210==    by 0x4E8B3D8: printf (printf.c:33)
==21210==    by 0x400548: main (main.c:6)
==21210==  Uninitialised value was created by a stack allocation
==21210==    at 0x40052D: main (main.c:4)
==21210== 
==21210== Conditional jump or move depends on uninitialised value(s)
==21210==    at 0x4E81599: vfprintf (vfprintf.c:1660)
==21210==    by 0x4E8B3D8: printf (printf.c:33)
==21210==    by 0x400548: main (main.c:6)
==21210==  Uninitialised value was created by a stack allocation
==21210==    at 0x40052D: main (main.c:4)
==21210== 
==21210== Conditional jump or move depends on uninitialised value(s)
==21210==    at 0x4E8161C: vfprintf (vfprintf.c:1660)
==21210==    by 0x4E8B3D8: printf (printf.c:33)
==21210==    by 0x400548: main (main.c:6)
==21210==  Uninitialised value was created by a stack allocation
==21210==    at 0x40052D: main (main.c:4)
==21210== 
==21210== 
==21210== HEAP SUMMARY:
==21210==     in use at exit: 0 bytes in 0 blocks
==21210==   total heap usage: 0 allocs, 0 frees, 0 bytes allocated
==21210== 
==21210== All heap blocks were freed -- no leaks are possible
==21210== 
==21210== For counts of detected and suppressed errors, rerun with: -v
==21210== ERROR SUMMARY: 6 errors from 6 contexts (suppressed: 0 from 0)

其中,指出未初始化的位置信息是:
==21210== Uninitialised value was created by a stack allocation
==21210== at 0x40052D: main (main.c:4)

3、Syscall param * uninitialised byte(s)

Syscall param write(buf) points to uninitialised byte(s)
Syscall param write(buf) points to uninitialised byte(s)
含义:在系统调用中使用未初始化或不可寻址的值。
Memcheck检查系统调用的所有参数:
它会检查所有直接参数本身,无论它们是否已初始化。
此外,如果系统调用需要从程序提供的缓冲区中读取,则Memcheck会检查整个缓冲区是否可寻址并初始化其内容。
此外,如果系统调用需要写入用户提供的缓冲区,Memcheck会检查缓冲区是否可寻址。
系统调用后,Memcheck会更新其跟踪信息,以准确反映系统调用导致的内存状态的任何变化。
例子
源码main.c如下

  #include <stdlib.h>
  #include <unistd.h>
  int main( void )
  {
    char* arr  = malloc(10);
    int*  arr2 = malloc(sizeof(int));
    write( 1 /* stdout */, arr, 10 );
    exit(arr2[0]);
  }

编译:gcc -g main.c
内存检查:valgrind --tool=memcheck ./a.out
错误打印信息如下

==21355== Memcheck, a memory error detector
==21355== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==21355== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==21355== Command: ./a.out
==21355== Parent PID: 17485
==21355== 
==21355== Syscall param write(buf) points to uninitialised byte(s)
==21355==    at 0x4F263C0: __write_nocancel (syscall-template.S:81)
==21355==    by 0x4005F6: main (main.c:7)
==21355==  Address 0x5200040 is 0 bytes inside a block of size 10 alloc'd
==21355==    at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==21355==    by 0x4005CE: main (main.c:5)
==21355==  Uninitialised value was created by a heap allocation
==21355==    at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==21355==    by 0x4005CE: main (main.c:5)
==21355== 
==21355== Syscall param exit_group(status) contains uninitialised byte(s)
==21355==    at 0x4EFC109: _Exit (_exit.c:32)
==21355==    by 0x4E7316A: __run_exit_handlers (exit.c:97)
==21355==    by 0x4E731F4: exit (exit.c:104)
==21355==    by 0x400603: main (main.c:8)
==21355==  Uninitialised value was created by a heap allocation
==21355==    at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==21355==    by 0x4005DC: main (main.c:6)
==21355== 
==21355== 
==21355== HEAP SUMMARY:
==21355==     in use at exit: 14 bytes in 2 blocks
==21355==   total heap usage: 2 allocs, 0 frees, 14 bytes allocated
==21355== 
==21355== LEAK SUMMARY:
==21355==    definitely lost: 0 bytes in 0 blocks
==21355==    indirectly lost: 0 bytes in 0 blocks
==21355==      possibly lost: 0 bytes in 0 blocks
==21355==    still reachable: 14 bytes in 2 blocks
==21355==         suppressed: 0 bytes in 0 blocks
==21355== Rerun with --leak-check=full to see details of leaked memory
==21355== 
==21355== For counts of detected and suppressed errors, rerun with: -v
==21355== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
4、 Invalid free() / delete / delete[] / realloc()

含义:非法释放。
例子
源码main.c如下:

#include <stdlib.h>
#include <unistd.h>
int main( void )
{
	char* arr  = malloc(10);
	free(arr);
	free(arr);
	return 0;
}

编译:gcc -g main.c
内存检查:valgrind --tool=memcheck ./a.out
错误打印信息如下

==21442== Memcheck, a memory error detector
==21442== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==21442== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==21442== Command: ./a.out
==21442== Parent PID: 17485
==21442== 
==21442== Invalid free() / delete / delete[] / realloc()
==21442==    at 0x4C2BDEC: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==21442==    by 0x4005AA: main (main.c:7)
==21442==  Address 0x5200040 is 0 bytes inside a block of size 10 free'd
==21442==    at 0x4C2BDEC: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==21442==    by 0x40059E: main (main.c:6)
==21442== 
==21442== 
==21442== HEAP SUMMARY:
==21442==     in use at exit: 0 bytes in 0 blocks
==21442==   total heap usage: 1 allocs, 2 frees, 10 bytes allocated
==21442== 
==21442== All heap blocks were freed -- no leaks are possible
==21442== 
==21442== For counts of detected and suppressed errors, rerun with: -v
==21442== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
5、Mismatched free() / delete / delete []

含义:分配内存和释放内存方法不匹配。
例子:使用malloc分配内存,然后使用delete释放就会报这个错误。
源码main.c

#include <stdlib.h>
#include <unistd.h>
int main( void )
{
	char* arr  = (char*)malloc(10);
	delete arr;
	return 0;
}

使用G++编译:g++ -g main.c
内存检查:valgrind --tool=memcheck ./a.out
错误打印信息如下

==21579== Memcheck, a memory error detector
==21579== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==21579== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==21579== Command: ./a.out
==21579== Parent PID: 17485
==21579== 
==21579== Mismatched free() / delete / delete []
==21579==    at 0x4C2C2BC: operator delete(void*) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==21579==    by 0x40066E: main (main.c:6)
==21579==  Address 0x5a20040 is 0 bytes inside a block of size 10 alloc'd
==21579==    at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==21579==    by 0x40065E: main (main.c:5)
==21579== 
==21579== 
==21579== HEAP SUMMARY:
==21579==     in use at exit: 0 bytes in 0 blocks
==21579==   total heap usage: 1 allocs, 1 frees, 10 bytes allocated
==21579== 
==21579== All heap blocks were freed -- no leaks are possible
==21579== 
==21579== For counts of detected and suppressed errors, rerun with: -v
==21579== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
6、Source and destination overlap in memcpy

含义:下面的C库函数从一个存储器块复制一些数据到另一个memcpy、 strcpy、strncpy、strcat、strncat它们src和 dst指针指向的块不允许重叠。POSIX标准的措辞如下:“如果在重叠的对象之间进行复制,则行为未定义。” 因此,Memcheck会检查这一点。
例子
源码main.c如下:

#include<string.h>

int main( void )
{
	char a[12] = {'h','e','l', 'l','o','\0'};
	memcpy(a+3,a,6);
	return 0;
}

编译:gcc -g main.c
内存检查:valgrind --tool=memcheck ./a.out
错误打印信息如下

==22017== Memcheck, a memory error detector
==22017== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==22017== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==22017== Command: ./a.out
==22017== 
==22017== Source and destination overlap in memcpy(0xffefffbc3, 0xffefffbc0, 6)
==22017==    at 0x4C2F71C: memcpy@@GLIBC_2.14 (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==22017==    by 0x400613: main (main.c:6)
==22017== 
==22017== 
==22017== HEAP SUMMARY:
==22017==     in use at exit: 0 bytes in 0 blocks
==22017==   total heap usage: 0 allocs, 0 frees, 0 bytes allocated
==22017== 
==22017== All heap blocks were freed -- no leaks are possible
==22017== 
==22017== For counts of detected and suppressed errors, rerun with: -v
==22017== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
疑问,当我用memcpy(a, a, 6);时,没有报错,哪位大神给解释下?
7、Argument ‘size’ of function malloc has a fishy (possibly negative) value:

含义:可疑的参数值。
所有内存分配函数都使用一个参数来指定应分配的内存块的大小。显然,请求的大小应该是非负值,并且通常不会过大。例如,在64位计算机上,分配请求的大小超过2 ** 63字节或者是负值。这样的值被称为“可疑的值”。
下列函数中的size参数将被检查: malloc、calloc、 realloc、memalign、new、 new []、 __builtin_new、 __builtin_vec_new,对于calloc 两个参数都在检查中。
例子
源码main.c如下

#include <stdlib.h>
#include <unistd.h>
int main( void )
{
	char* arr  = (char *)malloc(-1);
	free(arr);
	return 0;
}

编译:gcc -g main.c
内存检查:valgrind --tool=memcheck ./a.out
错误打印信息如下

==22177== Memcheck, a memory error detector
==22177== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==22177== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==22177== Command: ./a.out
==22177== 
==22177== Argument 'size' of function malloc has a fishy (possibly negative) value: -1
==22177==    at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==22177==    by 0x400590: main (main.c:5)
==22177== 
==22177== 
==22177== HEAP SUMMARY:
==22177==     in use at exit: 0 bytes in 0 blocks
==22177==   total heap usage: 0 allocs, 0 frees, 0 bytes allocated
==22177== 
==22177== All heap blocks were freed -- no leaks are possible
==22177== 
==22177== For counts of detected and suppressed errors, rerun with: -v
==22177== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
8、LEAK SUMMARY:

含义:内存泄漏检查。
Memcheck跟踪malloc/new函数对应的free/delete等的调用,因此,当程序退出时,它知道哪些块未被释放。
此功能需要设置参数–leak-check=summary或full。
例子
源码main.c如下

#include <stdlib.h>
#include <unistd.h>
int main( void )
{
	char* arr  = (char *)malloc(4);
	//free(arr);//此处没有释放
	return 0;
}

编译:gcc -g main.c
内存检查:valgrind --tool=memcheck --leak-check=full ./a.out
错误打印信息如下

==22289== Memcheck, a memory error detector
==22289== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==22289== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==22289== Command: ./a.out
==22289== 
==22289== 
==22289== HEAP SUMMARY:
==22289==     in use at exit: 4 bytes in 1 blocks
==22289==   total heap usage: 1 allocs, 0 frees, 4 bytes allocated
==22289== 
==22289== 4 bytes in 1 blocks are definitely lost in loss record 1 of 1
==22289==    at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==22289==    by 0x40053E: main (main.c:5)
==22289== 
==22289== LEAK SUMMARY:
==22289==    definitely lost: 4 bytes in 1 blocks
==22289==    indirectly lost: 0 bytes in 0 blocks
==22289==      possibly lost: 0 bytes in 0 blocks
==22289==    still reachable: 0 bytes in 0 blocks
==22289==         suppressed: 0 bytes in 0 blocks
==22289== 
==22289== For counts of detected and suppressed errors, rerun with: -v
==22289== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

LEAK SUMMARY:内存泄漏总结(分类)
definitely lost: 4 bytes in 1 blocks:绝对丢失,这种情况应该由程序员来解决,下面几种情况,可以当作参考
indirectly lost: 0 bytes in 0 blocks:间接丢失
possibly lost: 0 bytes in 0 blocks:可能丢失
still reachable: 0 bytes in 0 blocks:仍然可以访问
suppressed: 0 bytes in 0 blocks:抑制错误中的丢失

猜你喜欢

转载自blog.csdn.net/u010168781/article/details/83749609