vtkDebugLeaks attempts to lock mutex twice when printing error msg for the first time
The Problem
vtkDebugLeaks
locks and unlocks the std::mutex* CriticalSection
explicitly. It also reports error and warning messages before unlocking the mutex. If a failure occurs, for example in void vtkDebugLeaks::DestructClass(const char* className)
, the function tries to report the error using vtkGenericWarningMacro
. This macro will construct a vtkWin32OutputWindow
if being called for the first time. Since VTK_DEBUG_LEAKS
is defined, the construction causes another call to vtkDebugLeaks
here:
void vtkObjectBase::InitializeObjectBase()
{
#ifdef VTK_DEBUG_LEAKS
vtkDebugLeaks::ConstructClass(this);
#endif // VTK_DEBUG_LEAKS
}
which tries to lock the mutex for a second time.
Proposed solution:
vtkDebugLeaks
class should avoid using explicit calls to std::mutex::lock()
and std::mutex::unlock()
. It should use std::lock_guard
and set the scope to release the lock before attempting to print errors or do anything else that does not belong to a "CriticalSection".
Example shown below:
Before
void vtkDebugLeaks::DestructClass(const char* className)
{
vtkDebugLeaks::CriticalSection->lock();
// Due to globals being deleted, this table may already have
// been deleted.
if (vtkDebugLeaks::MemoryTable && !vtkDebugLeaks::MemoryTable->DecrementCount(className))
{
vtkGenericWarningMacro("Deleting unknown object: " << className);
}
vtkDebugLeaks::CriticalSection->unlock();
}
After (Solution)
void vtkDebugLeaks::DestructClass(const char* className)
{
bool failure = false;
{
const std::lock_guard<std::mutex> lock(*(vtkDebugLeaks::CriticalSection));
failure = vtkDebugLeaks::MemoryTable && !vtkDebugLeaks::MemoryTable->DecrementCount(className);
}
if (failure)
{
vtkGenericWarningMacro("Deleting unknown object: " << className);
}
}