Cloned library of VTK-5.0.0 with extra build files for internal package management.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

463 lines
11 KiB

/*=========================================================================
Program: Visualization Toolkit
Module: $RCSfile: vtkDebugLeaks.cxx,v $
Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
All rights reserved.
See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the above copyright notice for more information.
=========================================================================*/
#include "vtkDebugLeaks.h"
#include "vtkCriticalSection.h"
#include "vtkObjectFactory.h"
#include "vtkWindows.h"
#include <vtkstd/string>
static const char *vtkDebugLeaksIgnoreClasses[] = {
0
};
//----------------------------------------------------------------------------
// return 1 if the class should be ignored
int vtkDebugLeaksIgnoreClassesCheck(const char* s)
{
int i =0;
while(vtkDebugLeaksIgnoreClasses[i])
{
if(strcmp(s, vtkDebugLeaksIgnoreClasses[i]) == 0)
{
return 1;
}
i++;
}
return 0;
}
vtkCxxRevisionMacro(vtkDebugLeaks, "$Revision: 1.41 $");
vtkStandardNewMacro(vtkDebugLeaks);
//----------------------------------------------------------------------------
// A hash function for converting a string to a long
inline size_t vtkHashString(const char* s)
{
unsigned long h = 0;
for ( ; *s; ++s)
{
h = 5*h + *s;
}
return size_t(h);
}
//----------------------------------------------------------------------------
class vtkDebugLeaksHashNode
{
public:
vtkDebugLeaksHashNode()
{
this->Count =1; // if it goes in, then there is one of them
this->Key = 0;
this->Next =0;
}
void Print(vtkstd::string& os)
{
if(this->Count)
{
char tmp[256];
sprintf(tmp,"\" has %i %s still around.\n",this->Count,
(this->Count == 1) ? "instance" : "instances");
os += "Class \"";
os += this->Key;
os += tmp;
}
}
~vtkDebugLeaksHashNode()
{
delete [] this->Key;
if(this->Next)
{
delete this->Next;
}
}
public:
vtkDebugLeaksHashNode *Next;
char *Key;
int Count;
};
//----------------------------------------------------------------------------
class vtkDebugLeaksHashTable
{
public:
vtkDebugLeaksHashTable();
vtkDebugLeaksHashNode* GetNode(const char* name);
void IncrementCount(const char *name);
unsigned int GetCount(const char *name);
int DecrementCount(const char* name);
void PrintTable(vtkstd::string &os);
int IsEmpty();
~vtkDebugLeaksHashTable()
{
for (int i = 0; i < 64; i++)
{
vtkDebugLeaksHashNode *pos = this->Nodes[i];
if(pos)
{
delete pos;
}
}
}
private:
vtkDebugLeaksHashNode* Nodes[64];
};
//----------------------------------------------------------------------------
vtkDebugLeaksHashTable::vtkDebugLeaksHashTable()
{
int i;
for (i = 0; i < 64; i++)
{
this->Nodes[i] = NULL;
}
}
//----------------------------------------------------------------------------
void vtkDebugLeaksHashTable::IncrementCount(const char * name)
{
vtkDebugLeaksHashNode *pos;
vtkDebugLeaksHashNode *newpos;
int loc;
pos = this->GetNode(name);
if(pos)
{
pos->Count++;
return;
}
newpos = new vtkDebugLeaksHashNode;
newpos->Key = strcpy(new char[strlen(name)+1], name);
loc = (((unsigned long)vtkHashString(name)) & 0x03f0) / 16;
pos = this->Nodes[loc];
if (!pos)
{
this->Nodes[loc] = newpos;
return;
}
while (pos->Next)
{
pos = pos->Next;
}
pos->Next = newpos;
}
//----------------------------------------------------------------------------
vtkDebugLeaksHashNode* vtkDebugLeaksHashTable::GetNode(const char* key)
{
vtkDebugLeaksHashNode *pos;
int loc = (((unsigned long)vtkHashString(key)) & 0x03f0) / 16;
pos = this->Nodes[loc];
if (!pos)
{
return NULL;
}
while ((pos) && (strcmp(pos->Key, key) != 0) )
{
pos = pos->Next;
}
return pos;
}
//----------------------------------------------------------------------------
unsigned int vtkDebugLeaksHashTable::GetCount(const char* key)
{
vtkDebugLeaksHashNode *pos;
int loc = (((unsigned long)vtkHashString(key)) & 0x03f0) / 16;
pos = this->Nodes[loc];
if (!pos)
{
return 0;
}
while ((pos)&&(pos->Key != key))
{
pos = pos->Next;
}
if (pos)
{
return pos->Count;
}
return 0;
}
//----------------------------------------------------------------------------
int vtkDebugLeaksHashTable::IsEmpty()
{
int count = 0;
for(int i =0; i < 64; i++)
{
vtkDebugLeaksHashNode *pos = this->Nodes[i];
if(pos)
{
if(!vtkDebugLeaksIgnoreClassesCheck(pos->Key))
{
count += pos->Count;
}
while(pos->Next)
{
pos = pos->Next;
if(!vtkDebugLeaksIgnoreClassesCheck(pos->Key))
{
count += pos->Count;
}
}
}
}
return !count;
}
//----------------------------------------------------------------------------
int vtkDebugLeaksHashTable::DecrementCount(const char *key)
{
vtkDebugLeaksHashNode *pos = this->GetNode(key);
if(pos)
{
pos->Count--;
return 1;
}
else
{
return 0;
}
}
//----------------------------------------------------------------------------
void vtkDebugLeaksHashTable::PrintTable(vtkstd::string &os)
{
for(int i =0; i < 64; i++)
{
vtkDebugLeaksHashNode *pos = this->Nodes[i];
if(pos)
{
if(!vtkDebugLeaksIgnoreClassesCheck(pos->Key))
{
pos->Print(os);
}
while(pos->Next)
{
pos = pos->Next;
if(!vtkDebugLeaksIgnoreClassesCheck(pos->Key))
{
pos->Print(os);
}
}
}
}
}
//----------------------------------------------------------------------------
#ifdef VTK_DEBUG_LEAKS
void vtkDebugLeaks::ConstructClass(const char* name)
{
vtkDebugLeaks::CriticalSection->Lock();
vtkDebugLeaks::MemoryTable->IncrementCount(name);
vtkDebugLeaks::CriticalSection->Unlock();
}
#else
void vtkDebugLeaks::ConstructClass(const char*)
{
}
#endif
//----------------------------------------------------------------------------
#ifdef VTK_DEBUG_LEAKS
void vtkDebugLeaks::DestructClass(const char* p)
{
vtkDebugLeaks::CriticalSection->Lock();
// Due to globals being deleted, this table may already have
// been deleted.
if(vtkDebugLeaks::MemoryTable &&
!vtkDebugLeaks::MemoryTable->DecrementCount(p))
{
vtkDebugLeaks::CriticalSection->Unlock();
vtkGenericWarningMacro("Deleting unknown object: " << p);
}
else
{
vtkDebugLeaks::CriticalSection->Unlock();
}
}
#else
void vtkDebugLeaks::DestructClass(const char*)
{
}
#endif
//----------------------------------------------------------------------------
int vtkDebugLeaks::PrintCurrentLeaks()
{
#ifdef VTK_DEBUG_LEAKS
if(vtkDebugLeaks::MemoryTable->IsEmpty())
{
return 0;
}
// we must not use stringstream ior strstream due to problems with
// finalizers in MSVC
vtkstd::string leaks;
vtkDebugLeaks::MemoryTable->PrintTable(leaks);
#ifdef _WIN32
fprintf(stderr,"%s",leaks.c_str());
fflush(stderr);
int cancel=0;
if(getenv("DASHBOARD_TEST_FROM_CTEST") ||
getenv("DART_TEST_FROM_DART"))
{
// Skip dialogs when running on dashboard.
return 1;
}
vtkstd::string::size_type myPos = 0;
int count = 0;
vtkstd::string msg;
msg = "vtkDebugLeaks has detected LEAKS!\n";
while(!cancel && myPos != leaks.npos)
{
vtkstd::string::size_type newPos = leaks.find('\n',myPos);
if (newPos != leaks.npos)
{
msg += leaks.substr(myPos,newPos-myPos);
msg += "\n";
myPos = newPos;
myPos++;
}
else
{
myPos = newPos;
}
count++;
if (count == 10)
{
count = 0;
cancel = vtkDebugLeaks::DisplayMessageBox(msg.c_str());
msg = "";
}
}
if (!cancel && count > 0)
{
vtkDebugLeaks::DisplayMessageBox(msg.c_str());
}
#else
cout << "vtkDebugLeaks has detected LEAKS!\n";
cout << leaks.c_str() << endl;
#endif
#endif
return 1;
}
//----------------------------------------------------------------------------
#ifdef _WIN32
int vtkDebugLeaks::DisplayMessageBox(const char* msg)
{
#ifdef UNICODE
wchar_t *wmsg = new wchar_t [mbstowcs(NULL, msg, 32000)+1];
mbstowcs(wmsg, msg, 32000);
int result = (MessageBox(NULL, wmsg, L"Error",
MB_ICONERROR | MB_OKCANCEL) == IDCANCEL);
delete [] wmsg;
#else
int result = (MessageBox(NULL, msg, "Error",
MB_ICONERROR | MB_OKCANCEL) == IDCANCEL);
#endif
return result;
}
#else
int vtkDebugLeaks::DisplayMessageBox(const char*)
{
return 0;
}
#endif
//----------------------------------------------------------------------------
int vtkDebugLeaks::GetExitError()
{
return vtkDebugLeaks::ExitError;
}
//----------------------------------------------------------------------------
void vtkDebugLeaks::SetExitError(int flag)
{
vtkDebugLeaks::ExitError = flag;
}
//----------------------------------------------------------------------------
void vtkDebugLeaks::ClassInitialize()
{
#ifdef VTK_DEBUG_LEAKS
// Create the hash table.
vtkDebugLeaks::MemoryTable = new vtkDebugLeaksHashTable;
// Create the lock for the critical sections.
vtkDebugLeaks::CriticalSection = new vtkSimpleCriticalSection;
// Default to error when leaks occur while running tests.
vtkDebugLeaks::ExitError =
(getenv("DASHBOARD_TEST_FROM_CTEST") ||
getenv("DART_TEST_FROM_DART"))? 1:0;
#else
vtkDebugLeaks::MemoryTable = 0;
vtkDebugLeaks::CriticalSection = 0;
vtkDebugLeaks::ExitError = 0;
#endif
}
//----------------------------------------------------------------------------
void vtkDebugLeaks::ClassFinalize()
{
#ifdef VTK_DEBUG_LEAKS
// Report leaks.
int leaked = vtkDebugLeaks::PrintCurrentLeaks();
// Destroy the hash table.
delete vtkDebugLeaks::MemoryTable;
vtkDebugLeaks::MemoryTable = 0;
// Destroy the lock for the critical sections.
delete vtkDebugLeaks::CriticalSection;
vtkDebugLeaks::CriticalSection = 0;
// Exit with error if leaks occured and error mode is on.
if(leaked && vtkDebugLeaks::ExitError)
{
exit(1);
}
#endif
}
#ifndef VTK_LEGACY_REMOVE
void vtkDebugLeaks::PromptUserOn() {}
void vtkDebugLeaks::PromptUserOff() {}
#endif
//----------------------------------------------------------------------------
// Purposely not initialized. ClassInitialize will handle it.
vtkDebugLeaksHashTable* vtkDebugLeaks::MemoryTable;
// Purposely not initialized. ClassInitialize will handle it.
vtkSimpleCriticalSection* vtkDebugLeaks::CriticalSection;
// Purposely not initialized. ClassInitialize will handle it.
int vtkDebugLeaks::ExitError;