]>
git.saurik.com Git - wxWidgets.git/blob - src/common/memory.cpp
ee71e7fd3aff2fc940c127fd96b545fbec25a695
   1 ///////////////////////////////////////////////////////////////////////////// 
   3 // Purpose:     Memory checking implementation 
   4 // Author:      Arthur Seaton, Julian Smart 
   8 // Copyright:   (c) Julian Smart and Markus Holzem 
   9 // Licence:     wxWindows license 
  10 ///////////////////////////////////////////////////////////////////////////// 
  13 #pragma implementation "memory.h" 
  16 // For compilers that support precompilation, includes "wx.h". 
  17 #include "wx/wxprec.h" 
  27 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT 
  30 // #pragma implementation 
  52 #if !defined(__WATCOMC__) && !defined(__VMS__) 
  72 #include "wx/memory.h" 
  78 // wxDebugContext wxTheDebugContext; 
  80   Redefine new and delete so that we can pick up situations where: 
  81         - we overwrite or underwrite areas of malloc'd memory. 
  82         - we use uninitialise variables 
  83   Only do this in debug mode. 
  85   We change new to get enough memory to allocate a struct, followed 
  86   by the caller's requested memory, followed by a tag. The struct 
  87   is used to create a doubly linked list of these areas and also 
  88   contains another tag. The tags are used to determine when the area 
  89   has been over/under written. 
  94   Values which are used to set the markers which will be tested for 
  95   under/over write. There are 3 of these, one in the struct, one 
  96   immediately after the struct but before the caller requested memory and 
  97   one immediately after the requested memory. 
  99 #define MemStartCheck  0x23A8 
 100 #define MemMidCheck  0xA328 
 101 #define MemEndCheck 0x8A32 
 102 #define MemFillChar 0xAF 
 103 #define MemStructId  0x666D 
 106   External interface for the wxMemStruct class. Others are 
 107   defined inline within the class def. Here we only need to be able 
 108   to add and delete nodes from the list and handle errors in some way. 
 112   Used for internal "this shouldn't happen" type of errors. 
 114 void wxMemStruct::ErrorMsg (const char * mesg
) 
 116   wxLogDebug("wxWindows memory checking error: %s", mesg
); 
 119 //       << m_fileName << ' ' << m_lineNum << endl; 
 123   Used when we find an overwrite or an underwrite error. 
 125 void wxMemStruct::ErrorMsg () 
 127   wxLogDebug("wxWindows over/underwrite memory error:"); 
 130 //    cerr << m_fileName << ' ' << m_lineNum << endl; 
 135   We want to find out if pointers have been overwritten as soon as is 
 136   possible, so test everything before we dereference it. Of course it's still 
 137   quite possible that, if things have been overwritten, this function will 
 138   fall over, but the only way of dealing with that would cost too much in terms 
 141 int wxMemStruct::AssertList () 
 143     if (wxDebugContext::GetHead () != 0 && ! (wxDebugContext::GetHead ())->AssertIt () || 
 144         wxDebugContext::GetTail () != 0 && ! wxDebugContext::GetTail ()->AssertIt ()) { 
 145         ErrorMsg ("Head or tail pointers trashed"); 
 153   Check that the thing we're pointing to has the correct id for a wxMemStruct 
 154   object and also that it's previous and next pointers are pointing at objects 
 155   which have valid ids. 
 156   This is definitely not perfect since we could fall over just trying to access 
 157   any of the slots which we use here, but I think it's about the best that I 
 158   can do without doing something like taking all new wxMemStruct pointers and 
 159   comparing them against all known pointer within the list and then only 
 160   doing this sort of check _after_ you've found the pointer in the list. That 
 161   would be safer, but also much more time consuming. 
 163 int wxMemStruct::AssertIt () 
 165     return (m_id 
== MemStructId 
&& 
 166             (m_prev 
== 0 || m_prev
->m_id 
== MemStructId
) && 
 167             (m_next 
== 0 || m_next
->m_id 
== MemStructId
)); 
 172   Additions are always at the tail of the list. 
 173   Returns 0 on error, non-zero on success. 
 175 int wxMemStruct::Append () 
 180     if (wxDebugContext::GetHead () == 0) { 
 181         if (wxDebugContext::GetTail () != 0) { 
 182             ErrorMsg ("Null list should have a null tail pointer"); 
 185         (void) wxDebugContext::SetHead (this); 
 186         (void) wxDebugContext::SetTail (this); 
 188         wxDebugContext::GetTail ()->m_next 
= this; 
 189         this->m_prev 
= wxDebugContext::GetTail (); 
 190         (void) wxDebugContext::SetTail (this); 
 197   Don't actually free up anything here as the space which is used 
 198   by the node will be free'd up when the whole block is free'd. 
 199   Returns 0 on error, non-zero on success. 
 201 int wxMemStruct::Unlink () 
 206     if (wxDebugContext::GetHead () == 0 || wxDebugContext::GetTail () == 0) { 
 207         ErrorMsg ("Trying to remove node from empty list"); 
 211     // Handle the part of the list before this node. 
 213         if (this != wxDebugContext::GetHead ()) { 
 214             ErrorMsg ("No previous node for non-head node"); 
 217         (void) wxDebugContext::SetHead (m_next
); 
 219         if (! m_prev
->AssertIt ()) { 
 220             ErrorMsg ("Trashed previous pointer"); 
 224         if (m_prev
->m_next 
!= this) { 
 225             ErrorMsg ("List is inconsistent"); 
 228         m_prev
->m_next 
= m_next
; 
 231     // Handle the part of the list after this node. 
 233         if (this != wxDebugContext::GetTail ()) { 
 234             ErrorMsg ("No next node for non-tail node"); 
 237         (void) wxDebugContext::SetTail (m_prev
); 
 239         if (! m_next
->AssertIt ()) { 
 240             ErrorMsg ("Trashed next pointer"); 
 244         if (m_next
->m_prev 
!= this) { 
 245             ErrorMsg ("List is inconsistent"); 
 248         m_next
->m_prev 
= m_prev
; 
 257   Checks a node and block of memory to see that the markers are still 
 260 int wxMemStruct::CheckBlock () 
 264     if (m_firstMarker 
!= MemStartCheck
) { 
 269     char * pointer 
= wxDebugContext::MidMarkerPos ((char *) this); 
 270     if (* (wxMarkerType 
*) pointer 
!= MemMidCheck
) { 
 275     pointer 
= wxDebugContext::EndMarkerPos ((char *) this, RequestSize ()); 
 276     if (* (wxMarkerType 
*) pointer 
!= MemEndCheck
) { 
 286   Check the list of nodes to see if they are all ok. 
 288 int wxMemStruct::CheckAllPrevious () 
 292     for (wxMemStruct 
* st 
= this->m_prev
; st 
!= 0; st 
= st
->m_prev
) { 
 294             nFailures 
+= st
->CheckBlock (); 
 304   When we delete a node we set the id slot to a specific value and then test 
 305   against this to see if a nodes have been deleted previously. I don't 
 306   just set the entire memory to the fillChar because then I'd be overwriting 
 307   useful stuff like the vtbl which may be needed to output the error message 
 308   including the file name and line numbers. Without this info the whole point 
 309   of this class is lost! 
 311 void wxMemStruct::SetDeleted () 
 316 int wxMemStruct::IsDeleted () 
 318     return (m_id 
== MemFillChar
); 
 323   Print out a single node. There are many far better ways of doing this 
 324   but this will suffice for now. 
 326 void wxMemStruct::PrintNode () 
 330     wxObject 
*obj 
= (wxObject 
*)m_actualData
; 
 331     wxClassInfo 
*info 
= obj
->GetClassInfo(); 
 333     // Let's put this in standard form so IDEs can load the file at the appropriate 
 338       msg
.Printf("%s(%d): ", m_fileName
, (int)m_lineNum
); 
 340     if (info 
&& info
->GetClassName()) 
 341       msg 
+= info
->GetClassName(); 
 346     msg2
.Printf(" at $%lX, size %d", (long)GetActualData(), (int)RequestSize()); 
 356       msg
.Printf("%s(%d): ", m_fileName
, (int)m_lineNum
); 
 357     msg 
+= ("non-object data"); 
 359     msg2
.Printf(" at $%lX, size %d\n", (long)GetActualData(), (int)RequestSize()); 
 366 void wxMemStruct::Dump () 
 368   if (!ValidateNode()) return; 
 372     wxObject 
*obj 
= (wxObject 
*)m_actualData
; 
 376       msg
.Printf("%s(%d): ", m_fileName
, (int)m_lineNum
); 
 379     /* TODO: We no longer have a stream (using wxLogDebug) so we can't dump it. 
 380      * Instead, do what wxObject::Dump does. 
 381      * What should we do long-term, eliminate Dumping? Or specify 
 382      * that MyClass::Dump should use wxLogDebug? Ugh. 
 383     obj->Dump(wxDebugContext::GetStream()); 
 386     if (obj
->GetClassInfo() && obj
->GetClassInfo()->GetClassName()) 
 387       msg 
+= obj
->GetClassInfo()->GetClassName(); 
 389       msg 
+= "unknown object class"; 
 392     msg2
.Printf(" at $%lX, size %d", (long)GetActualData(), (int)RequestSize()); 
 401       msg
.Printf("%s(%d): ", m_fileName
, (int)m_lineNum
); 
 404     msg2
.Printf("non-object data at $%lX, size %d", (long)GetActualData(), (int)RequestSize() ); 
 412   Validate a node. Check to see that the node is "clean" in the sense 
 413   that nothing has over/underwritten it etc. 
 415 int wxMemStruct::ValidateNode () 
 417     char * startPointer 
= (char *) this; 
 420             ErrorMsg ("Object already deleted"); 
 422             // Can't use the error routines as we have no recognisable object. 
 424              wxLogDebug("Can't verify memory struct - all bets are off!"); 
 432     for (i = 0; i < wxDebugContext::TotSize (requestSize ()); i++) 
 433       cout << startPointer [i]; 
 436     if (Marker () != MemStartCheck
) 
 438     if (* (wxMarkerType 
*) wxDebugContext::MidMarkerPos (startPointer
) != MemMidCheck
) 
 440     if (* (wxMarkerType 
*) wxDebugContext::EndMarkerPos (startPointer
, 
 445     // Back to before the extra buffer and check that 
 446     // we can still read what we originally wrote. 
 447     if (Marker () != MemStartCheck 
|| 
 448         * (wxMarkerType 
*) wxDebugContext::MidMarkerPos (startPointer
) 
 450         * (wxMarkerType 
*) wxDebugContext::EndMarkerPos (startPointer
, 
 451                                               RequestSize ()) != MemEndCheck
) 
 461   The wxDebugContext class. 
 464 wxMemStruct 
*wxDebugContext::m_head 
= NULL
; 
 465 wxMemStruct 
*wxDebugContext::m_tail 
= NULL
; 
 466 // ostream *wxDebugContext::m_debugStream = NULL; 
 467 // streambuf *wxDebugContext::m_streamBuf = NULL; 
 469 // Must initialise these in wxEntry, and then delete them just before wxEntry exits 
 470 streambuf 
*wxDebugContext::m_streamBuf 
= NULL
; 
 471 ostream 
*wxDebugContext::m_debugStream 
= NULL
; 
 473 bool wxDebugContext::m_checkPrevious 
= FALSE
; 
 474 int wxDebugContext::debugLevel 
= 1; 
 475 bool wxDebugContext::debugOn 
= TRUE
; 
 476 wxMemStruct 
*wxDebugContext::checkPoint 
= NULL
; 
 478 wxDebugContext::wxDebugContext(void) 
 480 //  m_streamBuf = new wxDebugStreamBuf; 
 481 //  m_debugStream = new ostream(m_streamBuf); 
 484 wxDebugContext::~wxDebugContext(void) 
 486   SetStream(NULL
, NULL
); 
 490  * It's bizarre, but with BC++ 4.5, the value of str changes 
 491  * between SetFile and SetStream. 
 494 void wxDebugContext::SetStream(ostream 
*str
, streambuf 
*buf
) 
 498     m_debugStream
->flush(); 
 499     delete m_debugStream
; 
 501   m_debugStream 
= NULL
; 
 503   // Not allowed in Watcom (~streambuf is protected). 
 504   // Is this trying to say something significant to us?? 
 508     streambuf
* oldBuf 
= m_streamBuf
; 
 517 bool wxDebugContext::SetFile(const wxString
& file
) 
 519   ofstream 
*str 
= new ofstream((char *) (const char *)file
); 
 533 bool wxDebugContext::SetStandardError(void) 
 535 #if !defined(_WINDLL) 
 536   wxDebugStreamBuf 
*buf 
= new wxDebugStreamBuf
; 
 537   ostream 
*stream 
= new ostream(m_streamBuf
); 
 538   SetStream(stream
, buf
); 
 547   Work out the positions of the markers by creating an array of 2 markers 
 548   and comparing the addresses of the 2 elements. Use this number as the 
 549   alignment for markers. 
 551 size_t wxDebugContext::CalcAlignment () 
 554     return (char *) &ar
[1] - (char *) &ar
[0]; 
 558 char * wxDebugContext::StructPos (const char * buf
) 
 563 char * wxDebugContext::MidMarkerPos (const char * buf
) 
 565     return StructPos (buf
) + PaddedSize (sizeof (wxMemStruct
)); 
 568 char * wxDebugContext::CallerMemPos (const char * buf
) 
 570     return MidMarkerPos (buf
) + PaddedSize (sizeof(wxMarkerType
)); 
 574 char * wxDebugContext::EndMarkerPos (const char * buf
, const size_t size
) 
 576     return CallerMemPos (buf
) + PaddedSize (size
); 
 581   Slightly different as this takes a pointer to the start of the caller 
 582   requested region and returns a pointer to the start of the buffer. 
 584 char * wxDebugContext::StartPos (const char * caller
) 
 586     return ((char *) (caller 
- wxDebugContext::PaddedSize (sizeof(wxMarkerType
)) - 
 587             wxDebugContext::PaddedSize (sizeof (wxMemStruct
)))); 
 591   We may need padding between various parts of the allocated memory. 
 592   Given a size of memory, this returns the amount of memory which should 
 593   be allocated in order to allow for alignment of the following object. 
 595   I don't know how portable this stuff is, but it seems to work for me at 
 596   the moment. It would be real nice if I knew more about this! 
 598 size_t wxDebugContext::GetPadding (const size_t size
) 
 600     size_t pad 
= size 
% CalcAlignment (); 
 601     return (pad
) ? sizeof(wxMarkerType
) - pad 
: 0; 
 606 size_t wxDebugContext::PaddedSize (const size_t size
) 
 608     return size 
+ GetPadding (size
); 
 612   Returns the total amount of memory which we need to get from the system 
 613   in order to satisfy a caller request. This includes space for the struct 
 614   plus markers and the caller's memory as well. 
 616 size_t wxDebugContext::TotSize (const size_t reqSize
) 
 618     return (PaddedSize (sizeof (wxMemStruct
)) + PaddedSize (reqSize
) + 
 619             2 * sizeof(wxMarkerType
)); 
 624   Traverse the list of nodes executing the given function on each node. 
 626 void wxDebugContext::TraverseList (PmSFV func
, wxMemStruct 
*from
) 
 629     from 
= wxDebugContext::GetHead (); 
 631   for (wxMemStruct 
* st 
= from
; st 
!= 0; st 
= st
->m_next
) 
 633       void* data 
= st
->GetActualData(); 
 634 //      if ((data != (void*)m_debugStream) && (data != (void*) m_streamBuf)) 
 635       if (data 
!= (void*) wxLog::GetActiveTarget()) 
 646 bool wxDebugContext::PrintList (void) 
 652   TraverseList ((PmSFV
)&wxMemStruct::PrintNode
, (checkPoint 
? checkPoint
->m_next 
: (wxMemStruct
*)NULL
)); 
 660 bool wxDebugContext::Dump(void) 
 668     char* appName 
= "application"; 
 669     wxString 
appNameStr(""); 
 672         appNameStr 
= wxTheApp
->GetAppName(); 
 673         appName 
= (char*) (const char*) appNameStr
; 
 674         wxLogDebug("----- Memory dump of %s at %s -----", appName
, WXSTRINGCAST 
wxNow() ); 
 678       wxLogDebug( "----- Memory dump -----" ); 
 681   TraverseList ((PmSFV
)&wxMemStruct::Dump
, (checkPoint 
? checkPoint
->m_next 
: (wxMemStruct
*)NULL
)); 
 692 struct wxDebugStatsStruct
 
 697   wxDebugStatsStruct 
*next
; 
 700 static wxDebugStatsStruct 
*FindStatsStruct(wxDebugStatsStruct 
*st
, char *name
) 
 704     if (strcmp(st
->instanceClass
, name
) == 0) 
 711 static wxDebugStatsStruct 
*InsertStatsStruct(wxDebugStatsStruct 
*head
, wxDebugStatsStruct 
*st
) 
 717 bool wxDebugContext::PrintStatistics(bool detailed
) 
 725     char* appName 
= "application"; 
 726     wxString 
appNameStr(""); 
 729         appNameStr 
= wxTheApp
->GetAppName(); 
 730         appName 
= (char*) (const char*) appNameStr
; 
 731         wxLogDebug("----- Memory statistics of %s at %s -----", appName
, WXSTRINGCAST 
wxNow() ); 
 735       wxLogDebug( "----- Memory statistics -----" ); 
 739   bool currentMode 
= GetDebugMode(); 
 742   long noNonObjectNodes 
= 0; 
 743   long noObjectNodes 
= 0; 
 746   wxDebugStatsStruct 
*list 
= NULL
; 
 748   wxMemStruct 
*from 
= (checkPoint 
? checkPoint
->m_next 
: (wxMemStruct
*)NULL 
); 
 750     from 
= wxDebugContext::GetHead (); 
 753   for (st 
= from
; st 
!= 0; st 
= st
->m_next
) 
 755     void* data 
= st
->GetActualData(); 
 756 //    if (detailed && (data != (void*)m_debugStream) && (data != (void*) m_streamBuf)) 
 757       if (detailed 
&& (data 
!= (void*) wxLog::GetActiveTarget())) 
 759       char *className 
= "nonobject"; 
 760       if (st
->m_isObject 
&& st
->GetActualData()) 
 762         wxObject 
*obj 
= (wxObject 
*)st
->GetActualData(); 
 763         if (obj
->GetClassInfo()->GetClassName()) 
 764           className 
= obj
->GetClassInfo()->GetClassName(); 
 766       wxDebugStatsStruct 
*stats 
= FindStatsStruct(list
, className
); 
 769         stats 
= (wxDebugStatsStruct 
*)malloc(sizeof(wxDebugStatsStruct
)); 
 770         stats
->instanceClass 
= className
; 
 771         stats
->instanceCount 
= 0; 
 772         stats
->totalSize 
= 0; 
 773         list 
= InsertStatsStruct(list
, stats
); 
 775       stats
->instanceCount 
++; 
 776       stats
->totalSize 
+= st
->RequestSize(); 
 779 //    if ((data != (void*)m_debugStream) && (data != (void*) m_streamBuf)) 
 780     if (data 
!= (void*) wxLog::GetActiveTarget()) 
 782         totalSize 
+= st
->RequestSize(); 
 794       wxLogDebug("%ld objects of class %s, total size %ld", 
 795           list
->instanceCount
, list
->instanceClass
, list
->totalSize
); 
 796       wxDebugStatsStruct 
*old 
= list
; 
 803   SetDebugMode(currentMode
); 
 805   wxLogDebug("Number of object items: %ld", noObjectNodes
); 
 806   wxLogDebug("Number of non-object items: %ld", noNonObjectNodes
); 
 807   wxLogDebug("Total allocated size: %ld", totalSize
); 
 817 bool wxDebugContext::PrintClasses(void) 
 824     char* appName 
= "application"; 
 825     wxString 
appNameStr(""); 
 828         appNameStr 
= wxTheApp
->GetAppName(); 
 829         appName 
= (char*) (const char*) appNameStr
; 
 830         wxLogDebug("----- Classes in %s -----", appName
); 
 838   wxClassInfo::sm_classTable
->BeginFind(); 
 839   node 
= wxClassInfo::sm_classTable
->Next(); 
 842     info 
= (wxClassInfo 
*)node
->Data(); 
 843     if (info
->GetClassName()) 
 845         wxString 
msg(info
->GetClassName()); 
 848         if (info
->GetBaseClassName1() && !info
->GetBaseClassName2()) 
 851             msg 
+= info
->GetBaseClassName1(); 
 853         else if (info
->GetBaseClassName1() && info
->GetBaseClassName2()) 
 856             msg 
+= info
->GetBaseClassName1() ; 
 858             msg 
+= info
->GetBaseClassName2() ; 
 860         if (info
->GetConstructor()) 
 865     node 
= wxClassInfo::sm_classTable
->Next(); 
 869   wxLogDebug("There are %d classes derived from wxObject.", n
); 
 875 void wxDebugContext::SetCheckpoint(bool all
) 
 883 // Checks all nodes since checkpoint, or since start. 
 884 int wxDebugContext::Check(bool checkAll
) 
 888   wxMemStruct 
*from 
= (checkPoint 
? checkPoint
->m_next 
: (wxMemStruct
*)NULL 
); 
 889   if (!from 
|| checkAll
) 
 890     from 
= wxDebugContext::GetHead (); 
 892   for (wxMemStruct 
* st 
= from
; st 
!= 0; st 
= st
->m_next
) 
 895       nFailures 
+= st
->CheckBlock (); 
 903 // Count the number of non-wxDebugContext-related objects 
 904 // that are outstanding 
 905 int wxDebugContext::CountObjectsLeft(bool sinceCheckpoint
) 
 909   wxMemStruct 
*from 
= NULL
; 
 910   if (sinceCheckpoint 
&& checkPoint
) 
 911     from 
= checkPoint
->m_next
; 
 912   if (from 
== (wxMemStruct
*) NULL
) 
 913     from 
= wxDebugContext::GetHead () ; 
 915   for (wxMemStruct 
* st 
= from
; st 
!= 0; st 
= st
->m_next
) 
 917       void* data 
= st
->GetActualData(); 
 918 //      if ((data != (void*)m_debugStream) && (data != (void*) m_streamBuf)) 
 919       if (data 
!= (void*) wxLog::GetActiveTarget()) 
 927   The global operator new used for everything apart from getting 
 928   dynamic storage within this function itself. 
 931 // We'll only do malloc and free for the moment: leave the interesting 
 932 // stuff for the wxObject versions. 
 934 #if defined(__WXDEBUG__) && wxUSE_GLOBAL_MEMORY_OPERATORS 
 940 // Seems OK all of a sudden. Maybe to do with linking with multithreaded library? 
 941 #if 0 // def _MSC_VER 
 942 #define NO_DEBUG_ALLOCATION 
 945 // Unfortunately ~wxDebugStreamBuf doesn't work (VC++ 5) when we enable the debugging 
 946 // code. I have no idea why. In BC++ 4.5, we have a similar problem the debug 
 947 // stream myseriously changing pointer address between being passed from SetFile to SetStream. 
 948 // See docs/msw/issues.txt. 
 949 void * operator new (size_t size
, char * fileName
, int lineNum
) 
 951 #ifdef NO_DEBUG_ALLOCATION 
 954   return wxDebugAlloc(size
, fileName
, lineNum
, FALSE
, FALSE
); 
 958 // Added JACS 25/11/98 
 959 void * operator new (size_t size
) 
 961 #ifdef NO_DEBUG_ALLOCATION 
 964   return wxDebugAlloc(size
, NULL
, 0, FALSE
); 
 968 #if wxUSE_ARRAY_MEMORY_OPERATORS 
 969 void * operator new[] (size_t size
) 
 971 #ifdef NO_DEBUG_ALLOCATION 
 974   return wxDebugAlloc(size
, NULL
, 0, FALSE
, TRUE
); 
 979 #if wxUSE_ARRAY_MEMORY_OPERATORS 
 980 void * operator new[] (size_t size
, char * fileName
, int lineNum
) 
 982 #ifdef NO_DEBUG_ALLOCATION 
 985   return wxDebugAlloc(size
, fileName
, lineNum
, FALSE
, TRUE
); 
 990 void operator delete (void * buf
) 
 992 #ifdef NO_DEBUG_ALLOCATION 
1000 #if _MSC_VER >= 1200 
1001 void operator delete(void* pData
, char* /* fileName */, int /* lineNum */) 
1003 // ::operator delete(pData); 
1004   // JACS 21/11/1998: surely we need to call wxDebugFree? 
1005   wxDebugFree(pData
, FALSE
); 
1007 // New operator 21/11/1998 
1008 void operator delete[](void* pData
, char* /* fileName */, int /* lineNum */) 
1010   wxDebugFree(pData
, TRUE
); 
1014 #if wxUSE_ARRAY_MEMORY_OPERATORS 
1016 void operator delete[] (void * buf
) 
1018 #ifdef NO_DEBUG_ALLOCATION 
1021   wxDebugFree(buf
, TRUE
); 
1028 // TODO: store whether this is a vector or not. 
1029 void * wxDebugAlloc(size_t size
, char * fileName
, int lineNum
, bool isObject
, bool WXUNUSED(isVect
) ) 
1031   // If not in debugging allocation mode, do the normal thing 
1032   // so we don't leave any trace of ourselves in the node list. 
1034   if (!wxDebugContext::GetDebugMode()) 
1036     return (void *)malloc(size
); 
1039     char * buf 
= (char *) malloc(wxDebugContext::TotSize (size
)); 
1041         wxLogDebug("Call to malloc (%ld) failed.", (long)size
); 
1044     wxMemStruct 
* st 
= (wxMemStruct 
*)buf
; 
1045     st
->m_firstMarker 
= MemStartCheck
; 
1046     st
->m_reqSize 
= size
; 
1047     st
->m_fileName 
= fileName
; 
1048     st
->m_lineNum 
= lineNum
; 
1049     st
->m_id 
= MemStructId
; 
1052     st
->m_isObject 
= isObject
; 
1054     // Errors from Append() shouldn't really happen - but just in case! 
1055     if (st
->Append () == 0) { 
1056         st
->ErrorMsg ("Trying to append new node"); 
1059     if (wxDebugContext::GetCheckPrevious ()) { 
1060         if (st
->CheckAllPrevious () < 0) { 
1061             st
->ErrorMsg ("Checking previous nodes"); 
1065     // Set up the extra markers at the middle and end. 
1066     char * ptr 
= wxDebugContext::MidMarkerPos (buf
); 
1067     * (wxMarkerType 
*) ptr 
= MemMidCheck
; 
1068     ptr 
= wxDebugContext::EndMarkerPos (buf
, size
); 
1069     * (wxMarkerType 
*) ptr 
= MemEndCheck
; 
1071     // pointer returned points to the start of the caller's 
1073     void *m_actualData 
= (void *) wxDebugContext::CallerMemPos (buf
); 
1074     st
->m_actualData 
= m_actualData
; 
1076     return m_actualData
; 
1079 // TODO: check whether was allocated as a vector 
1080 void wxDebugFree(void * buf
, bool WXUNUSED(isVect
) ) 
1085   // If not in debugging allocation mode, do the normal thing 
1086   // so we don't leave any trace of ourselves in the node list. 
1087   if (!wxDebugContext::GetDebugMode()) 
1093     // Points to the start of the entire allocated area. 
1094     char * startPointer 
= wxDebugContext::StartPos ((char *) buf
); 
1095     // Find the struct and make sure that it's identifiable. 
1096     wxMemStruct 
* st 
= (wxMemStruct 
*) wxDebugContext::StructPos (startPointer
); 
1098     if (! st
->ValidateNode ()) 
1101     // If this is the current checkpoint, we need to 
1102     // move the checkpoint back so it points to a valid 
1104     if (st 
== wxDebugContext::checkPoint
) 
1105       wxDebugContext::checkPoint 
= wxDebugContext::checkPoint
->m_prev
; 
1107     if (! st
->Unlink ()) 
1109       st
->ErrorMsg ("Unlinking deleted node"); 
1112     // Now put in the fill char into the id slot and the caller requested 
1113     // memory locations. 
1115     (void) memset (wxDebugContext::CallerMemPos (startPointer
), MemFillChar
, 
1116                    st
->RequestSize ()); 
1118     // Don't allow delayed freeing of memory in this version 
1119 //    if (!wxDebugContext::GetDelayFree()) 
1120 //    free((void *)st); 
1124 // Trace: send output to the current debugging stream 
1125 void wxTrace(const char *fmt 
...) 
1128   static char buffer
[512]; 
1133   wvsprintf(buffer
,fmt
,ap
) ; 
1135   vsprintf(buffer
,fmt
,ap
) ; 
1140   if (wxDebugContext::HasStream()) 
1142     wxDebugContext::GetStream() << buffer
; 
1143     wxDebugContext::GetStream().flush(); 
1147     OutputDebugString((LPCSTR
)buffer
) ; 
1149     fprintf(stderr
, buffer
); 
1154 void wxTraceLevel(int level
, const char *fmt 
...) 
1156   if (wxDebugContext::GetLevel() < level
) 
1160   static char buffer
[512]; 
1165   wvsprintf(buffer
,fmt
,ap
) ; 
1167   vsprintf(buffer
,fmt
,ap
) ; 
1172   if (wxDebugContext::HasStream()) 
1174     wxDebugContext::GetStream() << buffer
; 
1175     wxDebugContext::GetStream().flush(); 
1179     OutputDebugString((LPCSTR
)buffer
) ; 
1181     fprintf(stderr
, buffer
); 
1185 #else // wxUSE_MEMORY_TRACING && defined(__WXDEBUG__) 
1186 void wxTrace(const char *WXUNUSED(fmt
) ...) 
1190 void wxTraceLevel(int WXUNUSED(level
), const char *WXUNUSED(fmt
) ...)