In my C program, I'm allocating memory using malloc() which does, in contrast to calloc(), not initialize the memory and it might still contain garbage. Mostly, in context of the allocation, I do not make any changes to the memory allocated by malloc(). (For example in a function to initialize a struct that contains a buffer, I do not make changes to the buffer's memory, but later on).
Valgrind gives me a lot of theese errors:
Conditional jump or move depends on uninitialised value(s)
Use of uninitialised value of size 4
I am sure to never read from memory that was not initialized in these cases.
Should I ignore them or is it better to initialize the memory on allocation? In case I should ignore them, how can I deactivate this error message in Valgrind?
Example 1:
==4253== Conditional jump or move depends on uninitialised value(s)
==4253== at 0x408EB8E: vfprintf (vfprintf.c:1624)
==4253== by 0x4093C2E: printf (printf.c:35)
==4253== by 0x40624D2: (below main) (libc-start.c:226)
==4253== Uninitialised value was created by a heap allocation
==4253== at 0x402BE68: malloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==4253== by 0x8048938: gk_StreamBufferNode_init (stream.c:101)
==4253== by 0x8048D0D: gk_Stream_bufferWriteProc (stream.c:252)
==4253== by 0x8048665: main (main.c:21)
Code:
int gk_StreamBufferNode_init(gk_StreamBufferNode* node, int buffer_size,
gk_AllocProc malloc) {
node->buffer = malloc(buffer_size); // line 101
if (node->buffer == NULL) {
return GKIT_FAILEDALLOC;
}
node->next = NULL;
return GKIT_NOERR;
}
Example 2:
==4253== Conditional jump or move depends on uninitialised value(s)
==4253== at 0x402DA39: memcpy (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==4253== by 0x8048C6E: gk_Stream_bufferWriteProc (stream.c:230)
==4253== by 0x8048665: main (main.c:21)
==4253== Uninitialised value was created by a heap allocation
==4253== at 0x402BE68: malloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==4253== by 0x8048CE0: gk_Stream_bufferWriteProc (stream.c:248)
==4253== by 0x8048665: main (main.c:21)
Code:
/* ... */
int available_bytes = binfo->buffer_size - bnode->filled;
int bytes_to_go = size * count;
int offset = 0;
int node_offset = 0;
gk_StreamBufferNode* new_node;
void* destination = NULL;
void* source = NULL;
while (bytes_to_go > 0) {
destination = bnode->buffer + bnode->filled + node_offset;
source = buffer + offset;
if (available_bytes > bytes_to_go) {
memcpy(destination, source, bytes_to_go); // line 230
bnode->filled += bytes_to_go;
offset += bytes_to_go;
node_offset = bytes_to_go;
bytes_to_go = 0;
}
else {
memcpy(destination, source, available_bytes);
offset += available_bytes;
node_offset = 0;
bytes_to_go -= available_bytes;
bnode->filled += available_bytes;
#ifdef DEBUG
assert(bnode->filled == bnode->buffer_size);
#endif // DEBUG
// Allocate a new buffer node.
new_node = (gk_StreamBufferNode*) malloc(sizeof(gk_StreamBufferNode)); // line 248
if (new_node == NULL) {
return GKIT_FAILEDALLOC;
}
int success = gk_StreamBufferNode_init(new_node, binfo->buffer_size,
malloc);
if (success <= GKIT_ERROR) {
free(new_node);
return GKIT_FAILEDALLOC;
}
bnode->next = new_node;
bnode = new_node;
available_bytes = binfo->buffer_size;
}
}
In both cases you just allocate memory without initializing it. The easiest way is to use calloc instead of malloc to zero it out. This may be a good strategy for simple cases, e.g if you later use a buffer as a string that is to be printed. For more complicated use cases assign values to the individual fields, or even better if you have C99 assign the whole structure from a compound literal:
toto * t = malloc(sizeof(*t));
*t = (toto){ 0 };
Your code should not be expecting uninitialized memory to contain any value, so having conditional jumps dependent on these shows serious problems.
You should either be initializing the memory (to some known value, eg. 0), or not refer to its contents unless they have been initialized.
Related
When debugin my code, I'm getting a series of strange errors in Valgrind. The errors are all of the same type: "Conditional jump or move depends on uninitialised value(s) at ... Uninitialised value was created by a stack allocation at ...".
Example of valgrind output:
==153367== Thread 6:
==153367== Conditional jump or move depends on uninitialised value(s)
==153367== at 0x14B393: serializeNewAnnounce (topology_discovery.c:1146)
==153367== by 0x1494A2: upon_AnnounceTimer (topology_discovery.c:360)
==153367== by 0x148D87: topology_discovery_main_loop (topology_discovery.c:189)
==153367== by 0x49EB608: start_thread (pthread_create.c:477)
==153367== by 0x4B27102: clone (clone.S:95)
==153367== Uninitialised value was created by a stack allocation
==153367== at 0x14AB00: serializeNewAnnounce (topology_discovery.c:1076)
==153367==
==153367== Conditional jump or move depends on uninitialised value(s)
==153367== at 0x14B3CC: serializeNewAnnounce (topology_discovery.c:1204)
==153367== by 0x1494A2: upon_AnnounceTimer (topology_discovery.c:360)
==153367== by 0x148D87: topology_discovery_main_loop (topology_discovery.c:189)
==153367== by 0x49EB608: start_thread (pthread_create.c:477)
==153367== by 0x4B27102: clone (clone.S:95)
==153367== Uninitialised value was created by a stack allocation
==153367== at 0x14AB00: serializeNewAnnounce (topology_discovery.c:1076)
At a frist glance, this error seems to indicate that I forgot to initialize some memory.
However, up verifying several times, I can't find where exactly is the source of these errors.
The code is huge and with several functions, so I filtered only the important parts:
...
148 topology_discovery_state* state = malloc(sizeof(topology_discovery_state));
149 memset(state, 0, sizeof(topology_discovery_state));
...
260 state->neighbors = double_list_init(); // neighbors is a malloc and initializes head as NULL
...
... // The following code is within a single function, the previous is on another function
...
1047 unsigned int horizon = state->proto_args.horizon;
...
1050 unsigned char ptrs[horizon+1];
1051 memset(ptrs, 0, sizeof(ptrs));
...
1076 for(double_list_item* current_item = state->neighbors->head; current_item; current_item = current_item->next) {
1077 neighbor* current_neigh = (neighbor*) current_item->data;
...
1106 for(int h = 0; h <= horizon; h++) {
1107 ptrs[h] = levels[h]->size + ptrs[h-1];
1108 }
...
1145 int processed = 0;
1146 for(int h = 0; h <= horizon; h++) {
1147 int level_size = ptrs[h];
1148 int level_start = h == 0 ? 0 : ptrs[h-1];
1149 for(int node = level_start; node < level_size; node++) {
...
Only state is not a local variable and is passed as a parameter, the rest is all local to the same function.
At line 1107, in the first iteration, ptrs get index -1. Since in C array is actually a memory location and index interprete as pointer arithmetic, the result is access to the memory location that is one byte before ptrs, which is of course not initialized.
So I'm building a virtual machine, and trying to make it as cross platform as possible, and suddenly encountering a strange error. There is a let instruction for my machine, which allocates memory for a variable in the memory of the machine and assign that variable with a value. In short, the let function calls getAddress to get the address of the variable. getAddress checks if the variable is already defined, and returns the address. If the variable is not defined, getAddress calls memallocate to allocate memory for the variable, and returns the address. Here is the definition of the functions :
static uint16_t memallocate(Machine *m, char *symbol){
uint16_t allocationAddress = getFirstFree(*m);
SymbolTable *newSymbol = (SymbolTable *)malloc(sizeof(SymbolTable));
newSymbol->symbolName = strdup(symbol);
newSymbol->next = NULL;
newSymbol->mema = allocationAddress;
if(m->symbolTable==NULL){
m->symbolTable = newSymbol;
}
else{
SymbolTable *temp = m->symbolTable;
while(temp->next!=NULL)
temp = temp->next;
temp->next = newSymbol;
}
m->memory[allocationAddress].acquired = 1;
m->memory[allocationAddress].data.value = 0;
m->occupiedAddress++;
return allocationAddress;
}
uint16_t getAddress(Machine *m, char *symbol){
SymbolTable *table = m->symbolTable;
while(table!=NULL){
if(strcmp(symbol, table->symbolName)==0){
return table->mema;
}
table = table->next;
}
uint16_t address = memallocate(m, symbol); // Here is the segfault happening
return address;
}
This code compiles and runs pretty well on Linux, but on Windows I'm getting a segfault on the memallocate call. Since memallocate is directly passed the arguments of getAddress, and the arguments both being a pointer, they shouldn't change. But while debugging through CLion, I'm seeing gibberish arguments to the memallocate call, which is indicating some kind of stack violation(may be). Again, it is ONLY happening in Windows. Can anybody tell me what is going wrong with my code?
Full code for the project can be found at GitHub.
I took your code and run it on linux through valgrind:
==13768== Conditional jump or move depends on uninitialised value(s)
==13768== at 0x109ABE: getAddress (in /home/vonaka/VirtualMachine/machine)
==13768== by 0x10B714: let (in /home/vonaka/VirtualMachine/machine)
==13768== by 0x109425: run (in /home/vonaka/VirtualMachine/machine)
==13768== by 0x109F64: main (in /home/vonaka/VirtualMachine/machine)
==13768== Uninitialised value was created by a heap allocation
==13768== at 0x4C2BE7F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd
==13768== by 0x109C2F: main (in /home/vonaka/VirtualMachine/machine)
==13768==
So (luckily for us) it's not a Windows specific problem. The trick is that on the first call of getAddress (when m->symbolTable is NULL) you call getFirstFree(*m) at the beginning of memallocate, but look at this function:
static uint16_t getFirstFree(Machine m) {
uint16_t add = 0;
while(m.memory[add].acquired)
add++;
return add;
}
m.memory[i].acquired for i between 0 and number_of_instructions_in_your_input_file - 1are all equal to 1 as you initialize them in writeInstruction, but m.memory[number_of_instructions_in_your_input_file].acquired is not initialized yet.
So something like this will resolve your problem:
void writeInstruction(Machine *m, uint16_t add, Instruction ins) {
m->memory[add].acquired = 1;
m->memory[add].type = INSTRUCTION;
m->memory[add].data.instruction = ins;
m->occupiedAddress++;
if(add + 1 < NUM_MEM)
m->memory[add + 1].acquired = 0;
}
Or maybe this is more elegant (if it's works):
static uint16_t getFirstFree(Machine m) {
uint16_t add = 0;
while (m.memory[add].acquired && add < m.occupiedAddress)
add++;
return add;
}
Edit:
First of all about your comment:
By default, the members of the structure is initialised as 0
It's just not true!
Now about why you have segfault without malloc and how it's connected with valgrind's warning.
You have variable m of type Machine and some other variables in the stack, m contains Cell memory[NUM_MEM] and there is acquired in each Cell (which are not initialized!). Your input file contains let's say 88 instructions, so first 88 acquired will be correctly initialized after 88 calls of writeInstruction. Then program start to execute your instructions by calling some functions including memallocate and getFirstFree. In this loop:
while(m.memory[add].acquired)
add++;
for any add m.memory[add].acquired very likely can be different from 0, so once add is equal to NUM_MEM you have segfault.
Why it's not happening with malloc? Simply because you are lucky (but it's not a good luck), your heap is 'cleaner' than stack. Why it's happening only in Windows? Because this time you were not so lucky (I don't have segfault even in Windows).
I have the code:
else if ((strtolnum=(strtol(&oldline[b+1],NULL,10)))>0)
{
char* excl = malloc(3*sizeof(char));
excl[0]=oldline[b];
excl[1]=oldline[b+1];
for (int j = 0; j<strtolnum; j++)
{
llist=llist->nextcmd;
}
struct token *p1;
struct token *save1 = llist->cmmd;
char *arra1 = malloc(sizeof(char));
memset(arra1, '\0', 1);
for (p1 = llist->cmmd; p1 != NULL; p1 = p1->next) {
arra = realloc(arra1, strlen(arra1)+strlen(p1->text)+2);
strcat(arra, p1->text);
if (p1->next!=NULL)
{
strcat(arra1, " ");
}// printing token and type
}
printf("%s excl\n", excl); //Line 137
oldline=strreplace(oldline,excl,arra1); //Line 138
llist->cmmd=save1;
for (int j = 0; j<(f-strtolnum); j++)
{
llist=llist->nextcmd;
}
*status=1;
size_t a = sizeof(excl);
memset(excl,'\0', a);
}
What the code should accomplish is get the first integer of a line which is preceded by an exclamation part, such as !3, and puts it in excl (and then do other stuff which is working perfectly fine).
However, when I run the loop more than once, I find that excl often has a random character at the end, such as when it shows up as "!3e" when I try to printf it. Valgrind shows the following errors:
==24878== Conditional jump or move depends on uninitialised value(s)
==24878== at 0x4E7AB5B: vfprintf (in /usr/lib64/libc-2.17.so)
==24878== by 0x4E83CD8: printf (in /usr/lib64/libc-2.17.so)
==24878== by 0x40130F: hExpand (Lex1.c:137)
==24878== by 0x400B6B: main (mainLex.c:27)
==24878==
==24878== Conditional jump or move depends on uninitialised value(s)
==24878== at 0x4C2B308: strlen (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==24878== by 0x4020D7: strreplace (Lex1.c:562)
==24878== by 0x40132C: hExpand (Lex1.c:138)
Apparently, excl is unititialized after the loop goes through once. What is wrong?
For additional information, cmmd is a data structure of type token, and llist is a global static data structure containing tokens.
You haven't null terminated the excl string; malloc() returns random garbage. You might think about adding:
excl[2] = '\0';
You also trample way out of bounds with:
size_t a = sizeof(excl);
memset(excl,'\0', a);
You assign either 4 or 8 (32-bit or 64-bit) to a, and then write over that many bytes, but you only allocated 3 bytes for excl.
The following code is part of a larger program, so I created a test file to try to isolate the problem. The code is working fully as intended, but it is throwing a valgrind error. From my understanding, I think it is most likely referring to *inputStr.
Valgrind error message:
==2807== Conditional jump or move depends on uninitialised value(s)
==2807== at 0x3156434819: ____strtol_l_internal (in /lib64/libc-2.5.so)
==2807== by 0x3156431BD1: atoi (in /lib64/libc-2.5.so)
==2807== by 0x400818: getInt (test.c:50)
==2807== by 0x4008B5: main (test.c:70)
==2807== Uninitialised value was created by a stack allocation
==2807== at 0x400668: getInt (test.c:13)
==2807==
==2807== Conditional jump or move depends on uninitialised value(s)
==2807== at 0x315643482F: ____strtol_l_internal (in /lib64/libc-2.5.so)
==2807== by 0x3156431BD1: atoi (in /lib64/libc-2.5.so)
==2807== by 0x400818: getInt (test.c:50)
==2807== by 0x4008B5: main (test.c:70)
==2807== Uninitialised value was created by a stack allocation
==2807== at 0x400668: getInt (test.c:13)
==2807==
==2807== Use of uninitialised value of size 8
==2807== at 0x31564348A8: ____strtol_l_internal (in /lib64/libc-2.5.so)
==2807== by 0x3156431BD1: atoi (in /lib64/libc-2.5.so)
==2807== by 0x400818: getInt (test.c:50)
==2807== by 0x4008B5: main (test.c:70)
==2807== Uninitialised value was created by a stack allocation
==2807== at 0x400668: getInt (test.c:13)
My code: Parses input command via stdin (e.g. "i 5"), the "i" would be used in a menu switch (but that code is removed), then calls getInt(), which starts scanning the inputStr at index 1 to parse the integer value from the inputStr. I have marked error lines 13, 50, and 70 as comments for clarity.
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
int getInt(char *inputStr, int *value, int *i) { // <-----line 13
char num[5];
int ctr = 0;
/* Skip whitespace */
while (!isdigit(*(inputStr+(*i))) && *(inputStr+(*i)) != '-') {
/* Input with only command letter and no integer value */
if (*(inputStr+(*i)) == '\n') {
//printError(-1);
return -1;
}
/* Input has invalid characters after command letter */
if (!isspace(*(inputStr+(*i)))) {
//printError(-2);
return -2;
}
(*i)++;
}
if (*(inputStr+(*i)) == '-') {
num[ctr++] = *(inputStr+(*i));
(*i)++;
}
/* Copy number characters to another array */
while (isdigit(*(inputStr+(*i)))) {
num[ctr++] = *(inputStr+(*i));
(*i)++;
}
/* Check if unwanted characters terminated the while loop above */
if (!isspace(*(inputStr+(*i)))) {
//printError(-2);
return -2;
}
/* Convert number characters to integer */
*value = atoi(num); // <----line 50
//printf("Positive Integer: num = %s, value = %d\n",num, value);
return 0;
}
int main () {
int value, i, int1;
char *inputStr;
size_t sizeInput = 10;
inputStr = malloc(sizeof(char) * sizeInput);
for (i = 0; i < sizeInput; i++)
inputStr[i] = '\0';
value = 0;
i = 1; //starting position for parsing number
getline(&inputStr, &sizeInput, stdin);
int1 = getInt(inputStr, &value, &i); // <---line 70
printf ("%d\n", value);
free(inputStr);
return 0;
}
Appreciate the help.
[Resolved] thanks to #JonathanLeffler. Added num[ctr] = '\0'; one line above the atoi() conversion. Now error free.
You have multiple errors:
getline return new memory by first parameter if the buffer is not large enough to hold the line, so you don't need allocate memory for inputStr, but you have to free it. You can just set inputStr to NULL, the getline will return new memory.
when you call function getInt, variable 'i' is initialize as 1; C/C++ array index starts with 0, so it should be 0, I don't know if you intend to pass 1 as the first.
in function getInt, the variable 'num' is not initialized if the while and if block are not excectuted, you can change it to:
char num[5] = {0};
Also in function getInt, no code to check if the string inputStr is already ended, so your loops may cause access violation.
I'm writing a simple program in C that finds anagrams of words based on looking them up in a hash table. What I have is an array of hash tables, where words are indexed by their length and hashed within by the summation of their letters, e.g. a = 1, b = 2, etc.
I'm still getting acquainted with dynamic memory management in C, so this question may be quite simple, but I have a functions that allocate and deallocate memory for each hash table (and its inside data).
I originally wrote this program using a single hash table and after running the program through valgrind I found that the memory had been freed correctly and there were no leaks. However, when expanding the program to use an array of hash tables, valgrind began to find possible leaks (though it's reporting them as still reachable). I'm confused as to why the memory isn't being freed correctly in the array of hash tables, although each hash table in the array is being run through the deallocate function that was used originally.
Gist with the full code Full Code
typedef struct Bucket Bucket;
typedef struct HashTable HashTable;
struct Bucket {
char* data;
Bucket *next;
};
struct HashTable {
int size;
Bucket **buckets;
};
int main(int argc, char const *argv[])
{
// Allocate memory for array of hash tables
HashTable** hash_array = (HashTable**) malloc(sizeof(HashTable*) * WORD_SIZE);
for(i = 0; i < WORD_SIZE; i++) {
hash_alloc(&hash_array[i], BUCKET_COUNT);
}
// Main logic here...
// Free memory
for(i = 0; i < WORD_SIZE; i++) {
hash_dealloc(hash_array[i]);
}
free(hash_array);
return 0;
}
Hash Table Allocation function
void hash_alloc(HashTable** a, unsigned int size) {
*a = (HashTable*) malloc(sizeof(HashTable));
(*a)->buckets = (Bucket**) malloc(sizeof(Bucket*) * size);
(*a)->size = size;
}
Hash Table Deallocation function
void hash_dealloc(HashTable* a) {
int i;
Bucket* current, *temp;
for(i = 0; i < a->size; i++) {
current = a->buckets[i];
while(current != NULL) {
temp = current;
free(temp->data);
current = current->next;
free(temp);
}
free(current);
}
free(a->buckets);
free(a);
}
Add to hash table function
void add_to_hash_array(HashTable** a, char* data) {
// Removed some other logic for readability...
replace_str(data, "\n", "\0");
newNode->data = strdup(data);
newNode->next = currentTable->buckets[index];
currentTable->buckets[index] = newNode;
} else {
return;
}
}
Valgrind output
==39817== 261,120 bytes in 128 blocks are still reachable in loss record 5 of 7
==39817== at 0x4C2B6CD: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==39817== by 0x400A38: hash_alloc (main.c:73)
==39817== by 0x4008B0: main (main.c:39)
==39817==
==39817== 286,936 bytes in 31,553 blocks are still reachable in loss record 6 of 7
==39817== at 0x4C2B6CD: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==39817== by 0x4EBAD71: strdup (strdup.c:43)
==39817== by 0x400D4D: add_to_hash_array (main.c:141)
==39817== by 0x400914: main (main.c:51)
==39817==
==39817== 504,848 bytes in 31,553 blocks are still reachable in loss record 7 of 7
==39817== at 0x4C2B6CD: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==39817== by 0x400D16: add_to_hash_array (main.c:136)
==39817== by 0x400914: main (main.c:51)
In generate_anagrams
void generate_anagrams(HashTable* a, char* word) {
int index = hash(word);
char* word_dup = strdup(word);
char* current_word;
string_sort(word_dup);
printf("%s: %i size: %zi\n", word, index, strlen(word));
Bucket* current = a->buckets[index];
while(current != NULL) {
if(current->data) {
current_word = strdup(current->data);
string_sort(current_word);
if(strcmp(word_dup, current_word) == 0) {
printf("%s\n", current->data);
}
}
current = current->next;
}
free(current_word);
free(word_dup);
}
you are leaking thestrduped current_words. Move the free(current_word); into the if (current->data).
In add_to_hash_array
void add_to_hash_array(HashTable** a, char* data) {
int index = hash(data);
HashTable* currentTable = a[strlen(data)];
Bucket* existingNode = hash_lookup(currentTable, data);
if(existingNode == NULL) {
Bucket *newNode = (Bucket*) malloc(sizeof(Bucket));
if(newNode == NULL) {
exit(1);
}
replace_str(data, "\n", "\0");
newNode->data = strdup(data);
newNode->next = currentTable->buckets[index];
currentTable->buckets[index] = newNode;
} else {
return;
}
}
You only remove the newline from data after you have looked it up, but you insert data after removing the newline, so you will not detect duplicates.
In main, you should not
generate_anagrams(hash_array[strlen(arg_dup) + 1], arg_dup);
but use hash_array[strlen(arg_dup)] if you remove the newline right at the beginning of add_to_hash_array.
And of course, you should ensure that hash generates no out-of-range indices.
And strncpy(str, str, p-str); is undefined behaviour.
Moving my comment to an answer because this nearly works.
No need to initialise to NULL before malloc, but any variable pointers that you later free should be set to NULL and only free if not NULL. Also initialise pointer values in your structs to NULL (easier to use calloc and get this automatically) so your guards work properly. I've had a bit more of look over your code and your hashing worries me - you need to make sure your hash function only returns values in the range 0 to BUCKET_COUNT-1. I made a few quick changes of this kind, and fixed your replace_str method and it no longer complains with valgrind.
Now when I run the code I see it finding the correct words to compare with, but the sorting function is not returning a sorted string, so it is not identifying the anagrams. Should be an easy fix.
Edit: I just pasted in the first string sort routine a google search found for me and ran to get the following output:
./a.out trips
trips: 82 size: 5
strip
stirp
sprit
spirt
Ther's no memory leak, but the code has some problems (the replace_str function need to be replaced by a correct version). The output of valgrind on my linux box:
$ valgrind --leak-check=full --show-reachable=yes ./MEMORY_LEAK absurde
==13476== Memcheck, a memory error detector
==13476== Copyright (C) 2002-2010, and GNU GPL'd, by Julian Seward et al.
==13476== Using Valgrind-3.6.1-Debian and LibVEX; rerun with -h for copyright info
==13476== Command: ./MEMORY_LEAK absurde
==13476==
==13476== Conditional jump or move depends on uninitialised value(s)
==13476== at 0x8048A9A: hash_lookup (MEMORY_LEAK.c:132)
==13476== by 0x80489BD: add_to_hash_array (MEMORY_LEAK.c:113)
==13476== by 0x804871C: main (MEMORY_LEAK.c:50)
==13476==
absurde: 70 size: 7
==13476== Conditional jump or move depends on uninitialised value(s)
==13476== at 0x8048D1C: generate_anagrams (MEMORY_LEAK.c:169)
==13476== by 0x8048795: main (MEMORY_LEAK.c:56)
==13476==
==13476== Conditional jump or move depends on uninitialised value(s)
==13476== at 0x8048890: hash_dealloc (MEMORY_LEAK.c:81)
==13476== by 0x80487D8: main (MEMORY_LEAK.c:64)
==13476==
==13476== Conditional jump or move depends on uninitialised value(s)
==13476== at 0x4027BC2: free (vg_replace_malloc.c:366)
==13476== by 0x804889C: hash_dealloc (MEMORY_LEAK.c:87)
==13476== by 0x80487D8: main (MEMORY_LEAK.c:64)
==13476==
==13476==
==13476== HEAP SUMMARY:
==13476== in use at exit: 0 bytes in 0 blocks
==13476== total heap usage: 360 allocs, 360 frees, 133,424 bytes allocated
==13476==
==13476== All heap blocks were freed -- no leaks are possible
==13476==
==13476== For counts of detected and suppressed errors, rerun with: -v
==13476== Use --track-origins=yes to see where uninitialised values come from
==13476== ERROR SUMMARY: 65330 errors from 4 contexts (suppressed: 11 from 6)