Valgrind and STL lists

Posted by Greven on Mon 26 Sep 2005 05:17 AM — 3 posts, 17,860 views.

Canada #0
We have been having some really wierd errors on our mud, so we want to valgrind to try to find some data corruption. To make the output close to usable, I have been using code to clean all memory that has been allocated, then booting and shutting down right away. I have been able to fix most issues with it, except for some error about conditional jumps in deflate and get_hostbyname, but I have a few that I can't figure out:
bool RACE_DATA::load_race_file(char *racefile)
{
        char filename[256];
        RACE_DATA *race;

        FILE     *fp;

        snprintf(filename, 256, "%s%s", RACES_DIR, racefile);

        if ((fp = fopen(filename, "r")) != NULL)
        {
                for (;;)
                {
                        char letter;
                        char     *word;

                        letter = fread_letter(fp);
                        if (letter == '*')
                        {
                                fread_to_eol(fp);
                                continue;
                        }

                        if (letter != '#')
                        {
                                bug("Load_race_file: # not found.", 0);
                                break;
                        }

                        word = fread_word(fp);
                        if (!str_cmp(word, "RACE"))
                        {
                                race = new RACE_DATA;
                                race->load(fp);
                                races.push_back(race); /* Line 309 */
                                break;
                        }
                        else if (!str_cmp(word, "END"))
                                break;
                        else
                        {
                                bug("Load_race_file: bad section: %s.", word);
                                break;
                        }
                }
                FCLOSE(fp);
                return TRUE;
        }
        return FALSE;
}

And I am getting this error:
==22665== 20 bytes in 5 blocks are still reachable in loss record 2 of 10
==22665==    at 0x1B904727: operator new(unsigned) (vg_replace_malloc.c:132)
==22665==    by 0x1B9A0EC1: __gnu_cxx::__pool<true>::_M_initialize(void (*)(void*)) (in /usr/lib/libstdc++.so.6.0.5)
==22665==    by 0x80757E8: __gnu_cxx::__common_pool_policy<__gnu_cxx::__pool, true>::_S_initialize() (mt_allocator.h:472)
==22665==    by 0x8073E28: __gnu_cxx::__pool<true>::_M_initialize_once(void (*)()) (mt_allocator.h:332)
==22665==    by 0x807510E: __gnu_cxx::__common_pool_policy<__gnu_cxx::__pool, true>::_S_initialize_once() (mt_allocator.h:460)
==22665==    by 0x81B8FC6: __gnu_cxx::__mt_alloc<std::_List_node<RACE_DATA*>, __gnu_cxx::__common_pool_policy<__gnu_cxx::__pool, true> >::allocate(unsigned, void const*) (mt_allocator.h:693)
==22665==    by 0x81B90F1: std::_List_base<RACE_DATA*, std::allocator<RACE_DATA*> >::_M_get_node() (stl_list.h:312)
==22665==    by 0x81B910A: std::list<RACE_DATA*, std::allocator<RACE_DATA*> >::_M_create_node(RACE_DATA* const&) (stl_list.h:437)
==22665==    by 0x81B9167: std::list<RACE_DATA*, std::allocator<RACE_DATA*> >::_M_insert(std::_List_iterator<RACE_DATA*>, RACE_DATA* const&) (stl_list.h:1151)
==22665==    by 0x81B91B2: std::list<RACE_DATA*, std::allocator<RACE_DATA*> >::push_back(RACE_DATA* const&) (stl_list.h:773)
==22665==    by 0x81B87D1: RACE_DATA::load_race_file(char*) (races.c:309)
==22665==    by 0x81B89A1: RACE_DATA::load_races() (races.c:367)
==22665==    by 0x81230C1: boot_db(bool) (db.c:942)
==22665==    by 0x810AEA9: main (comm.c:344)

==22665== 120 bytes in 1 blocks are still reachable in loss record 7 of 10
==22665==    at 0x1B904727: operator new(unsigned) (vg_replace_malloc.c:132)
==22665==    by 0x81B878B: RACE_DATA::load_race_file(char*) (races.c:307)
==22665==    by 0x81B89A1: RACE_DATA::load_races() (races.c:367)
==22665==    by 0x81230C1: boot_db(bool) (db.c:942)
==22665==    by 0x810AEA9: main (comm.c:344)
Now, does this mean that I am putting bad data into the list, or that maybe I'm not traversing the whole list to free it? Any insight would be great.
Amended on Mon 26 Sep 2005 05:44 AM by Greven
USA #1
Tossed my code into the grinder again now that you brought this up, and decided to play a baseless hunch. Here's some of what I got on a clean shutdown:

==19215== 334560 bytes in 82 blocks are still reachable in loss record 5 of 5
==19215== at 0x1B904C1E: operator new(unsigned) (vg_replace_malloc.c:164)
==19215== by 0x1B9BC02E: __gnu_cxx::__pool<true>::_M_reserve_block(unsigned, unsigned) (in /usr/lib/libstdc++.so.6.0.5)
==19215== by 0x1B9BC9A0: (within /usr/lib/libstdc++.so.6.0.5)
==19215== by 0x1BA0738C: std::string::_Rep::_S_create(unsigned, unsigned, std::allocator<char> const&) (in /usr/lib/libstdc++.so.6.0.5)
==19215== by 0x1BA0B41E: (within /usr/lib/libstdc++.so.6.0.5)
==19215== by 0x1BA0C03B: std::string::string(char const*, std::allocator<char> const&) (in /usr/lib/libstdc++.so.6.0.5)
==19215== by 0x814B810: main (comm.c:1265)

comm.c:1265 =
if( !is_number( argv[1] ) )

Now in this particular case I had is_number accepting only a std::string for an argument. It hit me that I might want to put back the const char* version to see how it reacted.

The leak report disappeared as soon as I put back the second version of is_number. So this leads me to beleive Valgrind considers the char->string promotion to be some form of memory leak. It's probably right since it would convert it on the fly into a std::string which would have to involve some sort of memory thing. I reground the code and came back with a different error, causes in a similar manner due to there only being one version of the function with std::string parameters being accepted.

Perhaps you are running into a similar situation here? No idea what your race->load() function looks like but you might check it for weirdness like this.
USA #2
I see what you're getting at now:

==20274== 338640 bytes in 83 blocks are still reachable in loss record 4 of 4
==20274== at 0x1B904C1E: operator new(unsigned) (vg_replace_malloc.c:164)
==20274== by 0x1B9BC02E: __gnu_cxx::__pool<true>::_M_reserve_block(unsigned, unsigned) (in /usr/lib/libstdc++.so.6.0.5)
==20274== by 0x80B278C: std::_List_base<shell_cmd*, std::allocator<shell_cmd*> >::_M_get_node() (stl_list.h:312)
==20274== by 0x80B27A2: std::list<shell_cmd*, std::allocator<shell_cmd*> >::_M_create_node(shell_cmd* const&) (stl_list.h:437)
==20274== by 0x80B2809: std::list<shell_cmd*, std::allocator<shell_cmd*> >::_M_insert(std::_List_iterator<shell_cmd*>, shell_cmd* const&) (stl_list.h:1151)
==20274== by 0x80B283A: std::list<shell_cmd*, std::allocator<shell_cmd*> >::push_back(shell_cmd* const&) (stl_list.h:773)
==20274== by 0x80B1650: add_shellcommand(shell_cmd*) (shell.c:925)
==20274== by 0x80B1E5F: fread_shellcommand(_IO_FILE*, int) (shell.c:1006)
==20274== by 0x80B219A: load_shellcommands() (shell.c:1135)
==20274== by 0x81592BB: boot_db(bool) (db.c:1908)

Line 925:
shellcmdlist.push_back( command );

I've poured over the code in my case and can't really figure on why this should get reported.

BTW - About the uninitialized stuff for deflate, there's not much you can do about that. Best bet would be to set a suppression file to stop it from reporting on zlib stuff.