为什么 valgrind 抛出条件跳转错误?

why does valgrind throw a conditional jump error?

我一直在尝试许多不同的方法来找出错误:

==14541== Conditional jump or move depends on uninitialised value(s)                  
==14541==    at 0x4011AC: main (so4.c:15)            

第 15 行是条件测试。示例代码:

#include <stdio.h>

int main(void)
{
   int numbers[4];
   numbers[0] = 1;
   numbers[1] = 3;
   numbers[2] = 4;
   int num = 0;
   for(int i = 0; i < 4; i++)
   {
    num *= 10;
    num += numbers[i];
   }
   if (num)
   {
      printf("num %d\n", num);
   }
}

对于上下文,数字是一个包含数字的数组,我正在尝试将它们组合起来,因此 {1,3,4} 应该导致 134

条件测试给出了 Valgrind 错误

让我们逐步查看代码,并附上关于 memcheck 正在做什么的注释。 for 循环已展开,我为 for 语句中执行的每个语句放置了两行。

int numbers[4]; // 16 bytes reserved on the stack, recorded as uninitialized
numbers[0] = 1; // the first 12 bytes of the stack area get values stored
numbers[1] = 3; // in them and recorded as initialized
numbers[2] = 4;
// bytes 12 to 15 on the stack are still uninitialized
int num=0; // num initialized to zero
for(int i = 0; i < 4; i++) // initialize i to 0
for(int i = 0; i < 4; i++) // check i < 4, initialized
num *= 10; // multiply num by 10 (0), initialized
num += numbers[i]; // add numbers[0] (1) to num (1), iniitialized
for(int i = 0; i < 4; i++) // increment i (1), initialized
for(int i = 0; i < 4; i++) // second loop, check i < 4, initialized
num *= 10; // multiply num by 10 (10), initialized
num += numbers[i]; // add numbers[1] (3) to num (13), initialized
for(int i = 0; i < 4; i++) // increment i (2), initialized
for(int i = 0; i < 4; i++) // third loop, check i < 4, initialized
num *= 10; // multiply num by 10 (130), initialized
num += numbers[i]; // add numbers[2] (4) to num (134), initialized
for(int i = 0; i < 4; i++) // increment i(3), initialized
for(int i = 0; i < 4; i++) // fourth loop, check i < 4, initialized
num *= 10; // multiply num by 10 (1340), initialized
num += numbers[i]; // add numbers[3] (????) to num (????), uninitialized, see below
if (num) // read num and use it in a condition, print an error message

有两个重要事件。

num += numbers[3]

numbers[3] 未初始化。将它添加到 num 会导致 num 被标记为未初始化 ,即使它之前被标记为已初始化 。但是,此时不会生成任何错误消息。复制未初始化的数据很常见,而且通常是无害的。如果 memcheck 为每个这样的副本生成错误消息,它将生成大量无法工作的错误消息。 memcheck 没有 crystal 球,因此它无法提前判断复制的未初始化数据是否会以不安全的方式使用。

if (num)

这里的代码根据 num 做出一些决定,它被标记为未初始化。这是不安全的,因此 Valgrind 会生成错误。

这就是上面@Tsyvarev 评论中 link 中描述的手册内容,但我已尝试具体说明。