]>
git.saurik.com Git - wxWidgets.git/blob - src/common/memory.cpp
01f70591f97eb8440e360a1cdfd91ce3c713ea1a
   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 (WXDEBUG && USE_MEMORY_TRACING) || USE_DEBUG_CONTEXT 
  30 // #pragma implementation 
  47 #if !defined(__WATCOMC__) && !defined(__VMS__) 
  67 #include "wx/memory.h" 
  75 // wxDebugContext wxTheDebugContext; 
  77   Redefine new and delete so that we can pick up situations where: 
  78         - we overwrite or underwrite areas of malloc'd memory. 
  79         - we use uninitialise variables 
  80   Only do this in debug mode. 
  82   We change new to get enough memory to allocate a struct, followed 
  83   by the caller's requested memory, followed by a tag. The struct 
  84   is used to create a doubly linked list of these areas and also 
  85   contains another tag. The tags are used to determine when the area 
  86   has been over/under written. 
  91   Values which are used to set the markers which will be tested for 
  92   under/over write. There are 3 of these, one in the struct, one 
  93   immediately after the struct but before the caller requested memory and 
  94   one immediately after the requested memory. 
  96 #define MemStartCheck  0x23A8 
  97 #define MemMidCheck  0xA328 
  98 #define MemEndCheck 0x8A32 
  99 #define MemFillChar 0xAF 
 100 #define MemStructId  0x666D 
 103   External interface for the wxMemStruct class. Others are 
 104   defined inline within the class def. Here we only need to be able 
 105   to add and delete nodes from the list and handle errors in some way. 
 109   Used for internal "this shouldn't happen" type of errors. 
 111 void wxMemStruct::ErrorMsg (const char * mesg
) 
 113   wxTrace("wxWindows memory checking error: %s\n", mesg
); 
 116 //       << m_fileName << ' ' << m_lineNum << endl; 
 120   Used when we find an overwrite or an underwrite error. 
 122 void wxMemStruct::ErrorMsg () 
 124   wxTrace("wxWindows over/underwrite memory error: \n"); 
 127 //    cerr << m_fileName << ' ' << m_lineNum << endl; 
 132   We want to find out if pointers have been overwritten as soon as is 
 133   possible, so test everything before we dereference it. Of course it's still 
 134   quite possible that, if things have been overwritten, this function will 
 135   fall over, but the only way of dealing with that would cost too much in terms 
 138 int wxMemStruct::AssertList () 
 140     if (wxDebugContext::GetHead () != 0 && ! (wxDebugContext::GetHead ())->AssertIt () || 
 141         wxDebugContext::GetTail () != 0 && ! wxDebugContext::GetTail ()->AssertIt ()) { 
 142         ErrorMsg ("Head or tail pointers trashed"); 
 150   Check that the thing we're pointing to has the correct id for a wxMemStruct 
 151   object and also that it's previous and next pointers are pointing at objects 
 152   which have valid ids. 
 153   This is definitely not perfect since we could fall over just trying to access 
 154   any of the slots which we use here, but I think it's about the best that I 
 155   can do without doing something like taking all new wxMemStruct pointers and 
 156   comparing them against all known pointer within the list and then only 
 157   doing this sort of check _after_ you've found the pointer in the list. That 
 158   would be safer, but also much more time consuming. 
 160 int wxMemStruct::AssertIt () 
 162     return (m_id 
== MemStructId 
&& 
 163             (m_prev 
== 0 || m_prev
->m_id 
== MemStructId
) && 
 164             (m_next 
== 0 || m_next
->m_id 
== MemStructId
)); 
 169   Additions are always at the tail of the list. 
 170   Returns 0 on error, non-zero on success. 
 172 int wxMemStruct::Append () 
 177     if (wxDebugContext::GetHead () == 0) { 
 178         if (wxDebugContext::GetTail () != 0) { 
 179             ErrorMsg ("Null list should have a null tail pointer"); 
 182         (void) wxDebugContext::SetHead (this); 
 183         (void) wxDebugContext::SetTail (this); 
 185         wxDebugContext::GetTail ()->m_next 
= this; 
 186         this->m_prev 
= wxDebugContext::GetTail (); 
 187         (void) wxDebugContext::SetTail (this); 
 194   Don't actually free up anything here as the space which is used 
 195   by the node will be free'd up when the whole block is free'd. 
 196   Returns 0 on error, non-zero on success. 
 198 int wxMemStruct::Unlink () 
 203     if (wxDebugContext::GetHead () == 0 || wxDebugContext::GetTail () == 0) { 
 204         ErrorMsg ("Trying to remove node from empty list"); 
 208     // Handle the part of the list before this node. 
 210         if (this != wxDebugContext::GetHead ()) { 
 211             ErrorMsg ("No previous node for non-head node"); 
 214         (void) wxDebugContext::SetHead (m_next
); 
 216         if (! m_prev
->AssertIt ()) { 
 217             ErrorMsg ("Trashed previous pointer"); 
 221         if (m_prev
->m_next 
!= this) { 
 222             ErrorMsg ("List is inconsistent"); 
 225         m_prev
->m_next 
= m_next
; 
 228     // Handle the part of the list after this node. 
 230         if (this != wxDebugContext::GetTail ()) { 
 231             ErrorMsg ("No next node for non-tail node"); 
 234         (void) wxDebugContext::SetTail (m_prev
); 
 236         if (! m_next
->AssertIt ()) { 
 237             ErrorMsg ("Trashed next pointer"); 
 241         if (m_next
->m_prev 
!= this) { 
 242             ErrorMsg ("List is inconsistent"); 
 245         m_next
->m_prev 
= m_prev
; 
 254   Checks a node and block of memory to see that the markers are still 
 257 int wxMemStruct::CheckBlock () 
 261     if (m_firstMarker 
!= MemStartCheck
) { 
 266     char * pointer 
= wxDebugContext::MidMarkerPos ((char *) this); 
 267     if (* (wxMarkerType 
*) pointer 
!= MemMidCheck
) { 
 272     pointer 
= wxDebugContext::EndMarkerPos ((char *) this, RequestSize ()); 
 273     if (* (wxMarkerType 
*) pointer 
!= MemEndCheck
) { 
 283   Check the list of nodes to see if they are all ok. 
 285 int wxMemStruct::CheckAllPrevious () 
 289     for (wxMemStruct 
* st 
= this->m_prev
; st 
!= 0; st 
= st
->m_prev
) { 
 291             nFailures 
+= st
->CheckBlock (); 
 301   When we delete a node we set the id slot to a specific value and then test 
 302   against this to see if a nodes have been deleted previously. I don't 
 303   just set the entire memory to the fillChar because then I'd be overwriting 
 304   useful stuff like the vtbl which may be needed to output the error message 
 305   including the file name and line numbers. Without this info the whole point 
 306   of this class is lost! 
 308 void wxMemStruct::SetDeleted () 
 313 int wxMemStruct::IsDeleted () 
 315     return (m_id 
== MemFillChar
); 
 320   Print out a single node. There are many far better ways of doing this 
 321   but this will suffice for now. 
 323 void wxMemStruct::PrintNode () 
 327     wxObject 
*obj 
= (wxObject 
*)m_actualData
; 
 328     wxClassInfo 
*info 
= obj
->GetClassInfo(); 
 330     if (info 
&& info
->GetClassName()) 
 331       wxTrace("%s", info
->GetClassName()); 
 336       wxTrace(" (%s %d)", m_fileName
, (int)m_lineNum
); 
 338     wxTrace(" at $%lX, size %d\n", (long)GetActualData(), (int)RequestSize()); 
 342     wxTrace("Non-object data"); 
 344       wxTrace(" (%s %d)", m_fileName
, (int)m_lineNum
); 
 345     wxTrace(" at $%lX, size %d\n", (long)GetActualData(), (int)RequestSize()); 
 349 void wxMemStruct::Dump () 
 351   if (!ValidateNode()) return; 
 355     wxObject 
*obj 
= (wxObject 
*)m_actualData
; 
 356 //    wxClassInfo *info = obj->GetClassInfo(); 
 359       wxTrace("Item (%s %d)", m_fileName
, (int)m_lineNum
); 
 363     wxTrace(" at $%lX, size %d: ", (long)GetActualData(), (int)RequestSize()); 
 364 //    wxTrace(info->GetClassName()); 
 365     obj
->Dump(wxDebugContext::GetStream()); 
 370     wxTrace("Non-object data"); 
 372       wxTrace(" (%s %d)", m_fileName
, (int)m_lineNum
); 
 373     wxTrace(" at $%lX, size %d\n", (long)GetActualData(), (int)RequestSize()); 
 379   Validate a node. Check to see that the node is "clean" in the sense 
 380   that nothing has over/underwritten it etc. 
 382 int wxMemStruct::ValidateNode () 
 384     char * startPointer 
= (char *) this; 
 387             ErrorMsg ("Object already deleted"); 
 389             // Can't use the error routines as we have no recognisable object. 
 391              wxTrace("Can't verify memory struct - all bets are off!\n"); 
 399     for (i = 0; i < wxDebugContext::TotSize (requestSize ()); i++) 
 400       cout << startPointer [i]; 
 403     if (Marker () != MemStartCheck
) 
 405     if (* (wxMarkerType 
*) wxDebugContext::MidMarkerPos (startPointer
) != MemMidCheck
) 
 407     if (* (wxMarkerType 
*) wxDebugContext::EndMarkerPos (startPointer
, 
 412     // Back to before the extra buffer and check that 
 413     // we can still read what we originally wrote. 
 414     if (Marker () != MemStartCheck 
|| 
 415         * (wxMarkerType 
*) wxDebugContext::MidMarkerPos (startPointer
) 
 417         * (wxMarkerType 
*) wxDebugContext::EndMarkerPos (startPointer
, 
 418                                               RequestSize ()) != MemEndCheck
) 
 428   The wxDebugContext class. 
 431 wxMemStruct 
*wxDebugContext::m_head 
= NULL
; 
 432 wxMemStruct 
*wxDebugContext::m_tail 
= NULL
; 
 433 // ostream *wxDebugContext::m_debugStream = NULL; 
 434 // streambuf *wxDebugContext::m_streamBuf = NULL; 
 436 // Must initialise these in wxEntry, and then delete them just before wxEntry exits 
 437 streambuf 
*wxDebugContext::m_streamBuf 
= NULL
; 
 438 ostream 
*wxDebugContext::m_debugStream 
= NULL
; 
 440 bool wxDebugContext::m_checkPrevious 
= FALSE
; 
 441 int wxDebugContext::debugLevel 
= 1; 
 442 bool wxDebugContext::debugOn 
= TRUE
; 
 443 wxMemStruct 
*wxDebugContext::checkPoint 
= NULL
; 
 445 wxDebugContext::wxDebugContext(void) 
 447 //  m_streamBuf = new wxDebugStreamBuf; 
 448 //  m_debugStream = new ostream(m_streamBuf); 
 451 wxDebugContext::~wxDebugContext(void) 
 453   SetStream(NULL
, NULL
); 
 457  * It's bizarre, but with BC++ 4.5, the value of str changes 
 458  * between SetFile and SetStream. 
 461 void wxDebugContext::SetStream(ostream 
*str
, streambuf 
*buf
) 
 467     sprintf(buff, "SetStream (1): str is %ld", (long) str); 
 468     MessageBox(NULL, buff, "Memory", MB_OK); 
 474     m_debugStream
->flush(); 
 475     delete m_debugStream
; 
 477   m_debugStream 
= NULL
; 
 479   // Not allowed in Watcom (~streambuf is protected). 
 480   // Is this trying to say something significant to us?? 
 484     streambuf
* oldBuf 
= m_streamBuf
; 
 493 bool wxDebugContext::SetFile(const wxString
& file
) 
 495   ofstream 
*str 
= new ofstream((char *) (const char *)file
); 
 506   sprintf(buf, "SetFile: str is %ld", (long) str); 
 507   MessageBox(NULL, buf, "Memory", MB_OK); 
 514 bool wxDebugContext::SetStandardError(void) 
 516 #if !defined(_WINDLL) 
 517   wxDebugStreamBuf 
*buf 
= new wxDebugStreamBuf
; 
 518   ostream 
*stream 
= new ostream(m_streamBuf
); 
 519   SetStream(stream
, buf
); 
 528   Work out the positions of the markers by creating an array of 2 markers 
 529   and comparing the addresses of the 2 elements. Use this number as the 
 530   alignment for markers. 
 532 size_t wxDebugContext::CalcAlignment () 
 535     return (char *) &ar
[1] - (char *) &ar
[0]; 
 539 char * wxDebugContext::StructPos (const char * buf
) 
 544 char * wxDebugContext::MidMarkerPos (const char * buf
) 
 546     return StructPos (buf
) + PaddedSize (sizeof (wxMemStruct
)); 
 549 char * wxDebugContext::CallerMemPos (const char * buf
) 
 551     return MidMarkerPos (buf
) + PaddedSize (sizeof(wxMarkerType
)); 
 555 char * wxDebugContext::EndMarkerPos (const char * buf
, const size_t size
) 
 557     return CallerMemPos (buf
) + PaddedSize (size
); 
 562   Slightly different as this takes a pointer to the start of the caller 
 563   requested region and returns a pointer to the start of the buffer. 
 565 char * wxDebugContext::StartPos (const char * caller
) 
 567     return ((char *) (caller 
- wxDebugContext::PaddedSize (sizeof(wxMarkerType
)) - 
 568             wxDebugContext::PaddedSize (sizeof (wxMemStruct
)))); 
 572   We may need padding between various parts of the allocated memory. 
 573   Given a size of memory, this returns the amount of memory which should 
 574   be allocated in order to allow for alignment of the following object. 
 576   I don't know how portable this stuff is, but it seems to work for me at 
 577   the moment. It would be real nice if I knew more about this! 
 579 size_t wxDebugContext::GetPadding (const size_t size
) 
 581     size_t pad 
= size 
% CalcAlignment (); 
 582     return (pad
) ? sizeof(wxMarkerType
) - pad 
: 0; 
 587 size_t wxDebugContext::PaddedSize (const size_t size
) 
 589     return size 
+ GetPadding (size
); 
 593   Returns the total amount of memory which we need to get from the system 
 594   in order to satisfy a caller request. This includes space for the struct 
 595   plus markers and the caller's memory as well. 
 597 size_t wxDebugContext::TotSize (const size_t reqSize
) 
 599     return (PaddedSize (sizeof (wxMemStruct
)) + PaddedSize (reqSize
) + 
 600             2 * sizeof(wxMarkerType
)); 
 605   Traverse the list of nodes executing the given function on each node. 
 607 void wxDebugContext::TraverseList (PmSFV func
, wxMemStruct 
*from
) 
 610     from 
= wxDebugContext::GetHead (); 
 612   for (wxMemStruct 
* st 
= from
; st 
!= 0; st 
= st
->m_next
) 
 614       void* data 
= st
->GetActualData(); 
 615       if ((data 
!= (void*)m_debugStream
) && (data 
!= (void*) m_streamBuf
)) 
 626 bool wxDebugContext::PrintList (void) 
 632   TraverseList ((PmSFV
)&wxMemStruct::PrintNode
, (checkPoint 
? checkPoint
->m_next 
: (wxMemStruct
*)NULL
)); 
 640 bool wxDebugContext::Dump(void) 
 648     char* appName 
= "application"; 
 649     wxString 
appNameStr(""); 
 652         appNameStr 
= wxTheApp
->GetAppName(); 
 653         appName 
= (char*) (const char*) appNameStr
; 
 654         wxTrace("Memory dump of %s at %s:\n", appName
, WXSTRINGCAST 
wxNow() ); 
 657   TraverseList ((PmSFV
)&wxMemStruct::Dump
, (checkPoint 
? checkPoint
->m_next 
: (wxMemStruct
*)NULL
)); 
 665 struct wxDebugStatsStruct
 
 670   wxDebugStatsStruct 
*next
; 
 673 static wxDebugStatsStruct 
*FindStatsStruct(wxDebugStatsStruct 
*st
, char *name
) 
 677     if (strcmp(st
->instanceClass
, name
) == 0) 
 684 static wxDebugStatsStruct 
*InsertStatsStruct(wxDebugStatsStruct 
*head
, wxDebugStatsStruct 
*st
) 
 690 bool wxDebugContext::PrintStatistics(bool detailed
) 
 696   bool currentMode 
= GetDebugMode(); 
 699   long noNonObjectNodes 
= 0; 
 700   long noObjectNodes 
= 0; 
 703   wxDebugStatsStruct 
*list 
= NULL
; 
 705   wxMemStruct 
*from 
= (checkPoint 
? checkPoint
->m_next 
: (wxMemStruct
*)NULL 
); 
 707     from 
= wxDebugContext::GetHead (); 
 710   for (st 
= from
; st 
!= 0; st 
= st
->m_next
) 
 712     void* data 
= st
->GetActualData(); 
 713     if (detailed 
&& (data 
!= (void*)m_debugStream
) && (data 
!= (void*) m_streamBuf
)) 
 715       char *className 
= "nonobject"; 
 716       if (st
->m_isObject 
&& st
->GetActualData()) 
 718         wxObject 
*obj 
= (wxObject 
*)st
->GetActualData(); 
 719         if (obj
->GetClassInfo()->GetClassName()) 
 720           className 
= obj
->GetClassInfo()->GetClassName(); 
 722       wxDebugStatsStruct 
*stats 
= FindStatsStruct(list
, className
); 
 725         stats 
= (wxDebugStatsStruct 
*)malloc(sizeof(wxDebugStatsStruct
)); 
 726         stats
->instanceClass 
= className
; 
 727         stats
->instanceCount 
= 0; 
 728         stats
->totalSize 
= 0; 
 729         list 
= InsertStatsStruct(list
, stats
); 
 731       stats
->instanceCount 
++; 
 732       stats
->totalSize 
+= st
->RequestSize(); 
 735     if ((data 
!= (void*)m_debugStream
) && (data 
!= (void*) m_streamBuf
)) 
 737         totalSize 
+= st
->RequestSize(); 
 749       wxTrace("%ld objects of class %s, total size %ld\n", 
 750           list
->instanceCount
, list
->instanceClass
, list
->totalSize
); 
 751       wxDebugStatsStruct 
*old 
= list
; 
 758   SetDebugMode(currentMode
); 
 760   wxTrace("Number of object items: %ld\n", noObjectNodes
); 
 761   wxTrace("Number of non-object items: %ld\n", noNonObjectNodes
); 
 762   wxTrace("Total allocated size: %ld\n", totalSize
); 
 770 bool wxDebugContext::PrintClasses(void) 
 777     char* appName 
= "application"; 
 778     wxString 
appNameStr(""); 
 781         appNameStr 
= wxTheApp
->GetAppName(); 
 782         appName 
= (char*) (const char*) appNameStr
; 
 783         wxTrace("Classes in %s:\n\n", appName
); 
 791   wxClassInfo::sm_classTable
->BeginFind(); 
 792   node 
= wxClassInfo::sm_classTable
->Next(); 
 795     info 
= (wxClassInfo 
*)node
->Data(); 
 796     if (info
->GetClassName()) 
 798       wxTrace("%s ", info
->GetClassName()); 
 800       if (info
->GetBaseClassName1() && !info
->GetBaseClassName2()) 
 801         wxTrace("is a %s", info
->GetBaseClassName1()); 
 802       else if (info
->GetBaseClassName1() && info
->GetBaseClassName2()) 
 803         wxTrace("is a %s, %s", info
->GetBaseClassName1(), info
->GetBaseClassName2()); 
 804       if (info
->GetConstructor()) 
 805         wxTrace(": dynamic\n"); 
 812   wxTrace("\nThere are %d classes derived from wxObject.\n", n
); 
 816 void wxDebugContext::SetCheckpoint(bool all
) 
 824 // Checks all nodes since checkpoint, or since start. 
 825 int wxDebugContext::Check(bool checkAll
) 
 829   wxMemStruct 
*from 
= (checkPoint 
? checkPoint
->m_next 
: (wxMemStruct
*)NULL 
); 
 830   if (!from 
|| checkAll
) 
 831     from 
= wxDebugContext::GetHead (); 
 833   for (wxMemStruct 
* st 
= from
; st 
!= 0; st 
= st
->m_next
) 
 836       nFailures 
+= st
->CheckBlock (); 
 844 // Count the number of non-wxDebugContext-related objects 
 845 // that are outstanding 
 846 int wxDebugContext::CountObjectsLeft(void) 
 850   wxMemStruct 
*from 
= wxDebugContext::GetHead (); 
 852   for (wxMemStruct 
* st 
= from
; st 
!= 0; st 
= st
->m_next
) 
 854       void* data 
= st
->GetActualData(); 
 855       if ((data 
!= (void*)m_debugStream
) && (data 
!= (void*) m_streamBuf
)) 
 863   The global operator new used for everything apart from getting 
 864   dynamic storage within this function itself. 
 867 // We'll only do malloc and free for the moment: leave the interesting 
 868 // stuff for the wxObject versions. 
 870 #if WXDEBUG && USE_GLOBAL_MEMORY_OPERATORS 
 876 // Seems OK all of a sudden. Maybe to do with linking with multithreaded library? 
 877 #if 0 // def _MSC_VER 
 878 #define NO_DEBUG_ALLOCATION 
 881 // Unfortunately ~wxDebugStreamBuf doesn't work (VC++ 5) when we enable the debugging 
 882 // code. I have no idea why. In BC++ 4.5, we have a similar problem the debug 
 883 // stream myseriously changing pointer address between being passed from SetFile to SetStream. 
 884 // See docs/msw/issues.txt. 
 885 void * operator new (size_t size
, char * fileName
, int lineNum
) 
 887 #ifdef NO_DEBUG_ALLOCATION 
 890   return wxDebugAlloc(size
, fileName
, lineNum
, FALSE
, FALSE
); 
 894 #if !( defined (_MSC_VER) && (_MSC_VER <= 1000) ) 
 895 void * operator new[] (size_t size
, char * fileName
, int lineNum
) 
 897 #ifdef NO_DEBUG_ALLOCATION 
 900   return wxDebugAlloc(size
, fileName
, lineNum
, FALSE
, TRUE
); 
 905 void operator delete (void * buf
) 
 907 #ifdef NO_DEBUG_ALLOCATION 
 914 #if !( defined (_MSC_VER) && (_MSC_VER <= 1000) ) 
 915 void operator delete[] (void * buf
) 
 917 #ifdef NO_DEBUG_ALLOCATION 
 920   wxDebugFree(buf
, TRUE
); 
 927 // TODO: store whether this is a vector or not. 
 928 void * wxDebugAlloc(size_t size
, char * fileName
, int lineNum
, bool isObject
, bool WXUNUSED(isVect
) ) 
 930   // If not in debugging allocation mode, do the normal thing 
 931   // so we don't leave any trace of ourselves in the node list. 
 933   if (!wxDebugContext::GetDebugMode()) 
 935     return (void *)malloc(size
); 
 938     char * buf 
= (char *) malloc(wxDebugContext::TotSize (size
)); 
 940         wxTrace("Call to malloc (%ld) failed.\n", (long)size
); 
 943     wxMemStruct 
* st 
= (wxMemStruct 
*)buf
; 
 944     st
->m_firstMarker 
= MemStartCheck
; 
 945     st
->m_reqSize 
= size
; 
 946     st
->m_fileName 
= fileName
; 
 947     st
->m_lineNum 
= lineNum
; 
 948     st
->m_id 
= MemStructId
; 
 951     st
->m_isObject 
= isObject
; 
 953     // Errors from Append() shouldn't really happen - but just in case! 
 954     if (st
->Append () == 0) { 
 955         st
->ErrorMsg ("Trying to append new node"); 
 958     if (wxDebugContext::GetCheckPrevious ()) { 
 959         if (st
->CheckAllPrevious () < 0) { 
 960             st
->ErrorMsg ("Checking previous nodes"); 
 964     // Set up the extra markers at the middle and end. 
 965     char * ptr 
= wxDebugContext::MidMarkerPos (buf
); 
 966     * (wxMarkerType 
*) ptr 
= MemMidCheck
; 
 967     ptr 
= wxDebugContext::EndMarkerPos (buf
, size
); 
 968     * (wxMarkerType 
*) ptr 
= MemEndCheck
; 
 970     // pointer returned points to the start of the caller's 
 972     void *m_actualData 
= (void *) wxDebugContext::CallerMemPos (buf
); 
 973     st
->m_actualData 
= m_actualData
; 
 978 // TODO: check whether was allocated as a vector 
 979 void wxDebugFree(void * buf
, bool WXUNUSED(isVect
) ) 
 984   // If not in debugging allocation mode, do the normal thing 
 985   // so we don't leave any trace of ourselves in the node list. 
 986   if (!wxDebugContext::GetDebugMode()) 
 992     // Points to the start of the entire allocated area. 
 993     char * startPointer 
= wxDebugContext::StartPos ((char *) buf
); 
 994     // Find the struct and make sure that it's identifiable. 
 995     wxMemStruct 
* st 
= (wxMemStruct 
*) wxDebugContext::StructPos (startPointer
); 
 997     if (! st
->ValidateNode ()) 
1000     // If this is the current checkpoint, we need to 
1001     // move the checkpoint back so it points to a valid 
1003     if (st 
== wxDebugContext::checkPoint
) 
1004       wxDebugContext::checkPoint 
= wxDebugContext::checkPoint
->m_prev
; 
1006     if (! st
->Unlink ()) 
1008       st
->ErrorMsg ("Unlinking deleted node"); 
1011     // Now put in the fill char into the id slot and the caller requested 
1012     // memory locations. 
1014     (void) memset (wxDebugContext::CallerMemPos (startPointer
), MemFillChar
, 
1015                    st
->RequestSize ()); 
1017     // Don't allow delayed freeing of memory in this version 
1018 //    if (!wxDebugContext::GetDelayFree()) 
1019 //    free((void *)st); 
1023 // Trace: send output to the current debugging stream 
1024 void wxTrace(const char *fmt 
...) 
1027   static char buffer
[512]; 
1032   wvsprintf(buffer
,fmt
,ap
) ; 
1034   vsprintf(buffer
,fmt
,ap
) ; 
1039   if (wxDebugContext::HasStream()) 
1041     wxDebugContext::GetStream() << buffer
; 
1042     wxDebugContext::GetStream().flush(); 
1046     OutputDebugString((LPCSTR
)buffer
) ; 
1048     fprintf(stderr
, buffer
); 
1053 void wxTraceLevel(int level
, const char *fmt 
...) 
1055   if (wxDebugContext::GetLevel() < level
) 
1059   static char buffer
[512]; 
1064   wvsprintf(buffer
,fmt
,ap
) ; 
1066   vsprintf(buffer
,fmt
,ap
) ; 
1071   if (wxDebugContext::HasStream()) 
1073     wxDebugContext::GetStream() << buffer
; 
1074     wxDebugContext::GetStream().flush(); 
1078     OutputDebugString((LPCSTR
)buffer
) ; 
1080     fprintf(stderr
, buffer
); 
1084 #else // USE_MEMORY_TRACING && WXDEBUG 
1085 void wxTrace(const char *WXUNUSED(fmt
) ...) 
1089 void wxTraceLevel(int WXUNUSED(level
), const char *WXUNUSED(fmt
) ...)