为什么 valgrind memcheck 找不到错误?

Why is valgrind memcheck not finding errors?

我以前没有使用过 valgrind,但我认为它应该可以检测到一些内存错误。

我的代码:

#include <stdio.h>
unsigned int a[2];

int main()
{
    a[-1] = 21;

    printf("%d,", a[-1]);

    return 1;
}

如您所见,我正在访问 a[-1],但我不应该访问。

我如何使用 valgrind?

我正在编译 gcc -g -O0 codeFile.c

并执行:valgrind -s ./a.out

结果是:

==239== Memcheck, a memory error detector

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

==239== Using Valgrind-3.16.0.GIT and LibVEX; rerun with -h for copyright info

==239== Command: ./a.out

==239== 21,==239==

==239== HEAP SUMMARY:

==239== in use at exit: 0 bytes in 0 blocks

==239== total heap usage: 1 allocs, 1 frees, 1,024 bytes allocated

==239==

==239== All heap blocks were freed -- no leaks are possible

==239==

==239== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

valgrind 不应该发现这些错误,还是我用错了?

编辑: 似乎 valgrind memcheck 对全局变量没有做任何事情,并且正如 answers/comments 中所建议的那样,它应该使用远离指针的索引,因此: 我删除了全局声明并将其添加到 main 中,并访问了 a[-10] 而不是 a[1]。相同的行为。

int main()
{
    unsigned int a[2];
    a[-10] = 21;

    printf("%d,", a[-10]);

    return 1;
}

不过,如果我使用 [-100],它实际上会抛出错误。怎么回事?

编辑 2

此外,为什么没有错误

while (i <= 2)
    {
        j = a[i];       
        i++;
    }

但这确实

while (i <= 2)
    {
        printf("%d,", a[i]);        
        i++;
    }

Valgrind 通常 can't find memory errors 正在修改的内存与当前堆栈指针或内存的负偏移量与内存中的另一个变量重合。

例如,如果a在堆叠上,a[3]会触发memchecka[-1] 不会,因为据 Valgrind 所知,这很容易成为有效内存。

为了进一步说明这一点,这里引用了文档中我强调的内容:

In this example, Memcheck can't identify the address. Actually the address is on the stack, but, for some reason, this is not a valid stack address -- it is below the stack pointer and that isn't allowed.

这句话实际上有部分不正确;当它说 "below the stack pointer" 时,它实际上意味着与堆栈指针的正偏移,或者干扰另一个函数的堆栈内存。

我还应该注意到(根据您的第二次编辑)Valgrind 实际上不会抱怨,直到以某种有意义的方式使用该值。在 Valgrind 看来,赋值并不是以有意义的方式使用值。这是我强调的另一句话来支持这一点:

It is important to understand that your program can copy around junk (uninitialised) data as much as it likes. Memcheck observes this and keeps track of the data, but does not complain. A complaint is issued only when your program attempts to make use of uninitialised data in a way that might affect your program's externally-visible behaviour.

因为a是一个全局变量,你将很难检查它的内存。我之前使用过的一个 Valgrind 工具是 exp-sgcheck(实验性静态和全局变量检查),尽管我发现它不可靠(很可能是因为它是实验性的)。

检测这些问题的更简单更好的方法是启用编译器警告或使用静态分析器(我最喜欢的是 LLVM 的 scan-build)。

您将 a 声明为全局数组,因此使用 --tool=exp-sgcheck 检查堆栈和全局数组溢出。请记住,--tool=exp-sgcheck 是一个实验性实施,因此它不会在启用 -s--show-error-list=yes 时显示,您可以阅读更多关于它的信息 here.