1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: Memory checking implementation
4 // Author: Arthur Seaton, Julian Smart
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // For compilers that support precompilation, includes "wx.h".
13 #include "wx/wxprec.h"
23 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
32 #include "wx/thread.h"
38 #include "wx/ioswrap.h"
40 #if !defined(__WATCOMC__) && !(defined(__VMS__) && ( __VMS_VER < 70000000 ) )\
41 && !defined( __MWERKS__ ) && !defined(__SALFORDC__)
49 #include "wx/msw/wrapwin.h"
61 #include "wx/memory.h"
63 #if wxUSE_THREADS && defined(__WXDEBUG__)
64 #define USE_THREADSAFE_MEMORY_ALLOCATION 1
66 #define USE_THREADSAFE_MEMORY_ALLOCATION 0
74 // wxDebugContext wxTheDebugContext;
76 Redefine new and delete so that we can pick up situations where:
77 - we overwrite or underwrite areas of malloc'd memory.
78 - we use uninitialise variables
79 Only do this in debug mode.
81 We change new to get enough memory to allocate a struct, followed
82 by the caller's requested memory, followed by a tag. The struct
83 is used to create a doubly linked list of these areas and also
84 contains another tag. The tags are used to determine when the area
85 has been over/under written.
90 Values which are used to set the markers which will be tested for
91 under/over write. There are 3 of these, one in the struct, one
92 immediately after the struct but before the caller requested memory and
93 one immediately after the requested memory.
95 #define MemStartCheck 0x23A8
96 #define MemMidCheck 0xA328
97 #define MemEndCheck 0x8A32
98 #define MemFillChar 0xAF
99 #define MemStructId 0x666D
102 External interface for the wxMemStruct class. Others are
103 defined inline within the class def. Here we only need to be able
104 to add and delete nodes from the list and handle errors in some way.
108 Used for internal "this shouldn't happen" type of errors.
110 void wxMemStruct::ErrorMsg (const char * mesg
)
112 wxLogMessage(wxT("wxWidgets memory checking error: %s"), mesg
);
117 Used when we find an overwrite or an underwrite error.
119 void wxMemStruct::ErrorMsg ()
121 wxLogMessage(wxT("wxWidgets over/underwrite memory error:"));
127 We want to find out if pointers have been overwritten as soon as is
128 possible, so test everything before we dereference it. Of course it's still
129 quite possible that, if things have been overwritten, this function will
130 fall over, but the only way of dealing with that would cost too much in terms
133 int wxMemStruct::AssertList ()
135 if (wxDebugContext::GetHead () != 0 && ! (wxDebugContext::GetHead ())->AssertIt () ||
136 wxDebugContext::GetTail () != 0 && ! wxDebugContext::GetTail ()->AssertIt ()) {
137 ErrorMsg ("Head or tail pointers trashed");
145 Check that the thing we're pointing to has the correct id for a wxMemStruct
146 object and also that it's previous and next pointers are pointing at objects
147 which have valid ids.
148 This is definitely not perfect since we could fall over just trying to access
149 any of the slots which we use here, but I think it's about the best that I
150 can do without doing something like taking all new wxMemStruct pointers and
151 comparing them against all known pointer within the list and then only
152 doing this sort of check _after_ you've found the pointer in the list. That
153 would be safer, but also much more time consuming.
155 int wxMemStruct::AssertIt ()
157 return (m_id
== MemStructId
&&
158 (m_prev
== 0 || m_prev
->m_id
== MemStructId
) &&
159 (m_next
== 0 || m_next
->m_id
== MemStructId
));
164 Additions are always at the tail of the list.
165 Returns 0 on error, non-zero on success.
167 int wxMemStruct::Append ()
172 if (wxDebugContext::GetHead () == 0) {
173 if (wxDebugContext::GetTail () != 0) {
174 ErrorMsg ("Null list should have a null tail pointer");
177 (void) wxDebugContext::SetHead (this);
178 (void) wxDebugContext::SetTail (this);
180 wxDebugContext::GetTail ()->m_next
= this;
181 this->m_prev
= wxDebugContext::GetTail ();
182 (void) wxDebugContext::SetTail (this);
189 Don't actually free up anything here as the space which is used
190 by the node will be free'd up when the whole block is free'd.
191 Returns 0 on error, non-zero on success.
193 int wxMemStruct::Unlink ()
198 if (wxDebugContext::GetHead () == 0 || wxDebugContext::GetTail () == 0) {
199 ErrorMsg ("Trying to remove node from empty list");
203 // Handle the part of the list before this node.
205 if (this != wxDebugContext::GetHead ()) {
206 ErrorMsg ("No previous node for non-head node");
209 (void) wxDebugContext::SetHead (m_next
);
211 if (! m_prev
->AssertIt ()) {
212 ErrorMsg ("Trashed previous pointer");
216 if (m_prev
->m_next
!= this) {
217 ErrorMsg ("List is inconsistent");
220 m_prev
->m_next
= m_next
;
223 // Handle the part of the list after this node.
225 if (this != wxDebugContext::GetTail ()) {
226 ErrorMsg ("No next node for non-tail node");
229 (void) wxDebugContext::SetTail (m_prev
);
231 if (! m_next
->AssertIt ()) {
232 ErrorMsg ("Trashed next pointer");
236 if (m_next
->m_prev
!= this) {
237 ErrorMsg ("List is inconsistent");
240 m_next
->m_prev
= m_prev
;
249 Checks a node and block of memory to see that the markers are still
252 int wxMemStruct::CheckBlock ()
256 if (m_firstMarker
!= MemStartCheck
) {
261 char * pointer
= wxDebugContext::MidMarkerPos ((char *) this);
262 if (* (wxMarkerType
*) pointer
!= MemMidCheck
) {
267 pointer
= wxDebugContext::EndMarkerPos ((char *) this, RequestSize ());
268 if (* (wxMarkerType
*) pointer
!= MemEndCheck
) {
278 Check the list of nodes to see if they are all ok.
280 int wxMemStruct::CheckAllPrevious ()
284 for (wxMemStruct
* st
= this->m_prev
; st
!= 0; st
= st
->m_prev
) {
286 nFailures
+= st
->CheckBlock ();
296 When we delete a node we set the id slot to a specific value and then test
297 against this to see if a nodes have been deleted previously. I don't
298 just set the entire memory to the fillChar because then I'd be overwriting
299 useful stuff like the vtbl which may be needed to output the error message
300 including the file name and line numbers. Without this info the whole point
301 of this class is lost!
303 void wxMemStruct::SetDeleted ()
308 int wxMemStruct::IsDeleted ()
310 return (m_id
== MemFillChar
);
315 Print out a single node. There are many far better ways of doing this
316 but this will suffice for now.
318 void wxMemStruct::PrintNode ()
322 wxObject
*obj
= (wxObject
*)m_actualData
;
323 wxClassInfo
*info
= obj
->GetClassInfo();
325 // Let's put this in standard form so IDEs can load the file at the appropriate
330 msg
.Printf(wxT("%s(%d): "), m_fileName
, (int)m_lineNum
);
332 if (info
&& info
->GetClassName())
333 msg
+= info
->GetClassName();
335 msg
+= wxT("object");
338 msg2
.Printf(wxT(" at 0x%lX, size %d"), (long)GetActualData(), (int)RequestSize());
348 msg
.Printf(wxT("%s(%d): "), m_fileName
, (int)m_lineNum
);
349 msg
+= wxT("non-object data");
351 msg2
.Printf(wxT(" at 0x%lX, size %d\n"), (long)GetActualData(), (int)RequestSize());
358 void wxMemStruct::Dump ()
360 if (!ValidateNode()) return;
364 wxObject
*obj
= (wxObject
*)m_actualData
;
368 msg
.Printf(wxT("%s(%d): "), m_fileName
, (int)m_lineNum
);
371 /* TODO: We no longer have a stream (using wxLogDebug) so we can't dump it.
372 * Instead, do what wxObject::Dump does.
373 * What should we do long-term, eliminate Dumping? Or specify
374 * that MyClass::Dump should use wxLogDebug? Ugh.
375 obj->Dump(wxDebugContext::GetStream());
378 if (obj
->GetClassInfo() && obj
->GetClassInfo()->GetClassName())
379 msg
+= obj
->GetClassInfo()->GetClassName();
381 msg
+= wxT("unknown object class");
384 msg2
.Printf(wxT(" at 0x%lX, size %d"), (long)GetActualData(), (int)RequestSize());
387 wxDebugContext::OutputDumpLine(msg
);
393 msg
.Printf(wxT("%s(%d): "), m_fileName
, (int)m_lineNum
);
396 msg2
.Printf(wxT("non-object data at 0x%lX, size %d"), (long)GetActualData(), (int)RequestSize() );
398 wxDebugContext::OutputDumpLine(msg
);
404 Validate a node. Check to see that the node is "clean" in the sense
405 that nothing has over/underwritten it etc.
407 int wxMemStruct::ValidateNode ()
409 char * startPointer
= (char *) this;
412 ErrorMsg ("Object already deleted");
414 // Can't use the error routines as we have no recognisable object.
416 wxLogMessage(wxT("Can't verify memory struct - all bets are off!"));
424 for (i = 0; i < wxDebugContext::TotSize (requestSize ()); i++)
425 cout << startPointer [i];
428 if (Marker () != MemStartCheck
)
430 if (* (wxMarkerType
*) wxDebugContext::MidMarkerPos (startPointer
) != MemMidCheck
)
432 if (* (wxMarkerType
*) wxDebugContext::EndMarkerPos (startPointer
,
437 // Back to before the extra buffer and check that
438 // we can still read what we originally wrote.
439 if (Marker () != MemStartCheck
||
440 * (wxMarkerType
*) wxDebugContext::MidMarkerPos (startPointer
)
442 * (wxMarkerType
*) wxDebugContext::EndMarkerPos (startPointer
,
443 RequestSize ()) != MemEndCheck
)
453 The wxDebugContext class.
456 wxMemStruct
*wxDebugContext::m_head
= NULL
;
457 wxMemStruct
*wxDebugContext::m_tail
= NULL
;
459 bool wxDebugContext::m_checkPrevious
= false;
460 int wxDebugContext::debugLevel
= 1;
461 bool wxDebugContext::debugOn
= true;
462 wxMemStruct
*wxDebugContext::checkPoint
= NULL
;
464 // For faster alignment calculation
465 static wxMarkerType markerCalc
[2];
466 int wxDebugContext::m_balign
= (int)((char *)&markerCalc
[1] - (char*)&markerCalc
[0]);
467 int wxDebugContext::m_balignmask
= (int)((char *)&markerCalc
[1] - (char*)&markerCalc
[0]) - 1;
469 wxDebugContext::wxDebugContext(void)
473 wxDebugContext::~wxDebugContext(void)
478 Work out the positions of the markers by creating an array of 2 markers
479 and comparing the addresses of the 2 elements. Use this number as the
480 alignment for markers.
482 size_t wxDebugContext::CalcAlignment ()
485 return (char *) &ar
[1] - (char *) &ar
[0];
489 char * wxDebugContext::StructPos (const char * buf
)
494 char * wxDebugContext::MidMarkerPos (const char * buf
)
496 return StructPos (buf
) + PaddedSize (sizeof (wxMemStruct
));
499 char * wxDebugContext::CallerMemPos (const char * buf
)
501 return MidMarkerPos (buf
) + PaddedSize (sizeof(wxMarkerType
));
505 char * wxDebugContext::EndMarkerPos (const char * buf
, const size_t size
)
507 return CallerMemPos (buf
) + PaddedSize (size
);
512 Slightly different as this takes a pointer to the start of the caller
513 requested region and returns a pointer to the start of the buffer.
515 char * wxDebugContext::StartPos (const char * caller
)
517 return ((char *) (caller
- wxDebugContext::PaddedSize (sizeof(wxMarkerType
)) -
518 wxDebugContext::PaddedSize (sizeof (wxMemStruct
))));
522 We may need padding between various parts of the allocated memory.
523 Given a size of memory, this returns the amount of memory which should
524 be allocated in order to allow for alignment of the following object.
526 I don't know how portable this stuff is, but it seems to work for me at
527 the moment. It would be real nice if I knew more about this!
529 // Note: this function is now obsolete (along with CalcAlignment)
530 // because the calculations are done statically, for greater speed.
532 size_t wxDebugContext::GetPadding (const size_t size
)
534 size_t pad
= size
% CalcAlignment ();
535 return (pad
) ? sizeof(wxMarkerType
) - pad
: 0;
538 size_t wxDebugContext::PaddedSize (const size_t size
)
540 // Added by Terry Farnham <TJRT@pacbell.net> to replace
541 // slow GetPadding call.
544 padb
= size
& m_balignmask
;
546 return(size
+ m_balign
- padb
);
552 Returns the total amount of memory which we need to get from the system
553 in order to satisfy a caller request. This includes space for the struct
554 plus markers and the caller's memory as well.
556 size_t wxDebugContext::TotSize (const size_t reqSize
)
558 return (PaddedSize (sizeof (wxMemStruct
)) + PaddedSize (reqSize
) +
559 2 * sizeof(wxMarkerType
));
564 Traverse the list of nodes executing the given function on each node.
566 void wxDebugContext::TraverseList (PmSFV func
, wxMemStruct
*from
)
569 from
= wxDebugContext::GetHead ();
571 wxMemStruct
* st
= NULL
;
572 for (st
= from
; st
!= 0; st
= st
->m_next
)
574 void* data
= st
->GetActualData();
575 // if ((data != (void*)m_debugStream) && (data != (void*) m_streamBuf))
576 if (data
!= (void*) wxLog::GetActiveTarget())
587 bool wxDebugContext::PrintList (void)
590 TraverseList ((PmSFV
)&wxMemStruct::PrintNode
, (checkPoint
? checkPoint
->m_next
: (wxMemStruct
*)NULL
));
598 bool wxDebugContext::Dump(void)
602 wxChar
* appName
= (wxChar
*) wxT("application");
606 appNameStr
= wxTheApp
->GetAppName();
607 appName
= WXSTRINGCAST appNameStr
;
608 OutputDumpLine(wxT("----- Memory dump of %s at %s -----"), appName
, WXSTRINGCAST
wxNow() );
612 OutputDumpLine( wxT("----- Memory dump -----") );
616 TraverseList ((PmSFV
)&wxMemStruct::Dump
, (checkPoint
? checkPoint
->m_next
: (wxMemStruct
*)NULL
));
618 OutputDumpLine(wxEmptyString
);
619 OutputDumpLine(wxEmptyString
);
628 struct wxDebugStatsStruct
632 wxChar
*instanceClass
;
633 wxDebugStatsStruct
*next
;
636 static wxDebugStatsStruct
*FindStatsStruct(wxDebugStatsStruct
*st
, wxChar
*name
)
640 if (wxStrcmp(st
->instanceClass
, name
) == 0)
647 static wxDebugStatsStruct
*InsertStatsStruct(wxDebugStatsStruct
*head
, wxDebugStatsStruct
*st
)
654 bool wxDebugContext::PrintStatistics(bool detailed
)
658 wxChar
* appName
= (wxChar
*) wxT("application");
662 appNameStr
= wxTheApp
->GetAppName();
663 appName
= WXSTRINGCAST appNameStr
;
664 OutputDumpLine(wxT("----- Memory statistics of %s at %s -----"), appName
, WXSTRINGCAST
wxNow() );
668 OutputDumpLine( wxT("----- Memory statistics -----") );
672 bool currentMode
= GetDebugMode();
675 long noNonObjectNodes
= 0;
676 long noObjectNodes
= 0;
679 wxDebugStatsStruct
*list
= NULL
;
681 wxMemStruct
*from
= (checkPoint
? checkPoint
->m_next
: (wxMemStruct
*)NULL
);
683 from
= wxDebugContext::GetHead ();
686 for (st
= from
; st
!= 0; st
= st
->m_next
)
688 void* data
= st
->GetActualData();
689 if (detailed
&& (data
!= (void*) wxLog::GetActiveTarget()))
691 wxChar
*className
= (wxChar
*) wxT("nonobject");
692 if (st
->m_isObject
&& st
->GetActualData())
694 wxObject
*obj
= (wxObject
*)st
->GetActualData();
695 if (obj
->GetClassInfo()->GetClassName())
696 className
= (wxChar
*)obj
->GetClassInfo()->GetClassName();
698 wxDebugStatsStruct
*stats
= FindStatsStruct(list
, className
);
701 stats
= (wxDebugStatsStruct
*)malloc(sizeof(wxDebugStatsStruct
));
702 stats
->instanceClass
= className
;
703 stats
->instanceCount
= 0;
704 stats
->totalSize
= 0;
705 list
= InsertStatsStruct(list
, stats
);
707 stats
->instanceCount
++;
708 stats
->totalSize
+= st
->RequestSize();
711 if (data
!= (void*) wxLog::GetActiveTarget())
713 totalSize
+= st
->RequestSize();
725 OutputDumpLine(wxT("%ld objects of class %s, total size %ld"),
726 list
->instanceCount
, list
->instanceClass
, list
->totalSize
);
727 wxDebugStatsStruct
*old
= list
;
731 OutputDumpLine(wxEmptyString
);
734 SetDebugMode(currentMode
);
736 OutputDumpLine(wxT("Number of object items: %ld"), noObjectNodes
);
737 OutputDumpLine(wxT("Number of non-object items: %ld"), noNonObjectNodes
);
738 OutputDumpLine(wxT("Total allocated size: %ld"), totalSize
);
739 OutputDumpLine(wxEmptyString
);
740 OutputDumpLine(wxEmptyString
);
749 bool wxDebugContext::PrintClasses(void)
752 wxChar
* appName
= (wxChar
*) wxT("application");
756 appNameStr
= wxTheApp
->GetAppName();
757 appName
= WXSTRINGCAST appNameStr
;
758 wxLogMessage(wxT("----- Classes in %s -----"), appName
);
763 wxHashTable::compatibility_iterator node
;
766 wxClassInfo::sm_classTable
->BeginFind();
767 node
= wxClassInfo::sm_classTable
->Next();
770 info
= (wxClassInfo
*)node
->GetData();
771 if (info
->GetClassName())
773 wxString
msg(info
->GetClassName());
776 if (info
->GetBaseClassName1() && !info
->GetBaseClassName2())
779 msg
+= info
->GetBaseClassName1();
781 else if (info
->GetBaseClassName1() && info
->GetBaseClassName2())
784 msg
+= info
->GetBaseClassName1() ;
786 msg
+= info
->GetBaseClassName2() ;
788 if (info
->GetConstructor())
789 msg
+= wxT(": dynamic");
793 node
= wxClassInfo::sm_classTable
->Next();
796 wxLogMessage(wxEmptyString
);
797 wxLogMessage(wxT("There are %d classes derived from wxObject."), n
);
798 wxLogMessage(wxEmptyString
);
799 wxLogMessage(wxEmptyString
);
803 void wxDebugContext::SetCheckpoint(bool all
)
811 // Checks all nodes since checkpoint, or since start.
812 int wxDebugContext::Check(bool checkAll
)
816 wxMemStruct
*from
= (checkPoint
? checkPoint
->m_next
: (wxMemStruct
*)NULL
);
817 if (!from
|| checkAll
)
818 from
= wxDebugContext::GetHead ();
820 for (wxMemStruct
* st
= from
; st
!= 0; st
= st
->m_next
)
823 nFailures
+= st
->CheckBlock ();
831 // Count the number of non-wxDebugContext-related objects
832 // that are outstanding
833 int wxDebugContext::CountObjectsLeft(bool sinceCheckpoint
)
837 wxMemStruct
*from
= NULL
;
838 if (sinceCheckpoint
&& checkPoint
)
839 from
= checkPoint
->m_next
;
841 from
= wxDebugContext::GetHead () ;
843 for (wxMemStruct
* st
= from
; st
!= 0; st
= st
->m_next
)
845 void* data
= st
->GetActualData();
846 if (data
!= (void*) wxLog::GetActiveTarget())
853 // This function is used to output the dump
854 void wxDebugContext::OutputDumpLine(const wxChar
*szFormat
, ...)
856 // a buffer of 2048 bytes should be long enough for a file name
861 va_start(argptr
, szFormat
);
862 buf
[sizeof(buf
)/sizeof(wxChar
)-1] = _T('\0');
864 // keep 3 bytes for a \r\n\0
865 count
= wxVsnprintf(buf
, sizeof(buf
)/sizeof(wxChar
)-3, szFormat
, argptr
);
868 count
= sizeof(buf
)/sizeof(wxChar
)-3;
870 buf
[count
+1]=_T('\n');
871 buf
[count
+2]=_T('\0');
873 wxMessageOutputDebug dbgout
;
878 #if USE_THREADSAFE_MEMORY_ALLOCATION
879 static bool memSectionOk
= false;
881 class MemoryCriticalSection
: public wxCriticalSection
884 MemoryCriticalSection() {
887 ~MemoryCriticalSection() {
888 memSectionOk
= false;
892 class MemoryCriticalSectionLocker
895 inline MemoryCriticalSectionLocker(wxCriticalSection
& critsect
)
896 : m_critsect(critsect
), m_locked(memSectionOk
) { if(m_locked
) m_critsect
.Enter(); }
897 inline ~MemoryCriticalSectionLocker() { if(m_locked
) m_critsect
.Leave(); }
900 // no assignment operator nor copy ctor
901 MemoryCriticalSectionLocker(const MemoryCriticalSectionLocker
&);
902 MemoryCriticalSectionLocker
& operator=(const MemoryCriticalSectionLocker
&);
904 wxCriticalSection
& m_critsect
;
908 static MemoryCriticalSection memLocker
;
910 #endif // USE_THREADSAFE_MEMORY_ALLOCATION
914 #if !(defined(__WXMSW__) && (defined(WXUSINGDLL) || defined(WXMAKINGDLL_BASE)))
915 #if wxUSE_GLOBAL_MEMORY_OPERATORS
916 void * operator new (size_t size
, wxChar
* fileName
, int lineNum
)
918 return wxDebugAlloc(size
, fileName
, lineNum
, false, false);
921 void * operator new (size_t size
)
923 return wxDebugAlloc(size
, NULL
, 0, false);
926 void operator delete (void * buf
)
928 wxDebugFree(buf
, false);
931 #if wxUSE_ARRAY_MEMORY_OPERATORS
932 void * operator new[] (size_t size
)
934 return wxDebugAlloc(size
, NULL
, 0, false, true);
937 void * operator new[] (size_t size
, wxChar
* fileName
, int lineNum
)
939 return wxDebugAlloc(size
, fileName
, lineNum
, false, true);
942 void operator delete[] (void * buf
)
944 wxDebugFree(buf
, true);
946 #endif // wxUSE_ARRAY_MEMORY_OPERATORS
947 #endif // wxUSE_GLOBAL_MEMORY_OPERATORS
948 #endif // !(defined(__WXMSW__) && (defined(WXUSINGDLL) || defined(WXMAKINGDLL_BASE)))
950 // TODO: store whether this is a vector or not.
951 void * wxDebugAlloc(size_t size
, wxChar
* fileName
, int lineNum
, bool isObject
, bool WXUNUSED(isVect
) )
953 #if USE_THREADSAFE_MEMORY_ALLOCATION
954 MemoryCriticalSectionLocker
lock(memLocker
);
957 // If not in debugging allocation mode, do the normal thing
958 // so we don't leave any trace of ourselves in the node list.
960 #if defined(__VISAGECPP__) && (__IBMCPP__ < 400 || __IBMC__ < 400 )
961 // VA 3.0 still has trouble in here
962 return (void *)malloc(size
);
964 if (!wxDebugContext::GetDebugMode())
966 return (void *)malloc(size
);
969 int totSize
= wxDebugContext::TotSize (size
);
970 char * buf
= (char *) malloc(totSize
);
972 wxLogMessage(wxT("Call to malloc (%ld) failed."), (long)size
);
975 wxMemStruct
* st
= (wxMemStruct
*)buf
;
976 st
->m_firstMarker
= MemStartCheck
;
977 st
->m_reqSize
= size
;
978 st
->m_fileName
= fileName
;
979 st
->m_lineNum
= lineNum
;
980 st
->m_id
= MemStructId
;
983 st
->m_isObject
= isObject
;
985 // Errors from Append() shouldn't really happen - but just in case!
986 if (st
->Append () == 0) {
987 st
->ErrorMsg ("Trying to append new node");
990 if (wxDebugContext::GetCheckPrevious ()) {
991 if (st
->CheckAllPrevious () < 0) {
992 st
->ErrorMsg ("Checking previous nodes");
996 // Set up the extra markers at the middle and end.
997 char * ptr
= wxDebugContext::MidMarkerPos (buf
);
998 * (wxMarkerType
*) ptr
= MemMidCheck
;
999 ptr
= wxDebugContext::EndMarkerPos (buf
, size
);
1000 * (wxMarkerType
*) ptr
= MemEndCheck
;
1002 // pointer returned points to the start of the caller's
1004 void *m_actualData
= (void *) wxDebugContext::CallerMemPos (buf
);
1005 st
->m_actualData
= m_actualData
;
1007 return m_actualData
;
1010 // TODO: check whether was allocated as a vector
1011 void wxDebugFree(void * buf
, bool WXUNUSED(isVect
) )
1013 #if USE_THREADSAFE_MEMORY_ALLOCATION
1014 MemoryCriticalSectionLocker
lock(memLocker
);
1020 #if defined(__VISAGECPP__) && (__IBMCPP__ < 400 || __IBMC__ < 400 )
1021 // VA 3.0 still has trouble in here
1024 // If not in debugging allocation mode, do the normal thing
1025 // so we don't leave any trace of ourselves in the node list.
1026 if (!wxDebugContext::GetDebugMode())
1032 // Points to the start of the entire allocated area.
1033 char * startPointer
= wxDebugContext::StartPos ((char *) buf
);
1034 // Find the struct and make sure that it's identifiable.
1035 wxMemStruct
* st
= (wxMemStruct
*) wxDebugContext::StructPos (startPointer
);
1037 if (! st
->ValidateNode ())
1040 // If this is the current checkpoint, we need to
1041 // move the checkpoint back so it points to a valid
1043 if (st
== wxDebugContext::checkPoint
)
1044 wxDebugContext::checkPoint
= wxDebugContext::checkPoint
->m_prev
;
1046 if (! st
->Unlink ())
1048 st
->ErrorMsg ("Unlinking deleted node");
1051 // Now put in the fill char into the id slot and the caller requested
1052 // memory locations.
1054 (void) memset (wxDebugContext::CallerMemPos (startPointer
), MemFillChar
,
1055 st
->RequestSize ());
1060 #endif // __WXDEBUG__
1062 // Trace: send output to the current debugging stream
1063 void wxTrace(const wxChar
* ...)
1066 wxFAIL_MSG(wxT("wxTrace is now obsolete. Please use wxDebugXXX instead."));
1069 static wxChar buffer
[512];
1074 wvsprintf(buffer
,fmt
,ap
) ;
1076 vsprintf(buffer
,fmt
,ap
) ;
1081 if (wxDebugContext::HasStream())
1083 wxDebugContext::GetStream() << buffer
;
1084 wxDebugContext::GetStream().flush();
1089 OutputDebugString((LPCTSTR
)buffer
) ;
1091 OutputDebugString((const char*) buffer
) ;
1094 fprintf(stderr
, buffer
);
1100 void wxTraceLevel(int, const wxChar
* ...)
1103 wxFAIL_MSG(wxT("wxTrace is now obsolete. Please use wxDebugXXX instead."));
1105 if (wxDebugContext::GetLevel() < level
)
1109 static wxChar buffer
[512];
1114 wxWvsprintf(buffer
,fmt
,ap
) ;
1116 vsprintf(buffer
,fmt
,ap
) ;
1121 if (wxDebugContext::HasStream())
1123 wxDebugContext::GetStream() << buffer
;
1124 wxDebugContext::GetStream().flush();
1129 OutputDebugString((LPCTSTR
)buffer
) ;
1131 OutputDebugString((const char*) buffer
) ;
1134 fprintf(stderr
, buffer
);
1139 //----------------------------------------------------------------------------
1140 // Final cleanup after all global objects in all files have been destroyed
1141 //----------------------------------------------------------------------------
1143 // Don't set it to 0 by dynamic initialization
1144 // Some compilers will really do the assignment later
1145 // All global variables are initialized to 0 at the very beginning, and this is just fine.
1146 int wxDebugContextDumpDelayCounter::sm_count
;
1148 void wxDebugContextDumpDelayCounter::DoDump()
1150 if (wxDebugContext::CountObjectsLeft(true) > 0)
1152 wxDebugContext::OutputDumpLine(wxT("There were memory leaks.\n"));
1153 wxDebugContext::Dump();
1154 wxDebugContext::PrintStatistics();
1158 // Even if there is nothing else, make sure that there is at
1159 // least one cleanup counter object
1160 static wxDebugContextDumpDelayCounter wxDebugContextDumpDelayCounter_One
;
1162 #endif // (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT