I'm stumped! In dictionary.c I have coded the load function (with more code that follows the bug, but not needed for this question.) One small block of code is producing a problem! Assigning NULL to a pointer is producing an error that only shows up in valgrind. Every malloc that follows it will then fail in gdb.
Two questions:
1.) Why is the NULL assignment failing? What is bad about the assignment code? Why is it writing 4 bytes beyond the end of a block of size 4... what, the pointer? Could it be because my computer is a 64 bit machine? ( a 4-byte overwrite is 32 bits.)
2.) Why is this causing subsequent malloc commands to fail?
The line that is causing the grief is this:
for(int i = 0; i < 27; i++)
{
root->children[i] = NULL; // HERE IS THE PROBLEM CODE!!!!!!
}
The error I get is this:
66 char* buf = malloc(46);
(gdb) n
speller: malloc.c:2372: sysmalloc: Assertion `(old_top == (((mbinptr) (((char *) &((av)->bins[((1) - 1) * 2])) - __builtin_offsetof (struct malloc_chunk, fd)))) && old_size == 0) || ((unsigned long) (old_size) >= (unsigned long)((((__builtin_offsetof (struct malloc_chunk, fd_nextsize))+((2 *(sizeof(size_t))) - 1)) & ~((2 *(sizeof(size_t))) - 1))) && ((old_top)->size & 0x1) && ((unsigned long) old_end & pagemask) == 0)' failed.
In another experiment, I replaced the loop with multiple individual lines to assign each pointer to NULL. I discovered that as little as 3 assignments will produce the same failure.
// replacing the FOR loop with these 3 lines will cause the same problem.
root->children[0] = NULL;
root->children[1] = NULL;
root->children[2] = NULL;
Even with only one or two of the above lines, valgrind tells me the following about each one:
==29464== at 0x8048F3D: load (dictionary.c:67)
==29464== by 0x8048695: main (speller.c:45)
==29464== Address 0x41f51bc is 0 bytes after a block of size 4 alloc'd
==29464== at 0x402A17C: malloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==29464== by 0x8048F25: load (dictionary.c:58)
==29464== by 0x8048695: main (speller.c:45)
So, I know where the problem is, but I have no idea what the problem is!! Can anyone clue me in? Here is a more complete block of code that can be plugged into your dictionary.c file if you'd like to experiment.It contains only the code needed to duplicate the problem. (If you can't dupe the problem, let me know.)
#include <stdbool.h>
#include <ctype.h>
#include <stdlib.h>
#include <stdio.h>
#include "dictionary.h"
typedef struct node
{
bool is_word;
struct node* children[27];
}
node;
node* root;
bool load(const char* dictionary)
{
FILE* dict = fopen(dictionary, "r");
if (dict == NULL)
{
printf("Could not open %s.\n", dictionary);
return false;
}
root = malloc(sizeof(root));
root->is_word = false;
for(int i = 0; i < 27; i++)
{
root->children[i] = NULL; // HERE IS THE PROBLEM CODE!!!!!!
}
char* buf = malloc(46); // it will cause this to fail.
buf = "TEST";
fclose(dict);
return true;
}