1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/memory.cpp
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"
19 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
28 #include "wx/thread.h"
34 #include "wx/ioswrap.h"
36 #if !defined(__WATCOMC__) && !(defined(__VMS__) && ( __VMS_VER < 70000000 ) )\
37 && !defined( __MWERKS__ ) && !defined(__SALFORDC__)
45 #include "wx/msw/wrapwin.h"
57 #include "wx/memory.h"
59 #if wxUSE_THREADS && defined(__WXDEBUG__)
60 #define USE_THREADSAFE_MEMORY_ALLOCATION 1
62 #define USE_THREADSAFE_MEMORY_ALLOCATION 0
70 // wxDebugContext wxTheDebugContext;
72 Redefine new and delete so that we can pick up situations where:
73 - we overwrite or underwrite areas of malloc'd memory.
74 - we use uninitialise variables
75 Only do this in debug mode.
77 We change new to get enough memory to allocate a struct, followed
78 by the caller's requested memory, followed by a tag. The struct
79 is used to create a doubly linked list of these areas and also
80 contains another tag. The tags are used to determine when the area
81 has been over/under written.
86 Values which are used to set the markers which will be tested for
87 under/over write. There are 3 of these, one in the struct, one
88 immediately after the struct but before the caller requested memory and
89 one immediately after the requested memory.
91 #define MemStartCheck 0x23A8
92 #define MemMidCheck 0xA328
93 #define MemEndCheck 0x8A32
94 #define MemFillChar 0xAF
95 #define MemStructId 0x666D
98 External interface for the wxMemStruct class. Others are
99 defined inline within the class def. Here we only need to be able
100 to add and delete nodes from the list and handle errors in some way.
104 Used for internal "this shouldn't happen" type of errors.
106 void wxMemStruct::ErrorMsg (const char * mesg
)
108 wxLogMessage(wxT("wxWidgets memory checking error: %s"), mesg
);
113 Used when we find an overwrite or an underwrite error.
115 void wxMemStruct::ErrorMsg ()
117 wxLogMessage(wxT("wxWidgets over/underwrite memory error:"));
123 We want to find out if pointers have been overwritten as soon as is
124 possible, so test everything before we dereference it. Of course it's still
125 quite possible that, if things have been overwritten, this function will
126 fall over, but the only way of dealing with that would cost too much in terms
129 int wxMemStruct::AssertList ()
131 if (wxDebugContext::GetHead () != 0 && ! (wxDebugContext::GetHead ())->AssertIt () ||
132 wxDebugContext::GetTail () != 0 && ! wxDebugContext::GetTail ()->AssertIt ()) {
133 ErrorMsg ("Head or tail pointers trashed");
141 Check that the thing we're pointing to has the correct id for a wxMemStruct
142 object and also that it's previous and next pointers are pointing at objects
143 which have valid ids.
144 This is definitely not perfect since we could fall over just trying to access
145 any of the slots which we use here, but I think it's about the best that I
146 can do without doing something like taking all new wxMemStruct pointers and
147 comparing them against all known pointer within the list and then only
148 doing this sort of check _after_ you've found the pointer in the list. That
149 would be safer, but also much more time consuming.
151 int wxMemStruct::AssertIt ()
153 return (m_id
== MemStructId
&&
154 (m_prev
== 0 || m_prev
->m_id
== MemStructId
) &&
155 (m_next
== 0 || m_next
->m_id
== MemStructId
));
160 Additions are always at the tail of the list.
161 Returns 0 on error, non-zero on success.
163 int wxMemStruct::Append ()
168 if (wxDebugContext::GetHead () == 0) {
169 if (wxDebugContext::GetTail () != 0) {
170 ErrorMsg ("Null list should have a null tail pointer");
173 (void) wxDebugContext::SetHead (this);
174 (void) wxDebugContext::SetTail (this);
176 wxDebugContext::GetTail ()->m_next
= this;
177 this->m_prev
= wxDebugContext::GetTail ();
178 (void) wxDebugContext::SetTail (this);
185 Don't actually free up anything here as the space which is used
186 by the node will be free'd up when the whole block is free'd.
187 Returns 0 on error, non-zero on success.
189 int wxMemStruct::Unlink ()
194 if (wxDebugContext::GetHead () == 0 || wxDebugContext::GetTail () == 0) {
195 ErrorMsg ("Trying to remove node from empty list");
199 // Handle the part of the list before this node.
201 if (this != wxDebugContext::GetHead ()) {
202 ErrorMsg ("No previous node for non-head node");
205 (void) wxDebugContext::SetHead (m_next
);
207 if (! m_prev
->AssertIt ()) {
208 ErrorMsg ("Trashed previous pointer");
212 if (m_prev
->m_next
!= this) {
213 ErrorMsg ("List is inconsistent");
216 m_prev
->m_next
= m_next
;
219 // Handle the part of the list after this node.
221 if (this != wxDebugContext::GetTail ()) {
222 ErrorMsg ("No next node for non-tail node");
225 (void) wxDebugContext::SetTail (m_prev
);
227 if (! m_next
->AssertIt ()) {
228 ErrorMsg ("Trashed next pointer");
232 if (m_next
->m_prev
!= this) {
233 ErrorMsg ("List is inconsistent");
236 m_next
->m_prev
= m_prev
;
245 Checks a node and block of memory to see that the markers are still
248 int wxMemStruct::CheckBlock ()
252 if (m_firstMarker
!= MemStartCheck
) {
257 char * pointer
= wxDebugContext::MidMarkerPos ((char *) this);
258 if (* (wxMarkerType
*) pointer
!= MemMidCheck
) {
263 pointer
= wxDebugContext::EndMarkerPos ((char *) this, RequestSize ());
264 if (* (wxMarkerType
*) pointer
!= MemEndCheck
) {
274 Check the list of nodes to see if they are all ok.
276 int wxMemStruct::CheckAllPrevious ()
280 for (wxMemStruct
* st
= this->m_prev
; st
!= 0; st
= st
->m_prev
) {
282 nFailures
+= st
->CheckBlock ();
292 When we delete a node we set the id slot to a specific value and then test
293 against this to see if a nodes have been deleted previously. I don't
294 just set the entire memory to the fillChar because then I'd be overwriting
295 useful stuff like the vtbl which may be needed to output the error message
296 including the file name and line numbers. Without this info the whole point
297 of this class is lost!
299 void wxMemStruct::SetDeleted ()
304 int wxMemStruct::IsDeleted ()
306 return (m_id
== MemFillChar
);
311 Print out a single node. There are many far better ways of doing this
312 but this will suffice for now.
314 void wxMemStruct::PrintNode ()
318 wxObject
*obj
= (wxObject
*)m_actualData
;
319 wxClassInfo
*info
= obj
->GetClassInfo();
321 // Let's put this in standard form so IDEs can load the file at the appropriate
326 msg
.Printf(wxT("%s(%d): "), m_fileName
, (int)m_lineNum
);
328 if (info
&& info
->GetClassName())
329 msg
+= info
->GetClassName();
331 msg
+= wxT("object");
334 msg2
.Printf(wxT(" at 0x%lX, size %d"), (long)GetActualData(), (int)RequestSize());
344 msg
.Printf(wxT("%s(%d): "), m_fileName
, (int)m_lineNum
);
345 msg
+= wxT("non-object data");
347 msg2
.Printf(wxT(" at 0x%lX, size %d\n"), (long)GetActualData(), (int)RequestSize());
354 void wxMemStruct::Dump ()
356 if (!ValidateNode()) return;
360 wxObject
*obj
= (wxObject
*)m_actualData
;
364 msg
.Printf(wxT("%s(%d): "), m_fileName
, (int)m_lineNum
);
367 /* TODO: We no longer have a stream (using wxLogDebug) so we can't dump it.
368 * Instead, do what wxObject::Dump does.
369 * What should we do long-term, eliminate Dumping? Or specify
370 * that MyClass::Dump should use wxLogDebug? Ugh.
371 obj->Dump(wxDebugContext::GetStream());
374 if (obj
->GetClassInfo() && obj
->GetClassInfo()->GetClassName())
375 msg
+= obj
->GetClassInfo()->GetClassName();
377 msg
+= wxT("unknown object class");
380 msg2
.Printf(wxT(" at 0x%lX, size %d"), (long)GetActualData(), (int)RequestSize());
383 wxDebugContext::OutputDumpLine(msg
);
389 msg
.Printf(wxT("%s(%d): "), m_fileName
, (int)m_lineNum
);
392 msg2
.Printf(wxT("non-object data at 0x%lX, size %d"), (long)GetActualData(), (int)RequestSize() );
394 wxDebugContext::OutputDumpLine(msg
);
400 Validate a node. Check to see that the node is "clean" in the sense
401 that nothing has over/underwritten it etc.
403 int wxMemStruct::ValidateNode ()
405 char * startPointer
= (char *) this;
408 ErrorMsg ("Object already deleted");
410 // Can't use the error routines as we have no recognisable object.
412 wxLogMessage(wxT("Can't verify memory struct - all bets are off!"));
420 for (i = 0; i < wxDebugContext::TotSize (requestSize ()); i++)
421 cout << startPointer [i];
424 if (Marker () != MemStartCheck
)
426 if (* (wxMarkerType
*) wxDebugContext::MidMarkerPos (startPointer
) != MemMidCheck
)
428 if (* (wxMarkerType
*) wxDebugContext::EndMarkerPos (startPointer
,
433 // Back to before the extra buffer and check that
434 // we can still read what we originally wrote.
435 if (Marker () != MemStartCheck
||
436 * (wxMarkerType
*) wxDebugContext::MidMarkerPos (startPointer
)
438 * (wxMarkerType
*) wxDebugContext::EndMarkerPos (startPointer
,
439 RequestSize ()) != MemEndCheck
)
449 The wxDebugContext class.
452 wxMemStruct
*wxDebugContext::m_head
= NULL
;
453 wxMemStruct
*wxDebugContext::m_tail
= NULL
;
455 bool wxDebugContext::m_checkPrevious
= false;
456 int wxDebugContext::debugLevel
= 1;
457 bool wxDebugContext::debugOn
= true;
458 wxMemStruct
*wxDebugContext::checkPoint
= NULL
;
460 // For faster alignment calculation
461 static wxMarkerType markerCalc
[2];
462 int wxDebugContext::m_balign
= (int)((char *)&markerCalc
[1] - (char*)&markerCalc
[0]);
463 int wxDebugContext::m_balignmask
= (int)((char *)&markerCalc
[1] - (char*)&markerCalc
[0]) - 1;
465 wxDebugContext::wxDebugContext(void)
469 wxDebugContext::~wxDebugContext(void)
474 Work out the positions of the markers by creating an array of 2 markers
475 and comparing the addresses of the 2 elements. Use this number as the
476 alignment for markers.
478 size_t wxDebugContext::CalcAlignment ()
481 return (char *) &ar
[1] - (char *) &ar
[0];
485 char * wxDebugContext::StructPos (const char * buf
)
490 char * wxDebugContext::MidMarkerPos (const char * buf
)
492 return StructPos (buf
) + PaddedSize (sizeof (wxMemStruct
));
495 char * wxDebugContext::CallerMemPos (const char * buf
)
497 return MidMarkerPos (buf
) + PaddedSize (sizeof(wxMarkerType
));
501 char * wxDebugContext::EndMarkerPos (const char * buf
, const size_t size
)
503 return CallerMemPos (buf
) + PaddedSize (size
);
508 Slightly different as this takes a pointer to the start of the caller
509 requested region and returns a pointer to the start of the buffer.
511 char * wxDebugContext::StartPos (const char * caller
)
513 return ((char *) (caller
- wxDebugContext::PaddedSize (sizeof(wxMarkerType
)) -
514 wxDebugContext::PaddedSize (sizeof (wxMemStruct
))));
518 We may need padding between various parts of the allocated memory.
519 Given a size of memory, this returns the amount of memory which should
520 be allocated in order to allow for alignment of the following object.
522 I don't know how portable this stuff is, but it seems to work for me at
523 the moment. It would be real nice if I knew more about this!
525 // Note: this function is now obsolete (along with CalcAlignment)
526 // because the calculations are done statically, for greater speed.
528 size_t wxDebugContext::GetPadding (const size_t size
)
530 size_t pad
= size
% CalcAlignment ();
531 return (pad
) ? sizeof(wxMarkerType
) - pad
: 0;
534 size_t wxDebugContext::PaddedSize (const size_t size
)
536 // Added by Terry Farnham <TJRT@pacbell.net> to replace
537 // slow GetPadding call.
540 padb
= size
& m_balignmask
;
542 return(size
+ m_balign
- padb
);
548 Returns the total amount of memory which we need to get from the system
549 in order to satisfy a caller request. This includes space for the struct
550 plus markers and the caller's memory as well.
552 size_t wxDebugContext::TotSize (const size_t reqSize
)
554 return (PaddedSize (sizeof (wxMemStruct
)) + PaddedSize (reqSize
) +
555 2 * sizeof(wxMarkerType
));
560 Traverse the list of nodes executing the given function on each node.
562 void wxDebugContext::TraverseList (PmSFV func
, wxMemStruct
*from
)
565 from
= wxDebugContext::GetHead ();
567 wxMemStruct
* st
= NULL
;
568 for (st
= from
; st
!= 0; st
= st
->m_next
)
570 void* data
= st
->GetActualData();
571 // if ((data != (void*)m_debugStream) && (data != (void*) m_streamBuf))
572 if (data
!= (void*) wxLog::GetActiveTarget())
583 bool wxDebugContext::PrintList (void)
586 TraverseList ((PmSFV
)&wxMemStruct::PrintNode
, (checkPoint
? checkPoint
->m_next
: (wxMemStruct
*)NULL
));
594 bool wxDebugContext::Dump(void)
598 wxChar
* appName
= (wxChar
*) wxT("application");
602 appNameStr
= wxTheApp
->GetAppName();
603 appName
= WXSTRINGCAST appNameStr
;
604 OutputDumpLine(wxT("----- Memory dump of %s at %s -----"), appName
, WXSTRINGCAST
wxNow() );
608 OutputDumpLine( wxT("----- Memory dump -----") );
612 TraverseList ((PmSFV
)&wxMemStruct::Dump
, (checkPoint
? checkPoint
->m_next
: (wxMemStruct
*)NULL
));
614 OutputDumpLine(wxEmptyString
);
615 OutputDumpLine(wxEmptyString
);
624 struct wxDebugStatsStruct
628 wxChar
*instanceClass
;
629 wxDebugStatsStruct
*next
;
632 static wxDebugStatsStruct
*FindStatsStruct(wxDebugStatsStruct
*st
, wxChar
*name
)
636 if (wxStrcmp(st
->instanceClass
, name
) == 0)
643 static wxDebugStatsStruct
*InsertStatsStruct(wxDebugStatsStruct
*head
, wxDebugStatsStruct
*st
)
650 bool wxDebugContext::PrintStatistics(bool detailed
)
654 wxChar
* appName
= (wxChar
*) wxT("application");
658 appNameStr
= wxTheApp
->GetAppName();
659 appName
= WXSTRINGCAST appNameStr
;
660 OutputDumpLine(wxT("----- Memory statistics of %s at %s -----"), appName
, WXSTRINGCAST
wxNow() );
664 OutputDumpLine( wxT("----- Memory statistics -----") );
668 bool currentMode
= GetDebugMode();
671 long noNonObjectNodes
= 0;
672 long noObjectNodes
= 0;
675 wxDebugStatsStruct
*list
= NULL
;
677 wxMemStruct
*from
= (checkPoint
? checkPoint
->m_next
: (wxMemStruct
*)NULL
);
679 from
= wxDebugContext::GetHead ();
682 for (st
= from
; st
!= 0; st
= st
->m_next
)
684 void* data
= st
->GetActualData();
685 if (detailed
&& (data
!= (void*) wxLog::GetActiveTarget()))
687 wxChar
*className
= (wxChar
*) wxT("nonobject");
688 if (st
->m_isObject
&& st
->GetActualData())
690 wxObject
*obj
= (wxObject
*)st
->GetActualData();
691 if (obj
->GetClassInfo()->GetClassName())
692 className
= (wxChar
*)obj
->GetClassInfo()->GetClassName();
694 wxDebugStatsStruct
*stats
= FindStatsStruct(list
, className
);
697 stats
= (wxDebugStatsStruct
*)malloc(sizeof(wxDebugStatsStruct
));
698 stats
->instanceClass
= className
;
699 stats
->instanceCount
= 0;
700 stats
->totalSize
= 0;
701 list
= InsertStatsStruct(list
, stats
);
703 stats
->instanceCount
++;
704 stats
->totalSize
+= st
->RequestSize();
707 if (data
!= (void*) wxLog::GetActiveTarget())
709 totalSize
+= st
->RequestSize();
721 OutputDumpLine(wxT("%ld objects of class %s, total size %ld"),
722 list
->instanceCount
, list
->instanceClass
, list
->totalSize
);
723 wxDebugStatsStruct
*old
= list
;
727 OutputDumpLine(wxEmptyString
);
730 SetDebugMode(currentMode
);
732 OutputDumpLine(wxT("Number of object items: %ld"), noObjectNodes
);
733 OutputDumpLine(wxT("Number of non-object items: %ld"), noNonObjectNodes
);
734 OutputDumpLine(wxT("Total allocated size: %ld"), totalSize
);
735 OutputDumpLine(wxEmptyString
);
736 OutputDumpLine(wxEmptyString
);
745 bool wxDebugContext::PrintClasses(void)
748 wxChar
* appName
= (wxChar
*) wxT("application");
752 appNameStr
= wxTheApp
->GetAppName();
753 appName
= WXSTRINGCAST appNameStr
;
754 wxLogMessage(wxT("----- Classes in %s -----"), appName
);
759 wxHashTable::compatibility_iterator node
;
762 wxClassInfo::sm_classTable
->BeginFind();
763 node
= wxClassInfo::sm_classTable
->Next();
766 info
= (wxClassInfo
*)node
->GetData();
767 if (info
->GetClassName())
769 wxString
msg(info
->GetClassName());
772 if (info
->GetBaseClassName1() && !info
->GetBaseClassName2())
775 msg
+= info
->GetBaseClassName1();
777 else if (info
->GetBaseClassName1() && info
->GetBaseClassName2())
780 msg
+= info
->GetBaseClassName1() ;
782 msg
+= info
->GetBaseClassName2() ;
784 if (info
->GetConstructor())
785 msg
+= wxT(": dynamic");
789 node
= wxClassInfo::sm_classTable
->Next();
792 wxLogMessage(wxEmptyString
);
793 wxLogMessage(wxT("There are %d classes derived from wxObject."), n
);
794 wxLogMessage(wxEmptyString
);
795 wxLogMessage(wxEmptyString
);
799 void wxDebugContext::SetCheckpoint(bool all
)
807 // Checks all nodes since checkpoint, or since start.
808 int wxDebugContext::Check(bool checkAll
)
812 wxMemStruct
*from
= (checkPoint
? checkPoint
->m_next
: (wxMemStruct
*)NULL
);
813 if (!from
|| checkAll
)
814 from
= wxDebugContext::GetHead ();
816 for (wxMemStruct
* st
= from
; st
!= 0; st
= st
->m_next
)
819 nFailures
+= st
->CheckBlock ();
827 // Count the number of non-wxDebugContext-related objects
828 // that are outstanding
829 int wxDebugContext::CountObjectsLeft(bool sinceCheckpoint
)
833 wxMemStruct
*from
= NULL
;
834 if (sinceCheckpoint
&& checkPoint
)
835 from
= checkPoint
->m_next
;
837 from
= wxDebugContext::GetHead () ;
839 for (wxMemStruct
* st
= from
; st
!= 0; st
= st
->m_next
)
841 void* data
= st
->GetActualData();
842 if (data
!= (void*) wxLog::GetActiveTarget())
849 // This function is used to output the dump
850 void wxDebugContext::OutputDumpLine(const wxChar
*szFormat
, ...)
852 // a buffer of 2048 bytes should be long enough for a file name
857 va_start(argptr
, szFormat
);
858 buf
[sizeof(buf
)/sizeof(wxChar
)-1] = _T('\0');
860 // keep 3 bytes for a \r\n\0
861 count
= wxVsnprintf(buf
, sizeof(buf
)/sizeof(wxChar
)-3, szFormat
, argptr
);
864 count
= sizeof(buf
)/sizeof(wxChar
)-3;
866 buf
[count
+1]=_T('\n');
867 buf
[count
+2]=_T('\0');
869 wxMessageOutputDebug dbgout
;
874 #if USE_THREADSAFE_MEMORY_ALLOCATION
875 static bool memSectionOk
= false;
877 class MemoryCriticalSection
: public wxCriticalSection
880 MemoryCriticalSection() {
883 ~MemoryCriticalSection() {
884 memSectionOk
= false;
888 class MemoryCriticalSectionLocker
891 inline MemoryCriticalSectionLocker(wxCriticalSection
& critsect
)
892 : m_critsect(critsect
), m_locked(memSectionOk
) { if(m_locked
) m_critsect
.Enter(); }
893 inline ~MemoryCriticalSectionLocker() { if(m_locked
) m_critsect
.Leave(); }
896 // no assignment operator nor copy ctor
897 MemoryCriticalSectionLocker(const MemoryCriticalSectionLocker
&);
898 MemoryCriticalSectionLocker
& operator=(const MemoryCriticalSectionLocker
&);
900 wxCriticalSection
& m_critsect
;
904 static MemoryCriticalSection memLocker
;
906 #endif // USE_THREADSAFE_MEMORY_ALLOCATION
910 #if !(defined(__WXMSW__) && (defined(WXUSINGDLL) || defined(WXMAKINGDLL_BASE)))
911 #if wxUSE_GLOBAL_MEMORY_OPERATORS
912 void * operator new (size_t size
, wxChar
* fileName
, int lineNum
)
914 return wxDebugAlloc(size
, fileName
, lineNum
, false, false);
917 void * operator new (size_t size
)
919 return wxDebugAlloc(size
, NULL
, 0, false);
922 void operator delete (void * buf
)
924 wxDebugFree(buf
, false);
927 #if wxUSE_ARRAY_MEMORY_OPERATORS
928 void * operator new[] (size_t size
)
930 return wxDebugAlloc(size
, NULL
, 0, false, true);
933 void * operator new[] (size_t size
, wxChar
* fileName
, int lineNum
)
935 return wxDebugAlloc(size
, fileName
, lineNum
, false, true);
938 void operator delete[] (void * buf
)
940 wxDebugFree(buf
, true);
942 #endif // wxUSE_ARRAY_MEMORY_OPERATORS
943 #endif // wxUSE_GLOBAL_MEMORY_OPERATORS
944 #endif // !(defined(__WXMSW__) && (defined(WXUSINGDLL) || defined(WXMAKINGDLL_BASE)))
946 // TODO: store whether this is a vector or not.
947 void * wxDebugAlloc(size_t size
, wxChar
* fileName
, int lineNum
, bool isObject
, bool WXUNUSED(isVect
) )
949 #if USE_THREADSAFE_MEMORY_ALLOCATION
950 MemoryCriticalSectionLocker
lock(memLocker
);
953 // If not in debugging allocation mode, do the normal thing
954 // so we don't leave any trace of ourselves in the node list.
956 #if defined(__VISAGECPP__) && (__IBMCPP__ < 400 || __IBMC__ < 400 )
957 // VA 3.0 still has trouble in here
958 return (void *)malloc(size
);
960 if (!wxDebugContext::GetDebugMode())
962 return (void *)malloc(size
);
965 int totSize
= wxDebugContext::TotSize (size
);
966 char * buf
= (char *) malloc(totSize
);
968 wxLogMessage(wxT("Call to malloc (%ld) failed."), (long)size
);
971 wxMemStruct
* st
= (wxMemStruct
*)buf
;
972 st
->m_firstMarker
= MemStartCheck
;
973 st
->m_reqSize
= size
;
974 st
->m_fileName
= fileName
;
975 st
->m_lineNum
= lineNum
;
976 st
->m_id
= MemStructId
;
979 st
->m_isObject
= isObject
;
981 // Errors from Append() shouldn't really happen - but just in case!
982 if (st
->Append () == 0) {
983 st
->ErrorMsg ("Trying to append new node");
986 if (wxDebugContext::GetCheckPrevious ()) {
987 if (st
->CheckAllPrevious () < 0) {
988 st
->ErrorMsg ("Checking previous nodes");
992 // Set up the extra markers at the middle and end.
993 char * ptr
= wxDebugContext::MidMarkerPos (buf
);
994 * (wxMarkerType
*) ptr
= MemMidCheck
;
995 ptr
= wxDebugContext::EndMarkerPos (buf
, size
);
996 * (wxMarkerType
*) ptr
= MemEndCheck
;
998 // pointer returned points to the start of the caller's
1000 void *m_actualData
= (void *) wxDebugContext::CallerMemPos (buf
);
1001 st
->m_actualData
= m_actualData
;
1003 return m_actualData
;
1006 // TODO: check whether was allocated as a vector
1007 void wxDebugFree(void * buf
, bool WXUNUSED(isVect
) )
1009 #if USE_THREADSAFE_MEMORY_ALLOCATION
1010 MemoryCriticalSectionLocker
lock(memLocker
);
1016 #if defined(__VISAGECPP__) && (__IBMCPP__ < 400 || __IBMC__ < 400 )
1017 // VA 3.0 still has trouble in here
1020 // If not in debugging allocation mode, do the normal thing
1021 // so we don't leave any trace of ourselves in the node list.
1022 if (!wxDebugContext::GetDebugMode())
1028 // Points to the start of the entire allocated area.
1029 char * startPointer
= wxDebugContext::StartPos ((char *) buf
);
1030 // Find the struct and make sure that it's identifiable.
1031 wxMemStruct
* st
= (wxMemStruct
*) wxDebugContext::StructPos (startPointer
);
1033 if (! st
->ValidateNode ())
1036 // If this is the current checkpoint, we need to
1037 // move the checkpoint back so it points to a valid
1039 if (st
== wxDebugContext::checkPoint
)
1040 wxDebugContext::checkPoint
= wxDebugContext::checkPoint
->m_prev
;
1042 if (! st
->Unlink ())
1044 st
->ErrorMsg ("Unlinking deleted node");
1047 // Now put in the fill char into the id slot and the caller requested
1048 // memory locations.
1050 (void) memset (wxDebugContext::CallerMemPos (startPointer
), MemFillChar
,
1051 st
->RequestSize ());
1056 #endif // __WXDEBUG__
1058 // Trace: send output to the current debugging stream
1059 void wxTrace(const wxChar
* ...)
1062 wxFAIL_MSG(wxT("wxTrace is now obsolete. Please use wxDebugXXX instead."));
1065 static wxChar buffer
[512];
1070 wvsprintf(buffer
,fmt
,ap
) ;
1072 vsprintf(buffer
,fmt
,ap
) ;
1077 if (wxDebugContext::HasStream())
1079 wxDebugContext::GetStream() << buffer
;
1080 wxDebugContext::GetStream().flush();
1085 OutputDebugString((LPCTSTR
)buffer
) ;
1087 OutputDebugString((const char*) buffer
) ;
1090 fprintf(stderr
, buffer
);
1096 void wxTraceLevel(int, const wxChar
* ...)
1099 wxFAIL_MSG(wxT("wxTrace is now obsolete. Please use wxDebugXXX instead."));
1101 if (wxDebugContext::GetLevel() < level
)
1105 static wxChar buffer
[512];
1110 wxWvsprintf(buffer
,fmt
,ap
) ;
1112 vsprintf(buffer
,fmt
,ap
) ;
1117 if (wxDebugContext::HasStream())
1119 wxDebugContext::GetStream() << buffer
;
1120 wxDebugContext::GetStream().flush();
1125 OutputDebugString((LPCTSTR
)buffer
) ;
1127 OutputDebugString((const char*) buffer
) ;
1130 fprintf(stderr
, buffer
);
1135 //----------------------------------------------------------------------------
1136 // Final cleanup after all global objects in all files have been destroyed
1137 //----------------------------------------------------------------------------
1139 // Don't set it to 0 by dynamic initialization
1140 // Some compilers will really do the assignment later
1141 // All global variables are initialized to 0 at the very beginning, and this is just fine.
1142 int wxDebugContextDumpDelayCounter::sm_count
;
1144 void wxDebugContextDumpDelayCounter::DoDump()
1146 if (wxDebugContext::CountObjectsLeft(true) > 0)
1148 wxDebugContext::OutputDumpLine(wxT("There were memory leaks.\n"));
1149 wxDebugContext::Dump();
1150 wxDebugContext::PrintStatistics();
1154 // Even if there is nothing else, make sure that there is at
1155 // least one cleanup counter object
1156 static wxDebugContextDumpDelayCounter wxDebugContextDumpDelayCounter_One
;
1158 #endif // (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT