Search code examples
c++visual-c++memory-leaksopencv3.0

OpenCV 3.0 + Visual Studio Memory Leak Detector "false" positive


I would like to create project with enabled Visual Studio memory leak detector (Memory Leak Detector)

It always worked fine and I could easily find memory leaks by running bunch of tests on my application and then checking the report.

But after statically linking OpenCV 3.0 to my project I got some false positives.

For instance the most frustrating error comes from StereoBMImpl::compute method and call: ocl::useOpenCL()

After debugging I found the source of the "leak":

TLSData<CoreTLSData>& getCoreTlsData()
{
    static TLSData<CoreTLSData> *value = new TLSData<CoreTLSData>();
    return *value;
}

After analyzing this code we know the static object is allocated only once and everything should be OK. But now I have bunch of false positive memory leak reports like:

{1370349} normal block at 0x0E74D560, 24 bytes long.
 Data: <                > FF FF FF FF 00 00 00 00 00 00 00 00 00 00 00 00 
{1370348} normal block at 0x0E74D4E0, 64 bytes long.
 Data: <` t             > 60 D5 74 0E CD CD CD CD CD CD CD CD CD CD CD CD 

And now it's very difficult to find some real memory leaks in my application because there is set of false positives from OpenCV. I can't also run automatic memory leak tests because the output always contains some leaks.

Is there any way to remove these "pseudo" errors (if possible without changing OpenCV source code) ? It's very annoying.

I suppose other memory leaks detectors will also report some similar pseudo leaks because the new operator is executed without delete (object is automatically cleaned up by the OS).


Solution

  • I solved the problem in a quite dirty way, but I didn't find better. The solution requires modifying one OpenCV file (system.cpp). If you found a better way to fix it, please leave a comment. I suppose more people might have similar problems.

    First I tried to solve the problem using @JamesMcNellis solution (from comment above), by explicitly mark the block as _IGNORE_BLOCK: new (_IGNORE_BLOCK, __FILE__, __LINE__). It was really good start to solve this problem. Unfortunately the leak class contains members like e.g. std::vector, so tracing the allocations from this vector weren't suspended.

    I started to read MSDN documentation to functions from crtdbg.h and I found a way to suspend memory leaks checking for a while. It's possible by clearing the flag '_CRTDBG_ALLOC_MEM_DF' using function: _CrtSetDbgFlag. Check details with example on MSDN: _CrtSetDbgFlag documentation. This solution has probably one drawback (one I know), It suspends memory leaks checking for all threads.

    Finally using RAII and few macro definitions I created simple class to manage this functionality.

    All the changes I applied to official 3.0 source codes.

    Somewhere on top (after precomp.hpp include) of system.cpp file from OpenCV I added simple machinery:

    #if defined(_MSC_VER) && defined(_DEBUG)
        #include <crtdbg.h>
        class MEMORY_LEAKS_CHECKING_SUSPENDER
        {
        public:
            MEMORY_LEAKS_CHECKING_SUSPENDER()
            {
                value = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
                int new_flag = value & (~_CRTDBG_ALLOC_MEM_DF);
                _CrtSetDbgFlag(new_flag);
            }
    
            ~MEMORY_LEAKS_CHECKING_SUSPENDER()
            {
                _CrtSetDbgFlag(value);
            }
    
        private:
            int value;
        };
    
        #define SUSPEND_MEMORY_LEAKS_CHECKING MEMORY_LEAKS_CHECKING_SUSPENDER suspend_memory_leaks_checking
    #else
        #define SUSPEND_MEMORY_LEAKS_CHECKING
    #endif
    

    And each time I want to suspend memory leaks checking i have to add: PAUSE_MEMORY_LEAKS_CHECKING; It is enabled only in Visual Studio Debug compilation. The memory leaks tracing is automatically enabled after leaving the scope (destructor of MEMORY_LEAKS_CHECKING_SUSPENDER class).

    Currently to suspend my OpenCV memory leaks I added suspending allocations in functions:

    • getTLSContainerStorage()
    • void* TLSDataContainer::getData() const
    • TLSData<CoreTLSData>& getCoreTlsData()
    • inline TLSStorage* TLSStorage::get()

    (The last suspension in TLSStorage is probably fixed on master OpenCV repository - I briefly checked the repository)

    Each modification is very simple (e.g. for first leak):

    Before modification:

    static TLSContainerStorage& getTLSContainerStorage()
    {
        static TLSContainerStorage *tlsContainerStorage = new TLSContainerStorage();
        return *tlsContainerStorage;
    }
    

    After modification:

    static TLSContainerStorage& getTLSContainerStorage()
    {
        SUSPEND_MEMORY_LEAKS_CHECKING;
        static TLSContainerStorage *tlsContainerStorage = new TLSContainerStorage();
        return *tlsContainerStorage;
    }
    

    If you modify all these statements and still observe memory leaks and you use OpenCV as separately loaded dll then make sure you properly unloaded this dll using FreeLibrary function. For the reason check DLLMain function in OpenCV system.cpp file and cv::__termination variable usage.