📄 object.cxx
字号:
/* * object.cxx * * Global object support. * * Portable Windows Library * * Copyright (c) 1993-1998 Equivalence Pty. Ltd. * * The contents of this file are subject to the Mozilla Public License * Version 1.0 (the "License"); you may not use this file except in * compliance with the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See * the License for the specific language governing rights and limitations * under the License. * * The Original Code is Portable Windows Library. * * The Initial Developer of the Original Code is Equivalence Pty. Ltd. * * Portions are Copyright (C) 1993 Free Software Foundation, Inc. * All Rights Reserved. * * Contributor(s): ______________________________________. * * $Log: object.cxx,v $ * Revision 1.44 2000/06/26 11:17:20 robertj * Nucleus++ port (incomplete). * * Revision 1.43 2000/01/05 00:29:12 robertj * Fixed alignment problems in memory checking debug functions. * * Revision 1.42 1999/11/01 00:17:20 robertj * Added override of new functions for MSVC memory check code. * * Revision 1.41 1999/08/22 13:38:39 robertj * Fixed termination hang up problem with memory check code under unix pthreads. * * Revision 1.40 1999/08/10 10:45:09 robertj * Added mutex in memory check detection code. * * Revision 1.39 1999/07/18 15:08:48 robertj * Fixed 64 bit compatibility * * Revision 1.38 1999/05/01 11:29:20 robertj * Alpha linux port changes. * * Revision 1.37 1999/03/09 10:30:17 robertj * Fixed ability to have PMEMORY_CHECK on/off on both debug/release versions. * * Revision 1.36 1999/02/22 10:48:14 robertj * Fixed delete operator prototypes for MSVC6 and GNU compatibility. * * Revision 1.35 1998/12/22 10:24:17 robertj * Fixed MSVC warnings caused by changes made in linux PPC support. * * Revision 1.34 1998/12/15 09:01:10 robertj * Fixed 8 byte alignment problem in memory leak check code for sparc. * * Revision 1.33 1998/11/30 05:33:00 robertj * Fixed duplicate debug stream class, ther can be only one. * * Revision 1.32 1998/11/03 03:11:53 robertj * Fixed memory leak question so correctly detects leaks and can be ^C'd. * * Revision 1.31 1998/11/03 00:55:31 robertj * Added allocation breakpoint variable. * * Revision 1.30 1998/10/15 07:48:56 robertj * Added hex dump to memory leak. * Added ability to ignore G++lib memory leaks. * * Revision 1.29 1998/10/15 01:53:35 robertj * GNU compatibility. * * Revision 1.28 1998/10/13 14:06:26 robertj * Complete rewrite of memory leak detection code. * * Revision 1.27 1998/09/23 06:22:22 robertj * Added open source copyright license. * * Revision 1.26 1998/05/30 13:27:02 robertj * Changed memory check code so global statics are not included in leak check. * * Revision 1.25 1997/07/08 13:07:07 robertj * DLL support. * * Revision 1.24 1997/02/09 03:45:28 robertj * Fixed unix/dos compatibility with include file. * * Revision 1.23 1997/02/05 11:54:12 robertj * Fixed problems with memory check and leak detection. * * Revision 1.22 1996/08/08 10:08:46 robertj * Directory structure changes for common files. * * Revision 1.21 1996/07/15 10:35:11 robertj * Changed memory leak dump to use static class rather than atexit for better portability. * * Revision 1.20 1996/06/17 11:35:47 robertj * Fixed display of memory leak info, needed flush and use of cin as getchar() does not work with services. * * Revision 1.19 1996/05/09 12:19:29 robertj * Fixed up 64 bit integer class for Mac platform. * Fixed incorrect use of memcmp/strcmp return value. * * Revision 1.18 1996/03/26 00:55:20 robertj * Added keypress before dumping memory leaks. * * Revision 1.17 1996/01/28 02:50:27 robertj * Added missing bit shift operators to 64 bit integer class. * Added assert into all Compare functions to assure comparison between compatible objects. * * Revision 1.16 1996/01/23 13:15:52 robertj * Mac Metrowerks compiler support. * * Revision 1.15 1996/01/02 12:52:02 robertj * Mac OS compatibility changes. * * Revision 1.14 1995/11/21 11:51:54 robertj * Improved streams compatibility. * * Revision 1.12 1995/04/25 11:30:34 robertj * Fixed Borland compiler warnings. * Fixed function hiding ancestors virtual. * * Revision 1.11 1995/03/12 04:59:53 robertj * Re-organisation of DOS/WIN16 and WIN32 platforms to maximise common code. * Used built-in equate for WIN32 API (_WIN32). * * Revision 1.10 1995/02/19 04:19:21 robertj * Added dynamically linked command processing. * * Revision 1.9 1995/01/15 04:52:02 robertj * Mac compatibility. * Added memory stats function. *// Revision 1.8 1995/01/09 12:38:07 robertj// Changed variable names around during documentation run.// Fixed smart pointer comparison.// Fixed serialisation stuff.//// Revision 1.7 1995/01/07 04:39:45 robertj// Redesigned font enumeration code and changed font styles.//// Revision 1.6 1995/01/04 10:57:08 robertj// Changed for HPUX and GNU2.6.x//// Revision 1.5 1995/01/03 09:39:10 robertj// Put standard malloc style memory allocation etc into memory check system.//// Revision 1.4 1994/12/21 11:43:29 robertj// Added extra memory stats.//// Revision 1.3 1994/12/13 11:54:54 robertj// Added some memory usage statistics.//// Revision 1.2 1994/12/12 10:08:32 robertj// Renamed PWrapper to PSmartPointer..//// Revision 1.1 1994/10/30 12:02:15 robertj// Initial revision// */#include <ptlib.h>#include <ctype.h>#ifdef _WIN32#include <strstrea.h>#include <ptlib/debstrm.h>#elif defined(__NUCLEUS_PLUS__)#include <ptlib/NucleusDebstrm.h>#else#include <strstream.h>#include <signal.h>#endifvoid PAssertFunc(const char * file, int line, PStandardAssertMessage msg){ static const char * const textmsg[PMaxStandardAssertMessage] = { NULL, "Out of memory", "Null pointer reference", "Invalid cast to non-descendant class", "Invalid array index", "Invalid array element", "Stack empty", "Unimplemented function", "Invalid parameter", "Operating System error", "File not open", "Unsupported feature", "Invalid or closed operating system window" }; const char * theMsg; char msgbuf[20]; if (msg < PMaxStandardAssertMessage) theMsg = textmsg[msg]; else { sprintf(msgbuf, "Error code: %i", msg); theMsg = msgbuf; } PAssertFunc(file, line, theMsg);}#if PMEMORY_CHECK#undef malloc#undef realloc#undef freevoid * operator new(size_t nSize){ return PMemoryHeap::Allocate(nSize, (const char *)NULL, 0, NULL);}void * operator new[](size_t nSize){ return PMemoryHeap::Allocate(nSize, (const char *)NULL, 0, NULL);}void operator delete(void * ptr){ PMemoryHeap::Deallocate(ptr, NULL);}void operator delete[](void * ptr){ PMemoryHeap::Deallocate(ptr, NULL);}DWORD PMemoryHeap::allocationBreakpoint;char PMemoryHeap::Header::GuardBytes[NumGuardBytes];PMemoryHeap::Wrapper::Wrapper(){ // The following is done like this to get over brain dead compilers that cannot // guarentee that a static global is contructed before it is used. static PMemoryHeap real_instance; instance = &real_instance; if (instance->isDestroyed) return;#if defined(_WIN32) EnterCriticalSection(&instance->mutex);#elif defined(P_PTHREADS) pthread_mutex_lock(&instance->mutex);#endif}PMemoryHeap::Wrapper::~Wrapper(){ if (instance->isDestroyed) return;#if defined(_WIN32) LeaveCriticalSection(&instance->mutex);#elif defined(P_PTHREADS) pthread_mutex_unlock(&instance->mutex);#endif}PMemoryHeap::PMemoryHeap(){ isDestroyed = FALSE; listHead = NULL; listTail = NULL; allocationRequest = 1; firstRealObject = 0; flags = 0; allocFillChar = '\x5A'; freeFillChar = '\xA5'; currentMemoryUsage = 0; peakMemoryUsage = 0; currentObjects = 0; peakObjects = 0; totalObjects = 0; for (PINDEX i = 0; i < Header::NumGuardBytes; i++) Header::GuardBytes[i] = (i&1) == 0 ? '\x55' : '\xaa';#if defined(_WIN32) InitializeCriticalSection(&mutex); static PDebugStream debug; leakDumpStream = &debug;#else#if defined(P_PTHREADS) pthread_mutex_init(&mutex, NULL);#endif leakDumpStream = &cerr;#endif}PMemoryHeap::~PMemoryHeap(){ isDestroyed = TRUE; if (leakDumpStream != NULL) { DumpStatistics(*leakDumpStream);#if !defined(_WIN32) if (listTail != NULL && listTail->request >= firstRealObject) {#if defined(P_PTHREADS) sigset_t blockedSignals; sigemptyset(&blockedSignals); sigaddset(&blockedSignals, SIGINT); sigaddset(&blockedSignals, SIGQUIT); sigaddset(&blockedSignals, SIGTERM); pthread_sigmask(SIG_UNBLOCK, &blockedSignals, NULL);#endif ::signal(SIGINT, SIG_DFL); ::signal(SIGQUIT, SIG_DFL); ::signal(SIGTERM, SIG_DFL); *leakDumpStream << "\nMemory leaks detected, press Enter to display . . ." << flush; cin.get(); }#endif DumpObjectsSince(firstRealObject, *leakDumpStream); }#if defined(_WIN32) DeleteCriticalSection(&mutex); extern void PWaitOnExitConsoleWindow(); PWaitOnExitConsoleWindow();#elif defined(P_PTHREADS) pthread_mutex_destroy(&mutex);#endif}void * PMemoryHeap::Allocate(size_t nSize, const char * file, int line, const char * className){ Wrapper mem; return mem->InternalAllocate(nSize, file, line, className);}void * PMemoryHeap::Allocate(size_t count, size_t size, const char * file, int line){ Wrapper mem; char oldFill = mem->allocFillChar; mem->allocFillChar = '\0'; void * data = mem->InternalAllocate(count*size, file, line, NULL); mem->allocFillChar = oldFill; return data;}void * PMemoryHeap::InternalAllocate(size_t nSize, const char * file, int line, const char * className){ if (isDestroyed) return malloc(nSize); Header * obj = (Header *)malloc(sizeof(Header) + nSize + sizeof(Header::GuardBytes)); if (obj == NULL) { PAssertAlways(POutOfMemory); return NULL; } if (firstRealObject == 0 && file != NULL && line > 0) firstRealObject = allocationRequest; PAssert(allocationRequest != allocationBreakpoint, "Break on memory allocation."); currentMemoryUsage += nSize; if (currentMemoryUsage > peakMemoryUsage) peakMemoryUsage = currentMemoryUsage; currentObjects++; if (currentObjects > peakObjects) peakObjects = currentObjects; totalObjects++; char * data = (char *)&obj[1]; obj->prev = listTail; obj->next = NULL; obj->size = nSize; obj->fileName = file; obj->line = (WORD)line; obj->className = className; obj->request = allocationRequest++; obj->flags = flags; memcpy(obj->guard, obj->GuardBytes, sizeof(obj->guard)); memset(data, allocFillChar, nSize); memcpy(&data[nSize], obj->GuardBytes, sizeof(obj->guard)); if (listTail != NULL) listTail->next = obj; listTail = obj; if (listHead == NULL) listHead = obj; return data;}void * PMemoryHeap::Reallocate(void * ptr, size_t nSize, const char * file, int line){ if (ptr == NULL) return Allocate(nSize, file, line, NULL); if (nSize == 0) { Deallocate(ptr, NULL); return NULL; } Wrapper mem; if (mem->isDestroyed) return realloc(ptr, nSize); if (mem->InternalValidate(ptr, NULL, mem->leakDumpStream) != Ok) return NULL; Header * obj = (Header *)realloc(((Header *)ptr)-1, sizeof(Header) + nSize + sizeof(obj->guard)); if (obj == NULL) { PAssertAlways(POutOfMemory); return NULL; } PAssert(mem->allocationRequest != allocationBreakpoint, "Break on memory allocation."); mem->currentMemoryUsage -= obj->size; mem->currentMemoryUsage += nSize; if (mem->currentMemoryUsage > mem->peakMemoryUsage) mem->peakMemoryUsage = mem->currentMemoryUsage; char * data = (char *)&obj[1]; memcpy(&data[nSize], obj->GuardBytes, sizeof(obj->guard)); obj->size = nSize; obj->fileName = file; obj->line = (WORD)line; obj->request = mem->allocationRequest++; if (obj->prev != NULL) obj->prev->next = obj; else mem->listHead = obj; if (obj->next != NULL) obj->next->prev = obj; else mem->listTail = obj; return data;}void PMemoryHeap::Deallocate(void * ptr, const char * className){ if (ptr == NULL) return; Wrapper mem; if (mem->isDestroyed) { free(ptr); return; } if (mem->InternalValidate(ptr, className, mem->leakDumpStream) != Ok) { free(ptr); return; } Header * obj = ((Header *)ptr)-1; if (obj->prev != NULL) obj->prev->next = obj->next; else mem->listHead = obj->next; if (obj->next != NULL) obj->next->prev = obj->prev; else mem->listTail = obj->prev; mem->currentMemoryUsage -= obj->size; mem->currentObjects--; memset(ptr, mem->freeFillChar, obj->size); // Make use of freed data noticable free(obj);}PMemoryHeap::Validation PMemoryHeap::Validate(void * ptr, const char * className, ostream * error){ Wrapper mem; return mem->InternalValidate(ptr, className, error);}PMemoryHeap::Validation PMemoryHeap::InternalValidate(void * ptr, const char * className, ostream * error){ if (isDestroyed) return Bad; if (ptr == NULL) return Trashed; Header * obj = ((Header *)ptr)-1; if (memcmp(obj->guard, obj->GuardBytes, sizeof(obj->guard)) != 0) { if (error != NULL) *error << "Underrun at " << ptr << '[' << obj->size << "] #" << obj->request << endl; return Bad; } if (memcmp((char *)ptr+obj->size, obj->GuardBytes, sizeof(obj->guard)) != 0) { if (error != NULL) *error << "Overrun at " << ptr << '[' << obj->size << "] #" << obj->request << endl; return Bad; } if (obj->className != NULL && strcmp(obj->className, className) != 0) { if (error != NULL) *error << "PObject " << ptr << '[' << obj->size << "] #" << obj->request << " allocated as \"" << obj->className << "\" and should be \"" << className << "\"." << endl; return Bad; } Header * forward = obj; Header * backward = obj; while (forward->next != NULL && backward->prev != NULL) { forward = forward->next; backward = backward->prev; } if (forward != listTail && backward != listHead) { if (error != NULL) *error << "Block " << ptr << '[' << obj->size << "] #" << obj->request << " not in heap!" << endl; return Trashed; } return Ok;}void PMemoryHeap::SetIgnoreAllocations(BOOL ignore){ Wrapper mem; if (ignore) mem->flags |= NoLeakPrint; else mem->flags &= ~NoLeakPrint;}void PMemoryHeap::DumpStatistics(){ Wrapper mem; if (mem->leakDumpStream != NULL) mem->InternalDumpStatistics(*mem->leakDumpStream);}void PMemoryHeap::DumpStatistics(ostream & strm){ Wrapper mem; mem->InternalDumpStatistics(strm);}void PMemoryHeap::InternalDumpStatistics(ostream & strm){ strm << "\nCurrent memory usage: " << currentMemoryUsage << " bytes"; if (currentMemoryUsage > 2048) strm << ", " << (currentMemoryUsage+1023)/1024 << "kb"; if (currentMemoryUsage > 2097152) strm << ", " << (currentMemoryUsage+1048575)/1048576 << "Mb"; strm << ".\nCurrent objects count: " << currentObjects << "\nPeak memory usage: " << peakMemoryUsage << " bytes"; if (peakMemoryUsage > 2048) strm << ", " << (peakMemoryUsage+1023)/1024 << "kb"; if (peakMemoryUsage > 2097152) strm << ", " << (peakMemoryUsage+1048575)/1048576 << "Mb"; strm << ".\nPeak objects created: " << peakObjects << "\nTotal objects created: " << totalObjects << '\n' << endl;}DWORD PMemoryHeap::GetAllocationRequest(){ Wrapper mem; return mem->allocationRequest;}void PMemoryHeap::SetAllocationBreakpoint(DWORD point){ allocationBreakpoint = point;}void PMemoryHeap::DumpObjectsSince(DWORD objectNumber){ Wrapper mem; if (mem->leakDumpStream != NULL) mem->InternalDumpObjectsSince(objectNumber, *mem->leakDumpStream);}void PMemoryHeap::DumpObjectsSince(DWORD objectNumber, ostream & strm){ Wrapper mem; mem->InternalDumpObjectsSince(objectNumber, strm);}void PMemoryHeap::InternalDumpObjectsSince(DWORD objectNumber, ostream & strm){ for (Header * obj = listHead; obj != NULL; obj = obj->next) { if (obj->request < objectNumber || (obj->flags&NoLeakPrint) != 0) continue; BYTE * data = (BYTE *)&obj[1]; if (obj->fileName != NULL) strm << obj->fileName << '(' << obj->line << ") : "; strm << '#' << obj->request << ' ' << (void *)data << " [" << obj->size << "] "; if (obj->className != NULL) strm << '"' << obj->className << "\" "; strm << '\n' << hex << setfill('0') << PBYTEArray(data, PMIN(16, obj->size), FALSE) << dec << setfill(' ') << endl; }}#endifconst char * PObject::GetClass(unsigned) const{ return Class();}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -