4

Valgrind memcheck 使用一堆启发式方法来避免误报“无害”使用未初始化的值,因为这种用法在正确和不正确但正常运行的代码中都很常见。

特别是,除非您以一种严肃的、也许是“不可逆”的方式实际使用这样的值,例如,根据它的值进行跳跃,否则它不会出错。

这意味着有时错误发生在离问题根源很远的地方,甚至无法确定涉及哪个值。是否有某种方法可以在运行时“检查”一个值,例如如果未初始化use(x),Valgrind 会在该位置发出错误?x

4

2 回答 2

1

你可以让你的use(x)宏使用ValgrindVALGRIND_CHECK_VALUE_IS_DEFINED客户端请求来当场出错。

为此,包括valgrind/memcheck.h并将您的宏定义为

#define use(x) VALGRIND_CHECK_VALUE_IS_DEFINED(x)

并确保始终传递一个左值。

您还可以使用 memcheck 运行--track-origins=yes更重的跟踪,以显示未初始化数据的来源。

另请参阅有关未初始化值错误的 Valgrind 常见问题解答,它解释了这两者,以及为什么 Valgrind 不会抱怨复制未初始化的值。

于 2019-07-02T12:24:09.273 回答
0

通常,像这样的东西需要对代码进行检测(由工具自动完成,或者在源代码中手动插入)。

正如我的评论中所述,如果您可以use(x)自己插入语句,您可以执行以下操作:

static FILE* dev_null = 0;
static void use_var(char* var_addr, size_t var_size)
{
  if (dev_null == 0) /* make sure we only open FILE* dev_null once */
  {
    dev_null = fopen("/dev/null", "wb");
    assert(dev_null != 0); /* opening /dev/null CAN actually fail */
  }
  size_t i;
  for (i = 0; i < var_size; ++i)
  {
    fputc(var_addr[i], dev_null); /* read every byte in the variable, write to dev_null */
  }
}

#define use(x) use_var((char*)&x, sizeof(x))

/* Example of usage */
int main()
{
  long x = 80;
  struct { double d; char c[123]; } y;
  memset(&y, 0, sizeof(y) - 1); /* initialize all bytes in y, except the last */
  double z[2] = {3.14, 42.0};

  use(x);
  use(y);
  use(z);

  return 0;
}

但是,使用struct包含对齐填充的 s 存在问题。填充从不用于任何事情,因此这可能是传递未初始化数据的合法原因。在这种情况下,Valgrind 可能会导致关于未初始化读取的虚假错误。

这两个帖子专门讨论了这个问题: 无论如何,valgrind 消息“条件跳转或移动取决于未初始化的值”可能是所谓的“误报”

我应该担心“条件跳转或移动取决于未初始化的值”吗?

于 2019-07-02T08:26:59.120 回答