为什么 valgrind memcheck 没有发现错误?

Kri*_*ica 3 c valgrind memcheck

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

我的代码:

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

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

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

    return 1;
}
Run Code Online (Sandbox Code Playgroud)

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

我如何使用 valgrind?

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

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

结果是:

==239== Memcheck,一个内存错误检测器

==239== 版权所有 (C) 2002-2017,以及 GNU GPL,由 Julian Seward 等人所有。

==239== 使用 Valgrind-3.16.0.GIT 和 LibVEX;使用 -h 重新运行以获取版权信息

==239== 命令:./a.out

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

==239== 堆摘要:

==239== 退出时正在使用:0 个块中的 0 个字节

==239== 总堆使用量:1 次分配,1 次释放,已分配 1,024 字节

==239==

==239== 所有堆块都被释放——不可能有泄漏

==239==

==239== 错误摘要:来自 0 个上下文的 0 个错误(禁止:来自 0 的 0)

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

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

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

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

    return 1;
}
Run Code Online (Sandbox Code Playgroud)

但是,如果我使用 a[-100],它实际上会引发错误。这是怎么回事?

编辑 2

此外,为什么这没有错误

while (i <= 2)
    {
        j = a[i];       
        i++;
    }
Run Code Online (Sandbox Code Playgroud)

但这确实

while (i <= 2)
    {
        printf("%d,", a[i]);        
        i++;
    }
Run Code Online (Sandbox Code Playgroud)

JL2*_*210 5

Valgrind 通常找不到内存错误,其中正在修改的内存与当前堆栈指针或与内存中另一个变量重合的内存的负偏移量。

例如,如果a在堆栈上,a[3]将触发memchecka[-1]不会,因为就所有 Valgrind 所知,这很容易成为有效记忆。

为了扩展这一点,这里引用了文档中我的重点:

在这个例子中,Memcheck 无法识别地址。实际上地址在堆栈上,但由于某种原因,这不是有效的堆栈地址——它低于堆栈指针,这是不允许的

这句话实际上是部分不正确的;当它说“低于堆栈指针”时,它实际上意味着与堆栈指针的正偏移量,或者干扰另一个函数的堆栈内存。

我还应该注意到(从您的第二次编辑中)Valgrind 实际上不会抱怨,直到以某种有意义的方式使用该值。在 Valgrind 看来,赋值是没有以有意义的方式使用值。这是另一个引用来支持我的重点:

重要的是要了解您的程序可以随心所欲地复制垃圾(未初始化)数据。Memcheck 观察到这一点并跟踪数据,但没有抱怨。只有当您的程序试图以可能影响您程序的外部可见行为的方式使用未初始化的数据时,才会发出投诉。

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

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