在 Valgrind 中抑制 GTK 错误

Suppressing GTK errors in Valgrind

我正在尝试编写一个 GTK 应用程序并想用 valgrind 测试它的有效性。

这是我要测试的示例程序:

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

#include <gtk/gtk.h>

int
main (int argc, char *argv[])
{
  GtkWidget *win;
  GtkWidget *btn;

  gtk_init (&argc, &argv);

  win = gtk_window_new (GTK_WINDOW_TOPLEVEL);
  btn = gtk_button_new_with_label ("Hello");

  gtk_container_add (GTK_CONTAINER (win), btn);
  gtk_widget_show_all (win);

  gtk_main();
}

GNOME 基金会写了一个 an article 关于使用 valgrind 测试应用程序,但即使我用所有这些标志启动 valgrind

valgrind --tool=memcheck --leak-check=full --num-callers=15 --log-file=vgdump ./diashow 

甚至在 valgrind-page

中提到的 gtk.suppression file
valgrind --tool=memcheck --leak-check=full --num-callers=15 --suppressions=gtk.suppression --log-file=vgdump ./diasho

valgrind dumpfile (pastebin) vgdump 非常难读。 2285行!

对我来说最奇怪的部分是我的 vgdump 文件以 Invalid write of size 4 开头,然后是 Invalid read of size 4。谁能给我解释一下吗?

根据我的经验,使用 valgrind 时的一个好规则是在开始时检查一些错误,尝试修复这些错误,然后再次在 valgrind 下重新启动应用程序。原因是:假设你在分配数组的函数中出错,并使用数组和数组的大小调用另一个函数+1 (即比实际大小多一个元素的大小)。然后,当下一个函数尝试访问过多的元素时,valgrind 可能会注意到它并触发警告。但是该函数可能会调用另一个函数,该函数也可能会尝试访问该元素,这也会导致警告,依此类推。

所以你最终得到了一堆导致一个错误的消息。即使有关于另一个错误的消息,找到这些通常也很难,修复第一个错误并再次重新启动应用程序和 valgrind 更容易。

此外,您需要对 valgrind 错误持怀疑态度。例如。我记得它曾经向我报告过函数 main 中有一个未初始化的变量——出于某种原因 valgrind 看不到它实际上是。它导致一条消息,指出在 main 调用的每个函数(即我程序中的每个函数)中使用了未初始化的变量。但我应该提一下,那是很久以前的事了——三年前——我可以假设 valgrind 甚至在那时都不是最新版本,只是因为 Ubuntu 存储库往往没有许多应用程序的最新版本。

Invalid read of size 4表示某处缓冲区溢出。第一个此类错误的堆栈跟踪应该指向您可以找到问题的位置。很难说更多,因为你没有显示堆栈跟踪,但你必须知道有错误的函数可能是上面错误数组的受害者。

作为旁注,我建议您调试那种默认情况下适用于 GCC 和 Clang 的错误 with AddressSanitizer (并且它们具有相同的选项来启用它)。它往往会给出 更详细的错误输出 (是的,它甚至是丰富多彩的!ε:),并且默认情况下会关闭应用程序当发生任何类型的内存错误时。此外,当 AddressSanitizer 不存在时,valgrind 会错过大部分内存错误 - 例如堆栈溢出等。是的,有时 (如您的情况) 它有效,但根据我的经验不经常。