1

I'm currently tinkering with binary trees in C, but I've run into an issue that I can't seem to solve on my own. I'm using Eclipse Mars as my IDE.

The basic idea of the project is to have a binary tree composed out of treeNodes. These nodes are structs and contain a struct within (struct Books), thus there are two separate libs for treeNode and books.

These are the structs in question:

TreeNode:

struct TreeNode {
    struct Book *book;
    unsigned long key;
    struct TreeNode *left;
    struct TreeNode *right;
};

Book:

struct Book {
    unsigned long ISBN;
    char* author_name;
    char* book_title;
};    

Now, the nodes get created fine and the insertion/print functions work well. However, I also have a clear() function, that is supposed to free any previously allocated memory. Malloc is called only in the new_xxx() functions:

struct TreeNode *new_tree_node(unsigned long ISBN, char *author, char *title) {
    //Creating and allocating the new TreeNode
    struct TreeNode *new_tree_node;
    new_tree_node = (struct TreeNode*) malloc(sizeof(struct TreeNode));

    //Creating the book
    struct Book *new_Book = newBook(ISBN, author, title); 

    new_tree_node->book = new_Book;

    new_tree_node->left = NULL;
    new_tree_node->right = NULL;

    new_tree_node->key = ISBN;

    return new_tree_node;
}

And newBook():

struct Book *newBook(unsigned long ISBN_nr, char *author_name, char *book_title) {
    //Creating and allocating the Book
    struct Book *new_Book;
    new_Book = (struct Book*) malloc(sizeof(struct Book));

    //Assigning Values
    new_Book->ISBN = ISBN_nr;
    new_Book->author_name = author_name;
    new_Book->book_title = book_title;

    return new_Book;
}

Now, when I try to run the clear() function, I receive a "SIGABRT:Aborted" signal as soon as I try to free a TreeNode and the process halts. Eclipse also returns:

"No source available for "raise() at 0x75ffff7a4bcc9".

Initially I thought this happened because my system could not find one of the standard functions, but the console also prints:

*** Error in /home/max/workspace/bst_2/Debug/bst_2': double free or corruption (out): 0x00007fffffffe030 ***

which makes me believe that there actually is an issue within the code.

This is the function in question:

void bst_clear(struct TreeNode *tree_node) {
    //Clears all nodes recursively
    if (tree_node->left != NULL) {
        bst_clear(tree_node->left);
    }
    if (tree_node->right != NULL) {
            bst_clear(tree_node->right);
    }

    tree_node->key = NULL;
    tree_node->book = NULL;

    free((void*) tree_node);
    return;
}

Funny thing is, this does only happen while using a Linux OS (Mint 17.1) - both in a VM and as a dual-boot system. My main OS, which is Windows 7 64-bit, does compile and run without any issues and gets through the process entirely.

I am not sure whether something is actually wrong with the code (which could definitely be the case, I'm still a newbie) or whether my OS did mess something up there. But since this happened both in a VM and an actual system, it probably has nothing to do with missing system libraries (I guess).

So, does anyone have a clue on what's going on here?

EDIT: valgrind output:

==2946== Invalid free() / delete / delete[] / realloc()
==2946==    at 0x4C2BDEC: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==2946==    by 0x4008D3: bst_clear (booktree.c:84)
==2946==    by 0x400884: bst_clear (booktree.c:73)
==2946==    by 0x400884: bst_clear (booktree.c:73)
==2946==    by 0x400D17: main (main.c:66)
==2946==  Address 0xfff000030 is on thread 1's stack
==2946== 
==2946== Invalid free() / delete / delete[] / realloc()
==2946==    at 0x4C2BDEC: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)

...

==2946== 
==2946== 
==2946== HEAP SUMMARY:
==2946==     in use at exit: 128 bytes in 4 blocks
==2946==   total heap usage: 10 allocs, 10 frees, 280 bytes allocated
==2946== 
==2946== LEAK SUMMARY:
==2946==    definitely lost: 128 bytes in 4 blocks
==2946==    indirectly lost: 0 bytes in 0 blocks
==2946==      possibly lost: 0 bytes in 0 blocks
==2946==    still reachable: 0 bytes in 0 blocks
==2946==         suppressed: 0 bytes in 0 blocks
==2946== Rerun with --leak-check=full to see details of leaked memory

The error appeared multiple times - the line in question is the free() command - line 73 is just the recursive function call.

Now, if I got this right, I'm trying to free an object in the stack - read-only memory, right? The only thing I can think of are the struct declarations, which contain possibly static elements?

I'd also like to point out, that there is ZERO issue when running this on a Windows machine - does anyone know the reason for this?

EDIT 2:

This is how nodes are created:

char* root_author;
char* root_title;
root_author = "A B C\0";
root_title = "ABC\0";
struct TreeNode *root;
root = new_tree_node(579610, root_author, root_title);

char* n1a;
char* n1t;
n1a = "B C D";
n1t = "BCD";
struct TreeNode *n1 = new_tree_node(406759, n1a, n1t);
bst_insert(root, n1);

And this is the insert() function:

   void bst_insert(struct TreeNode *tree_node, struct TreeNode *new_node) {
    if (new_node->key < tree_node->key) {
        //If the key is smaller -> insert left
        if (tree_node->left == NULL) {
            //There is no left node yet
            tree_node->left = new_node;
            return;
        } else
            bst_insert(tree_node->left, new_node); //There is a node -> pass it on
    }

    else {
        //The key is larger -> right
        if (tree_node->right == NULL) {
            //There is no left node yet
            `enter code here`tree_node->right = new_node;
                return;
            } else
                bst_insert(tree_node->right, new_node); //There is a node -> pass it on
        }
    }
Thomas Dickey
  • 51,086
  • 7
  • 70
  • 105
Thane
  • 11
  • 3
  • 1
    Please [see why not to cast](http://stackoverflow.com/q/605845/2173917) the return value of `malloc()` and family in `C`. – Sourav Ghosh Jul 09 '15 at 14:22
  • First build a *debug* version of the code, that will include symbols. Then learn to use tools such as [Valgrind](http://valgrind.org/) which will help you catch memory access problems. – Some programmer dude Jul 09 '15 at 14:25
  • Also, after building a small tree, one that causes this behavior, then try to make sure you don't have any unexpected loops in the tree, or some child not pointing to another node already in the tree. – Some programmer dude Jul 09 '15 at 14:27
  • 1
    Run you program in `valgrind`. It will explicitly tell you what line of code is wrong. And `double free`, generally means that you are calling `free` multiple times on the same pointer. – Šimon Tóth Jul 09 '15 at 14:36
  • 2
    Like this, you're leaking the memory for `key` and `book`. Why are they pointers in the first place? Apart from that, the snippets shown look good, so as already pointed out, use something like `valgrind` –  Jul 09 '15 at 14:41
  • TreeNode's key member - pointer or not? new_tree_node assigns an unsigned long to key, instead of unsigned long *. I also suspect we're missing some interesting parts of the story not seeing tree manipulation steps: how nodes are inserted into this binary tree matters, and would be a place to create two references to allocated memory. Voted for comments recommending giving `valgrind` a try. – sjnarv Jul 09 '15 at 15:42
  • @Sourav Gosh Thanks for the tip, going to check it out! – Thane Jul 09 '15 at 16:01
  • @sjnarv key is not a pointer, that was just a typo – Thane Jul 09 '15 at 16:03
  • Your valgrind summary is useful, but looks like a run against code not quite the same as what you've included here. Take valgrind at its word and run it with --leak-check=full to see more about leaked blocks (I suspect not freeing the memory pointed to by "book" is what's going on there). You're sure there's no use of a stack-allocated TreeNode as an argument to bst_insert? Can you run this outside of the IDE and see the same results (run gcc and valgrind out in the shell)? – sjnarv Jul 09 '15 at 16:39
  • This must be a case of buffer overflow and while freeing, the memory allocated cannot be properly dealloacted. And yes, this issue will not occur on all the systems (depends on heap allocater). – Pawan Jul 10 '15 at 11:51

0 Answers0