0

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;
    }
1

The problem is because you're allocating the wrong size for root

root = malloc(sizeof(root));

the size of root is typically 4 bytes on 32-bit systems. You actually need to allocate sizeof node which is typically 1 (for is_word) + 27 * 4 (for children) + 3 (padding) = 112 bytes.

1
  • That was it! Just goes to show how easy it is to make a simple mistake and not be able to see it at all! THANK YOU! I just wasn't seeing it, but knew I was dancing all around it! – Cliff B Mar 25 '15 at 3:18

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .