1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: Memory checking implementation
4 // Author: Arthur Seaton, Julian Smart
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
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
29 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
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__)
57 #include "wx/msw/wrapwin.h"
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 0x%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 0x%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 0x%lX, size %d"), (long)GetActualData(), (int)RequestSize());
395 wxDebugContext::OutputDumpLine(msg
);
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 0x%lX, size %d"), (long)GetActualData(), (int)RequestSize() );
406 wxDebugContext::OutputDumpLine(msg
);
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 OutputDumpLine(wxT("----- Memory dump of %s at %s -----"), appName
, WXSTRINGCAST
wxNow() );
620 OutputDumpLine( wxT("----- Memory dump -----") );
624 TraverseList ((PmSFV
)&wxMemStruct::Dump
, (checkPoint
? checkPoint
->m_next
: (wxMemStruct
*)NULL
));
626 OutputDumpLine( wxT("") );
627 OutputDumpLine( 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 OutputDumpLine(wxT("----- Memory statistics of %s at %s -----"), appName
, WXSTRINGCAST
wxNow() );
676 OutputDumpLine( 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 OutputDumpLine(wxT("%ld objects of class %s, total size %ld"),
734 list
->instanceCount
, list
->instanceClass
, list
->totalSize
);
735 wxDebugStatsStruct
*old
= list
;
739 OutputDumpLine(wxT(""));
742 SetDebugMode(currentMode
);
744 OutputDumpLine(wxT("Number of object items: %ld"), noObjectNodes
);
745 OutputDumpLine(wxT("Number of non-object items: %ld"), noNonObjectNodes
);
746 OutputDumpLine(wxT("Total allocated size: %ld"), totalSize
);
747 OutputDumpLine(wxT(""));
748 OutputDumpLine(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
);
771 wxHashTable::compatibility_iterator node
;
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 // This function is used to output the dump
862 void wxDebugContext::OutputDumpLine(const wxChar
*szFormat
, ...)
864 // a buffer of 2048 bytes should be long enough for a file name
869 va_start(argptr
, szFormat
);
870 buf
[sizeof(buf
)-1] = _T('\0');
872 // keep 3 bytes for a \r\n\0
873 count
= wxVsnprintf(buf
, sizeof(buf
)-3, szFormat
, argptr
);
876 count
= sizeof(buf
)-3;
878 buf
[count
+1]=_T('\n');
879 buf
[count
+2]=_T('\0');
881 wxMessageOutputDebug dbgout
;
886 #if USE_THREADSAFE_MEMORY_ALLOCATION
887 static bool memSectionOk
= FALSE
;
889 class MemoryCriticalSection
: public wxCriticalSection
892 MemoryCriticalSection() {
897 class MemoryCriticalSectionLocker
900 inline MemoryCriticalSectionLocker(wxCriticalSection
& critsect
)
901 : m_critsect(critsect
), m_locked(memSectionOk
) { if(m_locked
) m_critsect
.Enter(); }
902 inline ~MemoryCriticalSectionLocker() { if(m_locked
) m_critsect
.Leave(); }
905 // no assignment operator nor copy ctor
906 MemoryCriticalSectionLocker(const MemoryCriticalSectionLocker
&);
907 MemoryCriticalSectionLocker
& operator=(const MemoryCriticalSectionLocker
&);
909 wxCriticalSection
& m_critsect
;
913 static MemoryCriticalSection memLocker
;
916 // TODO: store whether this is a vector or not.
917 void * wxDebugAlloc(size_t size
, wxChar
* fileName
, int lineNum
, bool isObject
, bool WXUNUSED(isVect
) )
919 #if USE_THREADSAFE_MEMORY_ALLOCATION
920 MemoryCriticalSectionLocker
lock(memLocker
);
923 // If not in debugging allocation mode, do the normal thing
924 // so we don't leave any trace of ourselves in the node list.
926 #if defined(__VISAGECPP__) && (__IBMCPP__ < 400 || __IBMC__ < 400 )
927 // VA 3.0 still has trouble in here
928 return (void *)malloc(size
);
930 if (!wxDebugContext::GetDebugMode())
932 return (void *)malloc(size
);
935 int totSize
= wxDebugContext::TotSize (size
);
936 char * buf
= (char *) malloc(totSize
);
938 wxLogMessage(wxT("Call to malloc (%ld) failed."), (long)size
);
941 wxMemStruct
* st
= (wxMemStruct
*)buf
;
942 st
->m_firstMarker
= MemStartCheck
;
943 st
->m_reqSize
= size
;
944 st
->m_fileName
= fileName
;
945 st
->m_lineNum
= lineNum
;
946 st
->m_id
= MemStructId
;
949 st
->m_isObject
= isObject
;
951 // Errors from Append() shouldn't really happen - but just in case!
952 if (st
->Append () == 0) {
953 st
->ErrorMsg ("Trying to append new node");
956 if (wxDebugContext::GetCheckPrevious ()) {
957 if (st
->CheckAllPrevious () < 0) {
958 st
->ErrorMsg ("Checking previous nodes");
962 // Set up the extra markers at the middle and end.
963 char * ptr
= wxDebugContext::MidMarkerPos (buf
);
964 * (wxMarkerType
*) ptr
= MemMidCheck
;
965 ptr
= wxDebugContext::EndMarkerPos (buf
, size
);
966 * (wxMarkerType
*) ptr
= MemEndCheck
;
968 // pointer returned points to the start of the caller's
970 void *m_actualData
= (void *) wxDebugContext::CallerMemPos (buf
);
971 st
->m_actualData
= m_actualData
;
976 // TODO: check whether was allocated as a vector
977 void wxDebugFree(void * buf
, bool WXUNUSED(isVect
) )
979 #if USE_THREADSAFE_MEMORY_ALLOCATION
980 MemoryCriticalSectionLocker
lock(memLocker
);
986 #if defined(__VISAGECPP__) && (__IBMCPP__ < 400 || __IBMC__ < 400 )
987 // VA 3.0 still has trouble in here
990 // If not in debugging allocation mode, do the normal thing
991 // so we don't leave any trace of ourselves in the node list.
992 if (!wxDebugContext::GetDebugMode())
998 // Points to the start of the entire allocated area.
999 char * startPointer
= wxDebugContext::StartPos ((char *) buf
);
1000 // Find the struct and make sure that it's identifiable.
1001 wxMemStruct
* st
= (wxMemStruct
*) wxDebugContext::StructPos (startPointer
);
1003 if (! st
->ValidateNode ())
1006 // If this is the current checkpoint, we need to
1007 // move the checkpoint back so it points to a valid
1009 if (st
== wxDebugContext::checkPoint
)
1010 wxDebugContext::checkPoint
= wxDebugContext::checkPoint
->m_prev
;
1012 if (! st
->Unlink ())
1014 st
->ErrorMsg ("Unlinking deleted node");
1017 // Now put in the fill char into the id slot and the caller requested
1018 // memory locations.
1020 (void) memset (wxDebugContext::CallerMemPos (startPointer
), MemFillChar
,
1021 st
->RequestSize ());
1026 // Trace: send output to the current debugging stream
1027 void wxTrace(const wxChar
* ...)
1030 wxFAIL_MSG(wxT("wxTrace is now obsolete. Please use wxDebugXXX instead."));
1033 static wxChar buffer
[512];
1038 wvsprintf(buffer
,fmt
,ap
) ;
1040 vsprintf(buffer
,fmt
,ap
) ;
1045 if (wxDebugContext::HasStream())
1047 wxDebugContext::GetStream() << buffer
;
1048 wxDebugContext::GetStream().flush();
1053 OutputDebugString((LPCTSTR
)buffer
) ;
1055 OutputDebugString((const char*) buffer
) ;
1058 fprintf(stderr
, buffer
);
1064 void wxTraceLevel(int, const wxChar
* ...)
1067 wxFAIL_MSG(wxT("wxTrace is now obsolete. Please use wxDebugXXX instead."));
1069 if (wxDebugContext::GetLevel() < level
)
1073 static wxChar buffer
[512];
1078 wxWvsprintf(buffer
,fmt
,ap
) ;
1080 vsprintf(buffer
,fmt
,ap
) ;
1085 if (wxDebugContext::HasStream())
1087 wxDebugContext::GetStream() << buffer
;
1088 wxDebugContext::GetStream().flush();
1093 OutputDebugString((LPCTSTR
)buffer
) ;
1095 OutputDebugString((const char*) buffer
) ;
1098 fprintf(stderr
, buffer
);
1103 //----------------------------------------------------------------------------
1104 // Final cleanup after all global objects in all files have been destructed
1105 //----------------------------------------------------------------------------
1107 // Don't set it to 0 by dynamic initialization
1108 // Some compilers will realy do the asignment later
1109 // All global variables are initialized to 0 at the very beginning, and this is just fine.
1110 int wxDebugContextDumpDelayCounter::sm_count
;
1112 void wxDebugContextDumpDelayCounter::DoDump()
1114 if (wxDebugContext::CountObjectsLeft(TRUE
) > 0)
1116 wxDebugContext::OutputDumpLine(wxT("There were memory leaks.\n"));
1117 wxDebugContext::Dump();
1118 wxDebugContext::PrintStatistics();
1122 // Even if there is nothing else, make sure that there is at
1123 // least one clenup counter object
1124 static wxDebugContextDumpDelayCounter wxDebugContextDumpDelayCounter_One
;
1126 #endif // (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT