Search code examples
c++visual-c++memory-leakstypeidtypeinfo

Memory leaks after using typeinfo::name()


I have a program in which, partly for informational logging, I output the names of some classes as they are used (specifically I add an entry to a log saying along the lines of Messages::CSomeClass transmitted to 127.0.0.1). I do this with code similar to the following:

std::string getMessageName(void) const {
    return std::string(typeid(*this).name());
}

And yes, before anyone points it out, I realise that the output of typeinfo::name is implementation-specific.

According to MSDN

The type_info::name member function returns a const char* to a null-terminated string representing the human-readable name of the type. The memory pointed to is cached and should never be directly deallocated.

However, when I exit my program in the debugger, any "new" use of typeinfo::name() shows up as a memory leak. If I output the information for 2 classes, I get 2 memory leaks, and so on. This hints that the cached data is never being freed.

While this is not a major issue, it looks messy, and after a long debugging session it could easily hide genuine memory leaks.

I have looked around and found some useful information (one SO answer gives some interesting information about how typeinfo may be implemented), but I'm wondering if this memory should normally be freed by the system, or if there is something i can do to "not notice" the leaks when debugging.

I do have a back-up plan, which is to code the getMessageName method myself and not rely on typeinfo::name, but I'd like to know anyway if there's something I've missed.


Solution

  • Another solution is to correct the underlying problem. This is not really a memory leak, just a false report. The memory blocks allocated to the tyepinfo() and the name() string are assigned the wrong block type. It is probably not a good idea to "free" this memory, since an attempt will be made by the CRT to free it again. The good news is this was finally fixed in VS2012 (_MSC_VER 1700+).

    Since this only applies to _DEBUG builds, the following may be a safer solution. The function _FixTypeInfoBlockUse() should be called as mentioned above just before exiting the module entry point (main, WinMain, etc.).

    #if defined(_DEBUG) && (_MSC_VER >= 1000 && _MSC_VER <= 1699)
    //
    // Debug memory block header:
    //    o  Borrowed from the Microsoft CRT to fix the false "memory leak" report
    //       when using typeinfo 'name' accessor in a _DEBUG build of the library.  
    //
    struct _CrtMemBlockHeader
       {
       struct _CrtMemBlockHeader * pBlockHeaderNext;
       struct _CrtMemBlockHeader * pBlockHeaderPrev;
       char *                      szFileName;
       int                         nLine;
       #ifdef _WIN64
       int                         nBlockUse;
       size_t                      nDataSize;
       #else
       size_t                      nDataSize;
       int                         nBlockUse;
       #endif
       long                        lRequest;
       unsigned char               gap[4];
       };
    
    static void __cdecl _FixTypeInfoBlockUse(void)
       {
       __type_info_node* pNode = __type_info_root_node._Next;
    
       while(pNode != NULL)
          {
          __type_info_node* pNext = pNode->_Next;
    
          (((_CrtMemBlockHeader*)pNode) - 1)->nBlockUse = _CRT_BLOCK;
    
          if (pNode->_MemPtr != NULL)
             (((_CrtMemBlockHeader*)pNode->_MemPtr) - 1)->nBlockUse = _CRT_BLOCK;
    
          pNode = pNext;
          }
       }
    
    #endif//defined(_DEBUG) && (_MSC_VER >= 1000 && _MSC_VER <= 1699)