Let's go through the code step by step (imagine that each line below is a "next" command in a debugger), with comments as to what memcheck is doing. The for
loop has been unwound and I've put two lines for each statement executed within the for
statement.
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), initialized
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
There are two important events.
num += numbers[3]
numbers[3]
is uninitialized. Adding it to num
causes num
to be marked as uninitialized even though it was previously marked as initialized. However, no error message is generated at this point. Copying uninitialized data is very common and is often harmless. If memcheck produced error messages for every such copy it would produce an unworkably large amount of error messages. memcheck does not have a crystal ball and so it cannot tell in advance whether copied uninitialized data will be used in an unsafe way.
if (num)
Here the code is making some decision based on num
, which is flagged as uninitialized. This is unsafe, so Valgrind generates an error.
This is what the manual is says as described in the link in the comment from @Tsyvarev above, but I've tried to spell it out concretely.