1 ///////////////////////////////////////////////////////////////////////////// 
   3 // Purpose:     Memory checking implementation 
   4 // Author:      Arthur Seaton, Julian Smart 
   8 // Copyright:   (c) Julian Smart 
   9 // Licence:     wxWindows licence 
  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 
  40 #include "wx/thread.h" 
  46 #include "wx/ioswrap.h" 
  48 #if !defined(__WATCOMC__) && !(defined(__VMS__) && ( __VMS_VER < 70000000 ) )\ 
  49      && !defined( __MWERKS__ ) && !defined(__SALFORDC__) 
  69 #include "wx/memory.h" 
  71 #if wxUSE_THREADS && defined(__WXDEBUG__) && !defined(__WXMAC__) 
  72 #define USE_THREADSAFE_MEMORY_ALLOCATION 1 
  74 #define USE_THREADSAFE_MEMORY_ALLOCATION 0 
  82 // wxDebugContext wxTheDebugContext; 
  84   Redefine new and delete so that we can pick up situations where: 
  85         - we overwrite or underwrite areas of malloc'd memory. 
  86         - we use uninitialise variables 
  87   Only do this in debug mode. 
  89   We change new to get enough memory to allocate a struct, followed 
  90   by the caller's requested memory, followed by a tag. The struct 
  91   is used to create a doubly linked list of these areas and also 
  92   contains another tag. The tags are used to determine when the area 
  93   has been over/under written. 
  98   Values which are used to set the markers which will be tested for 
  99   under/over write. There are 3 of these, one in the struct, one 
 100   immediately after the struct but before the caller requested memory and 
 101   one immediately after the requested memory. 
 103 #define MemStartCheck  0x23A8 
 104 #define MemMidCheck  0xA328 
 105 #define MemEndCheck 0x8A32 
 106 #define MemFillChar 0xAF 
 107 #define MemStructId  0x666D 
 110   External interface for the wxMemStruct class. Others are 
 111   defined inline within the class def. Here we only need to be able 
 112   to add and delete nodes from the list and handle errors in some way. 
 116   Used for internal "this shouldn't happen" type of errors. 
 118 void wxMemStruct::ErrorMsg (const char * mesg
) 
 120   wxLogMessage(wxT("wxWindows memory checking error: %s"), mesg
); 
 125   Used when we find an overwrite or an underwrite error. 
 127 void wxMemStruct::ErrorMsg () 
 129   wxLogMessage(wxT("wxWindows over/underwrite memory error:")); 
 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 
 335     wxString 
msg(wxT("")); 
 338       msg
.Printf(wxT("%s(%d): "), m_fileName
, (int)m_lineNum
); 
 340     if (info 
&& info
->GetClassName()) 
 341       msg 
+= info
->GetClassName(); 
 343       msg 
+= wxT("object"); 
 346     msg2
.Printf(wxT(" at $%lX, size %d"), (long)GetActualData(), (int)RequestSize()); 
 353     wxString 
msg(wxT("")); 
 356       msg
.Printf(wxT("%s(%d): "), m_fileName
, (int)m_lineNum
); 
 357     msg 
+= wxT("non-object data"); 
 359     msg2
.Printf(wxT(" at $%lX, size %d\n"), (long)GetActualData(), (int)RequestSize()); 
 366 void wxMemStruct::Dump () 
 368   if (!ValidateNode()) return; 
 372     wxObject 
*obj 
= (wxObject 
*)m_actualData
; 
 374     wxString 
msg(wxT("")); 
 376       msg
.Printf(wxT("%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 
+= wxT("unknown object class"); 
 391     wxString 
msg2(wxT("")); 
 392     msg2
.Printf(wxT(" at $%lX, size %d"), (long)GetActualData(), (int)RequestSize()); 
 399     wxString 
msg(wxT("")); 
 401       msg
.Printf(wxT("%s(%d): "), m_fileName
, (int)m_lineNum
); 
 403     wxString 
msg2(wxT("")); 
 404     msg2
.Printf(wxT("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              wxLogMessage(wxT("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
; 
 467 bool wxDebugContext::m_checkPrevious 
= FALSE
; 
 468 int wxDebugContext::debugLevel 
= 1; 
 469 bool wxDebugContext::debugOn 
= TRUE
; 
 470 wxMemStruct 
*wxDebugContext::checkPoint 
= NULL
; 
 472 // For faster alignment calculation 
 473 static wxMarkerType markerCalc
[2]; 
 474 int wxDebugContext::m_balign 
= (int)((char *)&markerCalc
[1] - (char*)&markerCalc
[0]); 
 475 int wxDebugContext::m_balignmask 
= (int)((char *)&markerCalc
[1] - (char*)&markerCalc
[0]) - 1; 
 477 wxDebugContext::wxDebugContext(void) 
 481 wxDebugContext::~wxDebugContext(void) 
 486   Work out the positions of the markers by creating an array of 2 markers 
 487   and comparing the addresses of the 2 elements. Use this number as the 
 488   alignment for markers. 
 490 size_t wxDebugContext::CalcAlignment () 
 493     return (char *) &ar
[1] - (char *) &ar
[0]; 
 497 char * wxDebugContext::StructPos (const char * buf
) 
 502 char * wxDebugContext::MidMarkerPos (const char * buf
) 
 504     return StructPos (buf
) + PaddedSize (sizeof (wxMemStruct
)); 
 507 char * wxDebugContext::CallerMemPos (const char * buf
) 
 509     return MidMarkerPos (buf
) + PaddedSize (sizeof(wxMarkerType
)); 
 513 char * wxDebugContext::EndMarkerPos (const char * buf
, const size_t size
) 
 515     return CallerMemPos (buf
) + PaddedSize (size
); 
 520   Slightly different as this takes a pointer to the start of the caller 
 521   requested region and returns a pointer to the start of the buffer. 
 523 char * wxDebugContext::StartPos (const char * caller
) 
 525     return ((char *) (caller 
- wxDebugContext::PaddedSize (sizeof(wxMarkerType
)) - 
 526             wxDebugContext::PaddedSize (sizeof (wxMemStruct
)))); 
 530   We may need padding between various parts of the allocated memory. 
 531   Given a size of memory, this returns the amount of memory which should 
 532   be allocated in order to allow for alignment of the following object. 
 534   I don't know how portable this stuff is, but it seems to work for me at 
 535   the moment. It would be real nice if I knew more about this! 
 537   // Note: this function is now obsolete (along with CalcAlignment) 
 538   // because the calculations are done statically, for greater speed. 
 540 size_t wxDebugContext::GetPadding (const size_t size
) 
 542     size_t pad 
= size 
% CalcAlignment (); 
 543     return (pad
) ? sizeof(wxMarkerType
) - pad 
: 0; 
 546 size_t wxDebugContext::PaddedSize (const size_t size
) 
 548     // Added by Terry Farnham <TJRT@pacbell.net> to replace 
 549     // slow GetPadding call. 
 552     padb 
= size 
& m_balignmask
; 
 554         return(size 
+ m_balign 
- padb
); 
 560   Returns the total amount of memory which we need to get from the system 
 561   in order to satisfy a caller request. This includes space for the struct 
 562   plus markers and the caller's memory as well. 
 564 size_t wxDebugContext::TotSize (const size_t reqSize
) 
 566     return (PaddedSize (sizeof (wxMemStruct
)) + PaddedSize (reqSize
) + 
 567             2 * sizeof(wxMarkerType
)); 
 572   Traverse the list of nodes executing the given function on each node. 
 574 void wxDebugContext::TraverseList (PmSFV func
, wxMemStruct 
*from
) 
 577     from 
= wxDebugContext::GetHead (); 
 579   wxMemStruct 
* st 
= NULL
; 
 580   for (st 
= from
; st 
!= 0; st 
= st
->m_next
) 
 582       void* data 
= st
->GetActualData(); 
 583 //      if ((data != (void*)m_debugStream) && (data != (void*) m_streamBuf)) 
 584       if (data 
!= (void*) wxLog::GetActiveTarget()) 
 595 bool wxDebugContext::PrintList (void) 
 598   TraverseList ((PmSFV
)&wxMemStruct::PrintNode
, (checkPoint 
? checkPoint
->m_next 
: (wxMemStruct
*)NULL
)); 
 606 bool wxDebugContext::Dump(void) 
 610     wxChar
* appName 
= (wxChar
*) wxT("application"); 
 611     wxString 
appNameStr(wxT("")); 
 614         appNameStr 
= wxTheApp
->GetAppName(); 
 615         appName 
= WXSTRINGCAST appNameStr
; 
 616         wxLogMessage(wxT("----- Memory dump of %s at %s -----"), appName
, WXSTRINGCAST 
wxNow() ); 
 620       wxLogMessage( wxT("----- Memory dump -----") ); 
 624   TraverseList ((PmSFV
)&wxMemStruct::Dump
, (checkPoint 
? checkPoint
->m_next 
: (wxMemStruct
*)NULL
)); 
 626   wxLogMessage( wxT("") ); 
 627   wxLogMessage( wxT("") ); 
 636 struct wxDebugStatsStruct
 
 640   wxChar 
*instanceClass
; 
 641   wxDebugStatsStruct 
*next
; 
 644 static wxDebugStatsStruct 
*FindStatsStruct(wxDebugStatsStruct 
*st
, wxChar 
*name
) 
 648     if (wxStrcmp(st
->instanceClass
, name
) == 0) 
 655 static wxDebugStatsStruct 
*InsertStatsStruct(wxDebugStatsStruct 
*head
, wxDebugStatsStruct 
*st
) 
 662 bool wxDebugContext::PrintStatistics(bool detailed
) 
 666     wxChar
* appName 
= (wxChar
*) wxT("application"); 
 667     wxString 
appNameStr(wxT("")); 
 670         appNameStr 
= wxTheApp
->GetAppName(); 
 671         appName 
= WXSTRINGCAST appNameStr
; 
 672         wxLogMessage(wxT("----- Memory statistics of %s at %s -----"), appName
, WXSTRINGCAST 
wxNow() ); 
 676       wxLogMessage( wxT("----- Memory statistics -----") ); 
 680   bool currentMode 
= GetDebugMode(); 
 683   long noNonObjectNodes 
= 0; 
 684   long noObjectNodes 
= 0; 
 687   wxDebugStatsStruct 
*list 
= NULL
; 
 689   wxMemStruct 
*from 
= (checkPoint 
? checkPoint
->m_next 
: (wxMemStruct
*)NULL 
); 
 691     from 
= wxDebugContext::GetHead (); 
 694   for (st 
= from
; st 
!= 0; st 
= st
->m_next
) 
 696     void* data 
= st
->GetActualData(); 
 697     if (detailed 
&& (data 
!= (void*) wxLog::GetActiveTarget())) 
 699       wxChar 
*className 
= (wxChar
*) wxT("nonobject"); 
 700       if (st
->m_isObject 
&& st
->GetActualData()) 
 702         wxObject 
*obj 
= (wxObject 
*)st
->GetActualData(); 
 703         if (obj
->GetClassInfo()->GetClassName()) 
 704           className 
= (wxChar
*)obj
->GetClassInfo()->GetClassName(); 
 706       wxDebugStatsStruct 
*stats 
= FindStatsStruct(list
, className
); 
 709         stats 
= (wxDebugStatsStruct 
*)malloc(sizeof(wxDebugStatsStruct
)); 
 710         stats
->instanceClass 
= className
; 
 711         stats
->instanceCount 
= 0; 
 712         stats
->totalSize 
= 0; 
 713         list 
= InsertStatsStruct(list
, stats
); 
 715       stats
->instanceCount 
++; 
 716       stats
->totalSize 
+= st
->RequestSize(); 
 719     if (data 
!= (void*) wxLog::GetActiveTarget()) 
 721         totalSize 
+= st
->RequestSize(); 
 733       wxLogMessage(wxT("%ld objects of class %s, total size %ld"), 
 734           list
->instanceCount
, list
->instanceClass
, list
->totalSize
); 
 735       wxDebugStatsStruct 
*old 
= list
; 
 739     wxLogMessage(wxT("")); 
 742   SetDebugMode(currentMode
); 
 744   wxLogMessage(wxT("Number of object items: %ld"), noObjectNodes
); 
 745   wxLogMessage(wxT("Number of non-object items: %ld"), noNonObjectNodes
); 
 746   wxLogMessage(wxT("Total allocated size: %ld"), totalSize
); 
 747   wxLogMessage(wxT("")); 
 748   wxLogMessage(wxT("")); 
 757 bool wxDebugContext::PrintClasses(void) 
 760     wxChar
* appName 
= (wxChar
*) wxT("application"); 
 761     wxString 
appNameStr(wxT("")); 
 764         appNameStr 
= wxTheApp
->GetAppName(); 
 765         appName 
= WXSTRINGCAST appNameStr
; 
 766         wxLogMessage(wxT("----- Classes in %s -----"), appName
); 
 774   wxClassInfo::sm_classTable
->BeginFind(); 
 775   node 
= wxClassInfo::sm_classTable
->Next(); 
 778     info 
= (wxClassInfo 
*)node
->GetData(); 
 779     if (info
->GetClassName()) 
 781         wxString 
msg(info
->GetClassName()); 
 784         if (info
->GetBaseClassName1() && !info
->GetBaseClassName2()) 
 787             msg 
+= info
->GetBaseClassName1(); 
 789         else if (info
->GetBaseClassName1() && info
->GetBaseClassName2()) 
 792             msg 
+= info
->GetBaseClassName1() ; 
 794             msg 
+= info
->GetBaseClassName2() ; 
 796         if (info
->GetConstructor()) 
 797             msg 
+= wxT(": dynamic"); 
 801     node 
= wxClassInfo::sm_classTable
->Next(); 
 804   wxLogMessage(wxT("")); 
 805   wxLogMessage(wxT("There are %d classes derived from wxObject."), n
); 
 806   wxLogMessage(wxT("")); 
 807   wxLogMessage(wxT("")); 
 811 void wxDebugContext::SetCheckpoint(bool all
) 
 819 // Checks all nodes since checkpoint, or since start. 
 820 int wxDebugContext::Check(bool checkAll
) 
 824   wxMemStruct 
*from 
= (checkPoint 
? checkPoint
->m_next 
: (wxMemStruct
*)NULL 
); 
 825   if (!from 
|| checkAll
) 
 826     from 
= wxDebugContext::GetHead (); 
 828   for (wxMemStruct 
* st 
= from
; st 
!= 0; st 
= st
->m_next
) 
 831       nFailures 
+= st
->CheckBlock (); 
 839 // Count the number of non-wxDebugContext-related objects 
 840 // that are outstanding 
 841 int wxDebugContext::CountObjectsLeft(bool sinceCheckpoint
) 
 845   wxMemStruct 
*from 
= NULL
; 
 846   if (sinceCheckpoint 
&& checkPoint
) 
 847     from 
= checkPoint
->m_next
; 
 849     from 
= wxDebugContext::GetHead () ; 
 851   for (wxMemStruct 
* st 
= from
; st 
!= 0; st 
= st
->m_next
) 
 853       void* data 
= st
->GetActualData(); 
 854       if (data 
!= (void*) wxLog::GetActiveTarget()) 
 861 #if USE_THREADSAFE_MEMORY_ALLOCATION 
 862 static bool memSectionOk 
= FALSE
; 
 864 class MemoryCriticalSection 
: public wxCriticalSection
 
 867         MemoryCriticalSection() { 
 872 class MemoryCriticalSectionLocker
 
 875     inline MemoryCriticalSectionLocker(wxCriticalSection
& critsect
) 
 876         : m_critsect(critsect
), m_locked(memSectionOk
) { if(m_locked
) m_critsect
.Enter(); } 
 877     inline ~MemoryCriticalSectionLocker() { if(m_locked
) m_critsect
.Leave(); } 
 880     // no assignment operator nor copy ctor 
 881     MemoryCriticalSectionLocker(const MemoryCriticalSectionLocker
&); 
 882     MemoryCriticalSectionLocker
& operator=(const MemoryCriticalSectionLocker
&); 
 884     wxCriticalSection
& m_critsect
; 
 888 static MemoryCriticalSection memLocker
; 
 891 // TODO: store whether this is a vector or not. 
 892 void * wxDebugAlloc(size_t size
, wxChar 
* fileName
, int lineNum
, bool isObject
, bool WXUNUSED(isVect
) ) 
 894 #if USE_THREADSAFE_MEMORY_ALLOCATION 
 895   MemoryCriticalSectionLocker 
lock(memLocker
); 
 898   // If not in debugging allocation mode, do the normal thing 
 899   // so we don't leave any trace of ourselves in the node list. 
 901 #if defined(__VISAGECPP__) && (__IBMCPP__ < 400 || __IBMC__ < 400 ) 
 902 // VA 3.0 still has trouble in here 
 903   return (void *)malloc(size
); 
 905   if (!wxDebugContext::GetDebugMode()) 
 907     return (void *)malloc(size
); 
 910     int totSize 
= wxDebugContext::TotSize (size
); 
 911     char * buf 
= (char *) malloc(totSize
); 
 913         wxLogMessage(wxT("Call to malloc (%ld) failed."), (long)size
); 
 916     wxMemStruct 
* st 
= (wxMemStruct 
*)buf
; 
 917     st
->m_firstMarker 
= MemStartCheck
; 
 918     st
->m_reqSize 
= size
; 
 919     st
->m_fileName 
= fileName
; 
 920     st
->m_lineNum 
= lineNum
; 
 921     st
->m_id 
= MemStructId
; 
 924     st
->m_isObject 
= isObject
; 
 926     // Errors from Append() shouldn't really happen - but just in case! 
 927     if (st
->Append () == 0) { 
 928         st
->ErrorMsg ("Trying to append new node"); 
 931     if (wxDebugContext::GetCheckPrevious ()) { 
 932         if (st
->CheckAllPrevious () < 0) { 
 933             st
->ErrorMsg ("Checking previous nodes"); 
 937     // Set up the extra markers at the middle and end. 
 938     char * ptr 
= wxDebugContext::MidMarkerPos (buf
); 
 939     * (wxMarkerType 
*) ptr 
= MemMidCheck
; 
 940     ptr 
= wxDebugContext::EndMarkerPos (buf
, size
); 
 941     * (wxMarkerType 
*) ptr 
= MemEndCheck
; 
 943     // pointer returned points to the start of the caller's 
 945     void *m_actualData 
= (void *) wxDebugContext::CallerMemPos (buf
); 
 946     st
->m_actualData 
= m_actualData
; 
 951 // TODO: check whether was allocated as a vector 
 952 void wxDebugFree(void * buf
, bool WXUNUSED(isVect
) ) 
 954 #if USE_THREADSAFE_MEMORY_ALLOCATION 
 955   MemoryCriticalSectionLocker 
lock(memLocker
); 
 961 #if defined(__VISAGECPP__) && (__IBMCPP__ < 400 || __IBMC__ < 400 ) 
 962 // VA 3.0 still has trouble in here 
 965   // If not in debugging allocation mode, do the normal thing 
 966   // so we don't leave any trace of ourselves in the node list. 
 967   if (!wxDebugContext::GetDebugMode()) 
 973     // Points to the start of the entire allocated area. 
 974     char * startPointer 
= wxDebugContext::StartPos ((char *) buf
); 
 975     // Find the struct and make sure that it's identifiable. 
 976     wxMemStruct 
* st 
= (wxMemStruct 
*) wxDebugContext::StructPos (startPointer
); 
 978     if (! st
->ValidateNode ()) 
 981     // If this is the current checkpoint, we need to 
 982     // move the checkpoint back so it points to a valid 
 984     if (st 
== wxDebugContext::checkPoint
) 
 985       wxDebugContext::checkPoint 
= wxDebugContext::checkPoint
->m_prev
; 
 989       st
->ErrorMsg ("Unlinking deleted node"); 
 992     // Now put in the fill char into the id slot and the caller requested 
 995     (void) memset (wxDebugContext::CallerMemPos (startPointer
), MemFillChar
, 
1001 // Trace: send output to the current debugging stream 
1002 void wxTrace(const wxChar 
* ...) 
1005     wxFAIL_MSG(wxT("wxTrace is now obsolete. Please use wxDebugXXX instead.")); 
1008   static wxChar buffer
[512]; 
1013   wvsprintf(buffer
,fmt
,ap
) ; 
1015   vsprintf(buffer
,fmt
,ap
) ; 
1020   if (wxDebugContext::HasStream()) 
1022     wxDebugContext::GetStream() << buffer
; 
1023     wxDebugContext::GetStream().flush(); 
1028     OutputDebugString((LPCTSTR
)buffer
) ; 
1030     OutputDebugString((const char*) buffer
) ; 
1033     fprintf(stderr
, buffer
); 
1039 void wxTraceLevel(int, const wxChar 
* ...) 
1042     wxFAIL_MSG(wxT("wxTrace is now obsolete. Please use wxDebugXXX instead.")); 
1044   if (wxDebugContext::GetLevel() < level
) 
1048   static wxChar buffer
[512]; 
1053   wxWvsprintf(buffer
,fmt
,ap
) ; 
1055   vsprintf(buffer
,fmt
,ap
) ; 
1060   if (wxDebugContext::HasStream()) 
1062     wxDebugContext::GetStream() << buffer
; 
1063     wxDebugContext::GetStream().flush(); 
1068     OutputDebugString((LPCTSTR
)buffer
) ; 
1070     OutputDebugString((const char*) buffer
) ; 
1073     fprintf(stderr
, buffer
); 
1078 #else // wxUSE_MEMORY_TRACING && defined(__WXDEBUG__) 
1079 void wxTrace(const char *WXUNUSED(fmt
) ...) 
1083 void wxTraceLevel(int WXUNUSED(level
), const char *WXUNUSED(fmt
) ...)