Click here to Skip to main content
15,879,474 members
Please Sign up or sign in to vote.
1.89/5 (2 votes)
Hi,
I am getting a memory leak while running unit test in C++.
You can see definition of the function, and the map used by this function which casuses unit test memory leak;

C#
const char* myMap [] =
{
     "INPUT1"        ,           "OUTPUT1",
     "INPUT2"        ,           "OUTPUT2",
     "INPUT3"        ,           "OUTPUT3",
     "INPUT4"        ,           "OUTPUT4",
     "INPUT5"        ,           "OUTPUT5",
     "INPUT6"        ,           "OUTPUT6",
     "INPUT7"        ,           "OUTPUT7",
     "INPUT8"        ,           "OUTPUT8",
     "INPUT9"        ,           "OUTPUT9",
     "INPUT10"       ,           "OUTPUT10",
     "THE_END"
};

const std::string Class::translateInput( const std::string& tag )
{
 static bool initialized = false;
 static map<std::string, std::string> m;
 if (!initialized)
 {
  initialized = true;
  unsigned long i = 0;
  static const std::string s = "THE_END";

  while( s != myMap[i])
  {
    std::string key = myMap[i];
    printf("\n 1. key is set to %s \n", myMap[i] );
    printf("\n m[ key ] is set to %s \n", myMap[i+1] );
    m[ key ] = myMap[i+1];
    i+=2;
   };
 }



Here is the output of valgrind :

Block size: 29, Address: 0x5f40f44, Back Trace:
2. /usr/lib/i386-linux-gnu/libstdc++.so.6(std::string::_Rep::_S_create(unsigned int, unsigned int, std::allocator<char> const&)) [0x455f7d4]
3. /usr/lib/i386-linux-gnu/libstdc++.so.6(std::string::_M_mutate(unsigned int, unsigned int, unsigned int)) [0x455fab4]
4. /usr/lib/i386-linux-gnu/libstdc++.so.6(std::string::_M_replace_safe(unsigned int, unsigned int, char const*, unsigned int)) [0x455fc42]
5. /usr/lib/i386-linux-gnu/libstdc++.so.6(std::string::assign(char const*, unsigned int)) [0x455fcf9]
6. /usr/lib/i386-linux-gnu/libstdc++.so.6(std::string::operator=(char const*)) [0x455ff06]
7. MyClass::translateInput(std::string const&)) [0x43025c8]


And it indicates the line where string assignment is made as the following ;

m[ key ] = myMap[i+1];

I've put traces before, and after this line. And there is no error while making assignment after initialization. After the unit test is teared down, it gives the above output.

I have no idea about the cause of memory leak. As you can also see, there is no pointer, or memory initialization in the function. And When I put the correct output of this function( translateInput ) manually ( by commenting out the call of function ), there is no leak. Whenever I use this function, I get the memory leak I mentioned above.

P.S: All members and functions of this class, MyClass, is static.

Could you please help about the possible reasons which cause memory leak in this state ?
Thanks in advance,
Cranberries
Posted
Updated 25-Oct-15 11:43am
v4

Why your function doesn't return a std::string (as it should)?
What's the purpose of the std::map (or, better, what's the purpose of myMap while you can use a std::map?)?
 
Share this answer
 
Comments
creanberries__87 25-Oct-15 17:59pm    
Hi,
Firstly, thanks for your time and reply. I've just found the cause of leak. The problem is about that the map is static. The class I mentioned, MyClass is a static class, all members of it are static. And this event, translateInfo is called in lots of places, in another non-static class( MyNonStaticClass ). I am not sure but,I suppose, when I called translateString, it adds std::string type variables, and also references to the class(MyNonStaticClass) which uses MyClass::translateString.
When the object of MyNonStaticClass is destroyed, the reference which is hold by static map, is not released. Could you please share your comments about the exact cause of it ?
CPallini 26-Oct-15 4:07am    
I do think the static map is released (as it should).
Why didn't you answer my questions?
creanberries__87 26-Oct-15 6:26am    
I've tried your way, but it didn't resolve the memory leak.
CPallini 26-Oct-15 6:54am    
There is not 'my way'.
Your function is not returning a std::string (as it should). And what is the purpose of your map whend you could use std::map instead?
To me the code does not look ready for unit testing.

http://stackoverflow.com/questions/2931704/how-to-compare-string-with-const-char[^]

C++
while( s != myMap[i])
 
Share this answer
 
v2
Comments
creanberries__87 24-Oct-15 10:53am    
I'2 tried the way you suggested as the following but it didn't worked ;

while( strcmp( s.c_str(), myMap[i] ) != 0 )
// while( s != myMap[i])


By the way, I've examined the output of unit test run. It gives the following error in some places ;

Block size: 28, Address: 0x688d514, Back Trace:
2. Tests(__gnu_cxx::new_allocator<std::_rb_tree_node<std::pair<std::string const,="" std::string=""> > >::allocate(unsigned int, void const*)) [0x806db1e]
3. Tests(std::_Rb_tree<std::string, std::pair<std::string="" const,="" std::string="">, std::_Select1st<std::pair<std::string const,="" std::string=""> >, std::less<std::string>, std::allocator<std::pair<std::string const,="" std::string=""> > >::_M_get_node()) [0x806da43]
4. Tests(std::_Rb_tree<std::string, std::pair<std::string="" const,="" std::string="">, std::_Select1st<std::pair<std::string const,="" std::string=""> >, std::less<std::string>, std::allocator<std::pair<std::string const,="" std::string=""> > >::_M_create_node(std::pair<std::string const,="" std::string=""> const&)) [0x806d96a]
5. Tests(std::_Rb_tree<std::string, std::pair<std::string="" const,="" std::string="">, std::_Select1st<std::pair<std::string const,="" std::string=""> >, std::less<std::string>, std::allocator<std::pair<std::string const,="" std::string=""> > >::_M_insert_(std::_Rb_tree_node_base const*, std::_Rb_tree_node_base const*, std::pair<std::string const,="" std::string=""> const&)) [0x806d67a]
6. Tests(std::_Rb_tree<std::string, std::pair<std::string="" const,="" std::string="">, std::_Select1st<std::pair<std::string const,="" std::string=""> >, std::less<std::string>, std::allocator<std::pair<std::string const,="" std::string=""> > >::_M_insert_unique_(std::_Rb_tree_const_iterator<std::pair<std::string const,="" std::string=""> >, std::pair<std::string const,="" std::string=""> const&)) [0x806d2bc]
7. Tests(std::map<std::string, std::string,="" std::less<std::string="">, std::allocator<std::pair<std::string const,="" std::string=""> > >::insert(std::_Rb_tree_iterator<std::pair<std::string const,="" std::string=""> >, std::pair<std::string const,="" std::string=""> const&)) [0x806cfb2]
8. Tests(std::map<std::string, std::string,="" std::less<std::string="">, std::allocator<std::pair<std::string const,="" std::string=""> > >::operator[](std::string const&)) [0x806ca94]
9. MyClass::translateInput(std::string const&)) [0x430267c]

Do you have any comment about this ?

Thanks in advance,
Cranberries
[no name] 24-Oct-15 11:06am    
I am not going to write your program. I just pointed out the first error I found. Forget unit testing, the code doesn't work. Get out the debugger or use assert.
Your memory leak isn't a real memory leak.

Most heap checking tools will report a program like the following as having a leak.
C++
#include <stdio.h>

static char *leaks;

int main(int argc, char *argv[])
{
    leaks = strdup("leaked data");
    puts(leaks);
    return 0;
}


If it is allocated once - like a singleton - and is needed for the life of the application, there's no real need to reclaim it. The OS will reclaim the memory for you.

If you are concerned by the clutter caused in your heap reporting tool, you can add code to free these at program exit:

C++
#include <stdio.h>

static char *leaks;

int main(int argc, char *argv[])
{
    leaks = strdup("leaked data");
    puts(leaks);
    free(leaks);
    return 0;
}


As a side note, avoid using sentinel values when they aren't necessary. The countof operator will tell you how many items are in an array. Example:

C++
const char* myMap [] =
{
     "INPUT1"        ,           "OUTPUT1",
     "INPUT2"        ,           "OUTPUT2",
     "INPUT3"        ,           "OUTPUT3",
     "INPUT4"        ,           "OUTPUT4",
     "INPUT5"        ,           "OUTPUT5",
     "INPUT6"        ,           "OUTPUT6",
     "INPUT7"        ,           "OUTPUT7",
     "INPUT8"        ,           "OUTPUT8",
     "INPUT9"        ,           "OUTPUT9",
     "INPUT10"       ,           "OUTPUT10"
     // omit this: "THE_END"
};

for (size_t i = 0; i < countof(myMap); i++)
{
    const char *map = myMap[i];
    // ...
}


If your compiler does not have a countof (or _countof) macro defined, use this:

C++
#define countof(arg) ((sizeof arg) / (sizeof arg[0]))
 
Share this answer
 
v4

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900