【问题标题】:Why is valgrind memcheck not finding errors?为什么 valgrind memcheck 没有发现错误?
【发布时间】:2020-04-07 20:43:21
【问题描述】:

我之前没有使用过 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,内存错误检测器

==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 个释放,1024 个字节分配

==239==

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

==239==

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

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

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

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

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

    return 1;
}

如果我使用 a[-100] 它实际上会引发错误。怎么了?

编辑 2

此外,为什么这没有错误

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

但这确实

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

【问题讨论】:

  • a[-1] 可能不会导致内存错误。就 valgrind 而言,恰好您的程序正在将 21 写入有效的内存区域。
  • 我早就猜到了,但为什么呢?
  • 我似乎找不到任何关于 -s 标志的作用的文档。
  • why though - 为什么希望内核在程序中的任何位置插入内存保护区?它会让你的程序执行非常非常慢,内核将不得不使用大量内存来标记(并记住所有)受保护的小内存区域。
  • @pr0f3ss -s 相当于 --show-error-list=yes。

标签: c valgrind memcheck


【解决方案1】:

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

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

为了对此进行扩展,这里引用了文档中的一段话,并添加了我的重点:

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

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

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

了解您的程序可以根据需要复制垃圾(未初始化)数据,这一点很重要。 Memcheck 观察到这一点并跟踪数据,但不会抱怨。仅当您的程序尝试以可能影响程序的外部可见行为的方式使用未初始化数据时,才会发出投诉。

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

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

【讨论】:

  • 为什么不能呢?是什么决定了这几个字节?如果我要做 [-100] 会起作用吗?还是[-1000]?我的意思是它将如何找到它?
  • 即使 -10 不起作用,但 -100 可以。检查我编辑的帖子
  • +1 用于解释负偏移量。您能否提供正偏移的答案,以便我可以接受您的答案(在我的问题中检查 Edit2)
  • @KristjanKica 这是另一个编辑和另一个文档引用。
【解决方案2】:

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

【讨论】:

  • 当我尝试它时,我有一个“valgrind:无法为平台'amd64-linux'启动工具'exp-sgchec':没有这样的文件或目录”。我将检查它是否是我使用 wsl2 的版本或事实。 +1 感谢您提供全局数组提示。
  • @KristjanKica 我认为您有拼写错误,请在 sgcheck 末尾添加一个“k”。
  • 啊,是的,谢谢。它正在添加warning: evaluate_Dwarf3_Expr: unhandled DW_OP_ 0x93
猜你喜欢
  • 2011-07-01
  • 2014-04-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-10-16
  • 1970-01-01
  • 2012-08-04
  • 2011-11-22
相关资源
最近更新 更多