Thread: C array/malloc/free problem

  1. #1
    Registered User
    Join Date
    Oct 2007
    Posts
    3

    C array/malloc/free problem

    Hi all,

    Apologies for covering old ground AGAIN... I'm having trouble with a 2D array, pointers, malloc and free (a classic combo). I'm getting a variety of core dumps when running the code below... can anyone spot the problem?

    The core dumps are for reasons such as: "free(): invalid next size (fast)". So I guess I'm freeing something I shouldn't be, or corrupting something with overflow. Help!

    Firstly, I have declared the structures in my software as follows:
    Code:
    typedef struct waitingtype {
            char* sym_name;
            char* bulk_name;
            char** alloc_names;
            int alloc_count;
    } port_wait_struct;
    
    typedef struct maptype {
            port_wait_struct** waiting_ports;
            int waiting_count;
    
    /* Other stuff here, removed to avoid confusion */
    } global_structure;
    I am creating the initial pointer as follows:
    Code:
    global_structure* bulks;
            bulks = (global_structure*)malloc(sizeof(global_structure));
            bulks->waiting_ports = NULL;
            bulks->waiting_count = 0;
    The problematic code follows (by the time I get here, I have char arrays param1, param2 and param3 which are all less than 256 characters and are null terminated) :

    Code:
            int found=-1;
            for( int i=0; i<bulks->waiting_count; i++ )
            {
                    if( strcmp( bulks->waiting_ports[i]->bulk_name, param1 ) == 0 )
                    {
                            found = i;
                    }
            }
    
            if( found == -1 )
            {
                    found = bulks->waiting_count;
                    port_wait_struct** new_struct = (port_wait_struct**)malloc( found * sizeof(port_wait_struct*) );
    
                    // Only copy old values across if there were any
                    if( bulks->waiting_count > 0 )
                    {
                            for( int i=0; i<bulks->waiting_count; i++ )
                            {
                                    new_struct[i] = bulks->waiting_ports[i];
                            }
                    }
    
                    // Put our new value on the end.
                    new_struct[found] = (port_wait_struct*)malloc( sizeof( port_wait_struct ) );
                    new_struct[found]->bulk_name = (char*)malloc( 256 * sizeof(char) );
                    new_struct[found]->sym_name = (char*)malloc( 256 * sizeof(char) );
    
                    strncpy( new_struct[found]->bulk_name, param1, 256 );
                    new_struct[found]->bulk_name[256 - 1] = '\0';
                    strncpy( new_struct[found]->sym_name, param3, 256 );
                    new_struct[found]->sym_name[256 - 1] = '\0';
    
                    new_struct[found]->alloc_count = 0;
                    new_struct[found]->alloc_names = NULL;
    
                    // Free old one and put our new one in its place.
                    if( bulks->waiting_ports NEQ NULL )
                    {
                            free( bulks->waiting_ports );
                    }
                    bulks->waiting_ports = new_struct;
                    bulks->waiting_count++;
    
            }
    
            // By here we have a 'found' value, whether it's a new one or an
            // old one.  We need to add ourselves onto the list of names.
            int old_count = bulks->waiting_ports[found]->alloc_count;
            char** new_names = (char**)malloc( (old_count+1) * sizeof(char*) );
    
            // Copy old ones across if there were any.
            if( old_count > 0 )
            {
                    for( int i=0; i<old_count; i++ )
                    {
                            new_names[i] = bulks->waiting_ports[found]->alloc_names[i];
                    }
            }
    
            new_names[old_count] = (char*)malloc( 256 * sizeof(char) );
            strcpy( new_names[old_count], param2 );
    
            free( bulks->waiting_ports[found]->alloc_names );
            bulks->waiting_ports[found]->alloc_names = new_names;
            bulks->waiting_ports[found]->alloc_count++;
    It's supposed to be an implementation of a map of char-arrays to 'lists' of other char-arrays. param1 is the 'key' and param2 is the char-array to be stored in the 'list'. param3 is kind of irrelevent, but needs to be stored beside the 'key'.

    It core dumps if I run the problematic chunk as a function with a whole bunch of test data, and it varies how far through the test data I get.

    Help! Much appreciated!

  2. #2
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    It seems to me that your job would be a lot easier if you used realloc().

    Anyway, I think this is your problem.
    Code:
    port_wait_struct** new_struct = (port_wait_struct**)malloc( found * sizeof(port_wait_struct*) );
    Since you soon afterwards access new_struct[found], you likely want (found+1):
    Code:
    port_wait_struct** new_struct = (port_wait_struct**)malloc( (found + 1) * sizeof(port_wait_struct*) );
    Oh, and you might want to consider not casting *alloc().
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  3. #3
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    If you are running on Linux... Valgrind, Valgrind, Valgrind. It will spit out the EXACT LINE NUMBER where the bug occurs.

  4. #4
    Registered User
    Join Date
    Oct 2007
    Posts
    3
    By Jove dwks, you've got it! If I could hug you, I would.

    One more question, you say "you might want to consider not casting *alloc()"... what alternatives are there?

  5. #5
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Quote Originally Posted by Weasel View Post
    One more question, you say "you might want to consider not casting *alloc()"... what alternatives are there?
    If your code is C (rather than C++), then the return type from malloc() [and friends] is void *, which according to the C standard is compatible with any other type of pointer, so for example, using
    Code:
    int *p;
    
    p = malloc(10);
    works just fine without warnings.

    Not putting a cast in there will tell you when you have forgotten to include <stdlib.h>, and thus not got a declaration on malloc - this could lead to mysterious problems in some systems (because some compilers will return pointers in a different type of register than integer values, and if you don't get the declaration of malloc included, it may think that it returns an integer).

    If you are using C++ to compile your code (e.g. your file is called xxx.cpp rather than xxx.c), then you should probably consider using new and delete rather than malloc.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  6. #6
    Registered User
    Join Date
    Oct 2007
    Posts
    3
    I see your point. Thanks for the explanation.

    I'm using C, so I'm stuck with malloc and free!

    Thanks again,
    Weasel

  7. #7
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Quote Originally Posted by Weasel View Post
    I see your point. Thanks for the explanation.

    I'm using C, so I'm stuck with malloc and free!

    Thanks again,
    Weasel
    Nothing wrong with C. Just different from C++.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Memory problem with Borland C 3.1
    By AZ1699 in forum C Programming
    Replies: 16
    Last Post: 11-16-2007, 11:22 AM
  2. Someone having same problem with Code Block?
    By ofayto in forum C++ Programming
    Replies: 1
    Last Post: 07-12-2007, 08:38 AM
  3. A question related to strcmp
    By meili100 in forum C++ Programming
    Replies: 6
    Last Post: 07-07-2007, 02:51 PM
  4. WS_POPUP, continuation of old problem
    By blurrymadness in forum Windows Programming
    Replies: 1
    Last Post: 04-20-2007, 06:54 PM
  5. beginner problem
    By The_Nymph in forum C Programming
    Replies: 4
    Last Post: 03-05-2002, 05:46 PM