Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Could valgrind complaint about uninitialized values be a false positive?

Tags:

c

valgrind

So I've been teaching myself C, and in the hopes of learning how to properly manage memory from the beginning and write better code, I've been running Valgrind on everything. This has helped me with memory leaks, but I can't seem to get rid of this "Conditional jump or move depends on uninitialised value(s)/Uninitialised value was created by a heap allocation" situation, although I've narrowed it down to this block of code:

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

int main()    
{  
    char* test = (char*) malloc(3);
    strncpy(test, "123", 2);
    printf("%s\n", test);
    free(test);
    return 0;
}

When I run Valgrind with ---track-origins=yes, I get this output:

==91702== Conditional jump or move depends on uninitialised value(s) 
==91702==    at 0x100011507: strlen (mc_replace_strmem.c:282)
==91702==    by 0x1000AA338: puts (in /usr/lib/libSystem.B.dylib)
==91702==    by 0x100000EFA: main (valgrind_test.c:10)
==91702==  Uninitialised value was created by a heap allocation
==91702==    at 0x100010345: malloc (vg_replace_malloc.c:236)
==91702==    by 0x100000EEA: main (valgrind_test.c:8)

This seems like a false positive to me, but I'm not confident enough in my own knowledge to write it off as such. Maybe I'm allocating wrong or using strncpy wrong? I'm not sure.

Thanks in advance

like image 504
pivotal Avatar asked Jun 14 '11 15:06

pivotal


People also ask

Can Valgrind be wrong?

Yes, there are false positives with Valgrind, that's why it has suppression files for particular glibc and gcc versions, for example.

What does conditional jump mean in Valgrind?

The error message "Conditional jump or move depends on uninitialized value(s)" essentially means Valgrind has determined that the result of your program depends on uninitialized memory. Sometimes you will also see the message "Use of uninitialized value of size N".


3 Answers

No, this is broken code.

You have a memory block with 3 uninitialized characters. Then you copy "12" into it, and don't terminate. Beware of strncpy().

I quote the documentation:

The strncpy() function is similar, except that not more than n bytes of src are copied. Thus, if there is no null byte among the first n bytes of src, the result will not be null-terminated.

Since there is no termination within the first 2 characters of the source, the destination is not terminated.

like image 189
unwind Avatar answered Oct 23 '22 23:10

unwind


Idiomatic ways to use strcpy() and strncpy():

If you know that the buffer has space for the string plus the NUL terminator, you can use strcpy(). This will probably use constants, or have checks in code (you should make sure the checks are right).

Otherwise, you can do:

strncpy(dest, src, length);
dest[length - 1] = '\0';

which has the following disadvantages:

  • it can truncate strings.
  • it is potentially inefficient, since it always fills length bytes.

There is also OpenBSD's strlcpy().

Any other use of strcpy()/strncpy() is potentially suspicious, and you should look at them carefully.

Bottom line: avoid C string functions for anything moderately complex, try to use some library for dynamically allocated strings. Qmail/Postfix roll their own, GNU has obstacks.

like image 24
ninjalj Avatar answered Oct 23 '22 23:10

ninjalj


Your string has no terminator, so valgrind is probably right when it complains. Change:

strncpy(test, "123", 2);

to:

strcpy(test, "12");
like image 21
Paul R Avatar answered Oct 23 '22 23:10

Paul R