pinpointing conditional jump or move depends on uninitialized value(s) valgrind message
Use the valgrind option --track-origins=yes
to have it track the origin of uninitialized values. This will make it slower and take more memory, but can be very helpful if you need to track down the origin of an uninitialized value.
Update: Regarding the point at which the uninitialized value is reported, the valgrind manual states:
It is important to understand that your program can copy around junk (uninitialised) data as much as it likes. Memcheck observes this and keeps track of the data, but does not complain. A complaint is issued only when your program attempts to make use of uninitialised data in a way that might affect your program's externally-visible behaviour.
From the Valgrind FAQ:
As for eager reporting of copies of uninitialised memory values, this has been suggested multiple times. Unfortunately, almost all programs legitimately copy uninitialised memory values around (because compilers pad structs to preserve alignment) and eager checking leads to hundreds of false positives. Therefore Memcheck does not support eager checking at this time.
Conditional jump or move depends on uninitialized value(s) with strcat in for loop
Using Valgrind to locate the problematic code
The "Conditional jump or move depends on uninitialised value(s)" message means Valgrind has determined that some result of your program depends on uninitialized memory.
Use the --track-origins=yes
flag to track the origin of the uninitialized value. It might help you finding that value. From man 1 valgrind
:
When set to yes, Memcheck keeps track of the origins of all uninitialised values. Then, when an uninitialised value error is reported, Memcheck will try to show the origin of the value. An origin can be one of the following four places: a heap block, a stack allocation, a client request, or miscellaneous other sources (eg, a call to brk).
More specifically in your program:
Problem 1: Using uninitialized genome
The line
char* genome = (char*) malloc(sizeof(char) * (genome_size+chr_total));
Allocates the genome
buffer using malloc(2)
and then consumes it in:
strcat(genome,data);
Please note that functions such as strlen(3)
and strcat(3)
works on C-strings, which are buffers that terminate with a null character ('\0').
malloc(2)
just allocates memory and it doesn't initialize it so your allocated buffer may contain any value (and considered as uninitialized). You should avoid using string related functions with an uninitialized buffers as it results undefined behavior.
Fortunately calloc(2)
does the trick - it allocates the buffer and initializes all of its bits to zero, resulting a valid 0 length C-string you can operate on. I suggest the following fix to ensure that genome
is initialized:
char* genome = calloc(genome_size+chr_total+1, sizeof(char));
Also note that I've added +1
to the length of the allocated buffer. It is done to guarantee that the resulting genome
will end with a null terminator (assuming that genome_size+chr_total
is the total size of all the buffers returned from fai_fetch
).
Also note that in terms of performance calloc
is a bit slower than malloc
(because it initializes the data) but for my opinion it is safer as it initializes the whole buffer. For the purposes of your specific program, you could save the performance burden by using malloc
and initializing just the first byte:
char* genome = malloc(sizeof(char) * (genome_size + chr_total + 1));
if (NULL == genome) {
perror("malloc of genome failed");
exit(1);
}
// So it will be a valid 0 length c-string
genome[0] = 0;
We don't have to initialize the last byte to be 0 because strcat
writes the terminating null character for us.
(Potential) Problem 2: Using potentially non-null terminated data
with strcat
As you described in your question, the fai_fetch
extracts some data:
const char *data = fai_fetch(seq_ref,chr_names[i],&chr_sizes[i]);
and then consumes it in the strcat
line:
strcat(genome,data);
As I wrote above, because you use strcat
, data
should be null-terminated as well.
I'm not sure how fai_fetch
is implemented but if it returns a valid C-string then you're all good.
If it doesn't then you should use strncat
which works on buffers that are not null-terminated.
From man 3 strcat
:
The strncat() function is similar, except that
- it will use at most n bytes from src; and
- src does not need to be null-terminated if it contains n or
more bytes.
I suggest the following fix:
// I'm not sure what type `&chr_sizes[i]` is, assuming it's `size_t`
size_t length = &chr_sizes[i];
const char *data = fai_fetch(seq_ref,chr_names[i], length);
// Use strcat
strncat(genome, used_data, length);
Valgrind error: Conditional jump or move depends on uninitialised value
Ok your main problem is with null terminators, I dont understand a lot of you logic , I just called load with a simple 4 word file.
You must make sure that you make enough space for the null and you must make sure that you have a null.
so
the ones I found, you have to fix the others
char c;
while (fread(&c, sizeof(char), 1, dict))
{
if (c != '\n')
{
tmpWord[index] = c;
index++;
}
else
{
break;
}
}
tmpWord[index] = 0; <<<<===== add the null at the end
and
//copy over the word into the node
// +1 for the null
strncpy(firstNode->word, tmpWord, index + 1);
now in hash
char* wordCopy = calloc(strlen(word)+1, sizeof(char));
strncpy(wordCopy, word, strlen(word)+1);
+1, +1
there are others I am sure.
The reason valgrind is complaining is becuase without the trailing null functions like strlen will keep readin memory till they do find a random null, valgrind sees you reading characters from waaaay off the end of what you copied
To make sure you have the null, put a printf or simply pause in the debugger and look at a string. If you see
"cat"
things are good, but if you see
"cat!!@*foodle!....ll"
then you know you have missed the null
Valgrind gives Conditional jump or move depends on uninitialised value(s) error
Although reading uninitialized memory through char*
handle is not undefined behavior (and isn't via memcpy
and memcmp
functions), still it is considered good practice to always initialize memory before reading.
Valgrind properly diagnoses the "issue", you new_st = malloc(GET_STACK_SIZE(capacity, element_size));
allocate the memory and do not initialize the memory in the range ( offsetof(stack_t, _data), offsetof(stack_t, _data) + x * y ]
. Then the code reads from it in memcpy(new_st, other, GET_STACK_SIZE(other->_capacity, other->_element_size));
and compares it in memcmp(st1, st2,
- so valgrind shows uninitialized bytes errors.
The solve would be easy - initialize the memory. Either use calloc
or call memset
like memset(new_st.data, 0, x * y)
.
Valgrind: Conditional jump or move depends on uninitialised value(s). Is not terminating a string inside a longer array with '\0' enough?
key->word
is not null terminated in the load function. The char array word
is, though it's never populated.
Valgrind memcheck keeps dying before it finishes
Per the 5th comment from my original question, this appears to be related to the valgrind macros and can at least be worked around by spacing out the macro calls to give more processing time prior to the crash. Moving to a newer version might help, too, but is unknown and not an option for me at this time.
Related Topics
Can Placement New For Arrays Be Used in a Portable Way
Template Specialization of Particular Members
Multiple Definition in Header File
Checking If a Directory Exists in Unix (System Call)
C++11 - Static_Assert Within Constexpr Function
When to Overload the Comma Operator
Const& , & and && Specifiers For Member Functions in C++
Initializing a Two Dimensional Std::Vector
The Differences Between Initialize, Define, Declare a Variable
Why Does C++ Need a Separate Header File
Optional Parameters With C++ Macros
How to Get Iostream to Perform Better
String Literal Address Across Translation Units
Why Is Out-Of-Bounds Pointer Arithmetic Undefined Behaviour
How to Deal With Mutexes in Movable Types in C++
C++ Dll Export: Decorated/Mangled Names
How Many and Which Are the Uses of "Const" in C++
Const Int' Vs. 'Int Const' as Function Parameters in C++ and C