【问题标题】:Program fails normally, but not in Valgrind程序正常失败,但在 Valgrind 中没有
【发布时间】:2024-05-03 08:25:02
【问题描述】:

我在调试用 C11 编写的应用程序时遇到了这个问题。我阅读了其他相关的堆栈帖子,但没有一个能解决我的问题。我的代码包含一个“安全 malloc”实现,如下所示:

void *try_malloc(size_t size) {
  void *mem = malloc(size);
  if (!mem) { perror("Error: unable to allocate memory"); exit(1); }
  return mem;
}

我编译它:
gcc -Wall -Wextra -std=c11 -ggdb -o main
然后当我使用./main < inp.in 运行它时,它显然有内存问题并输出“错误:无法分配内存:无法分配内存”并以代码1 退出。当我使用valgrind ./main < inp.in 运行它时,valgrind 报告没有警告或错误,报告比没有内存泄漏是可能的并且程序打印正确的输出。
为了方便,我写了一个简单的测试脚本:

$ cat ttest.sh
./main < inp.in

当我像valgrind ./ttest.sh一样运行valgrind时,再次出现与上面相同的问题,这是“错误:无法分配内存:无法分配内存”,但valgrind无法产生有意义的跟踪并且没有给我任何信息关于为什么会出现问题。 Inp.in 是一个大文件,我的程序应该使用大量内存来处理它。对于较小的输入文件,不会发生内存错误。我在 Debian 中的环境在 WSL2 中运行。

  • 如何调试它?
  • 为什么在 Valgrind 中运行的程序可以正常工作?
  • 如何设置 Valgrind 以便重现分配错误?
  • 可能是某种竞争条件? (虽然我没有使用任何线程等,但代码没有任何异步)
  • 可能是 WSL 限制了子进程的内存吗?如何检查?

@编辑: Valgrind 对程序执行环境的影响抑制了这个问题。我将尝试找出 Valgrind 究竟如何影响 env 以尝试重现问题并可能提供 MRE

【问题讨论】:

  • 代码不完整。请提供complete minimal reproducible example。也就是说,显示可以重现问题的准确和完整的代码。例如,我们如何知道函数没有被过大的size 值调用?
  • 您可以在调试器中运行并在perror 上放置断点。您可能还想打印 size 以确保它具有合理的值。
  • 关于 valgrind,当您在 valgrind 中运行 shell 脚本时,除非您使用 --trace-children=yes,否则它不会检查您的程序。
  • @kaylum 我知道我应该提供 CMRE,但我什至无法正确重现问题,更不用说在不提供完整源代码的情况下找到它的源代码了,因为它有几个 kLOC 大跨度>
  • 在您尝试调试程序时似乎消失的错误通常与未定义的行为有关。我猜size 的值是由未定义的行为引起的,当您运行程序而不尝试调试它时,这是一个非常大的数字。当使用valgrind 运行时,内存布局可能不同,或者未初始化的变量可能会获得不同的值,从而导致程序的不同行为。

标签: c memory valgrind


【解决方案1】:

我解决了问题 - 错误出现在我的代码中(我在重新分配指针指向的数据结构后忘记更新指针)。但是,我无法回答为什么程序在 Valgrind 中没有失败的问题

【讨论】: