1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/memory.cpp
3 // Purpose: Memory checking implementation
4 // Author: Arthur Seaton, Julian Smart
7 // Copyright: (c) Julian Smart
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
11 // For compilers that support precompilation, includes "wx.h".
12 #include "wx/wxprec.h"
18 #if wxUSE_MEMORY_TRACING || wxUSE_DEBUG_CONTEXT
20 #include "wx/memory.h"
24 #include "wx/msw/wrapwin.h"
33 #include "wx/thread.h"
38 #include "wx/ioswrap.h"
40 #if !defined(__WATCOMC__) && !(defined(__VMS__) && ( __VMS_VER < 70000000 ) )
48 #define USE_THREADSAFE_MEMORY_ALLOCATION 1
50 #define USE_THREADSAFE_MEMORY_ALLOCATION 0
58 // wxDebugContext wxTheDebugContext;
60 Redefine new and delete so that we can pick up situations where:
61 - we overwrite or underwrite areas of malloc'd memory.
62 - we use uninitialise variables
63 Only do this in debug mode.
65 We change new to get enough memory to allocate a struct, followed
66 by the caller's requested memory, followed by a tag. The struct
67 is used to create a doubly linked list of these areas and also
68 contains another tag. The tags are used to determine when the area
69 has been over/under written.
74 Values which are used to set the markers which will be tested for
75 under/over write. There are 3 of these, one in the struct, one
76 immediately after the struct but before the caller requested memory and
77 one immediately after the requested memory.
79 #define MemStartCheck 0x23A8
80 #define MemMidCheck 0xA328
81 #define MemEndCheck 0x8A32
82 #define MemFillChar 0xAF
83 #define MemStructId 0x666D
86 External interface for the wxMemStruct class. Others are
87 defined inline within the class def. Here we only need to be able
88 to add and delete nodes from the list and handle errors in some way.
92 Used for internal "this shouldn't happen" type of errors.
94 void wxMemStruct::ErrorMsg (const char * mesg
)
96 wxLogMessage(wxT("wxWidgets memory checking error: %s"), mesg
);
101 Used when we find an overwrite or an underwrite error.
103 void wxMemStruct::ErrorMsg ()
105 wxLogMessage(wxT("wxWidgets over/underwrite memory error:"));
111 We want to find out if pointers have been overwritten as soon as is
112 possible, so test everything before we dereference it. Of course it's still
113 quite possible that, if things have been overwritten, this function will
114 fall over, but the only way of dealing with that would cost too much in terms
117 int wxMemStruct::AssertList ()
119 if ((wxDebugContext::GetHead() && !wxDebugContext::GetHead()->AssertIt()) ||
120 (wxDebugContext::GetTail() && !wxDebugContext::GetTail()->AssertIt()))
122 ErrorMsg ("Head or tail pointers trashed");
130 Check that the thing we're pointing to has the correct id for a wxMemStruct
131 object and also that it's previous and next pointers are pointing at objects
132 which have valid ids.
133 This is definitely not perfect since we could fall over just trying to access
134 any of the slots which we use here, but I think it's about the best that I
135 can do without doing something like taking all new wxMemStruct pointers and
136 comparing them against all known pointer within the list and then only
137 doing this sort of check _after_ you've found the pointer in the list. That
138 would be safer, but also much more time consuming.
140 int wxMemStruct::AssertIt ()
142 return (m_id
== MemStructId
&&
143 (m_prev
== 0 || m_prev
->m_id
== MemStructId
) &&
144 (m_next
== 0 || m_next
->m_id
== MemStructId
));
149 Additions are always at the tail of the list.
150 Returns 0 on error, non-zero on success.
152 int wxMemStruct::Append ()
157 if (wxDebugContext::GetHead () == 0) {
158 if (wxDebugContext::GetTail () != 0) {
159 ErrorMsg ("Null list should have a null tail pointer");
162 (void) wxDebugContext::SetHead (this);
163 (void) wxDebugContext::SetTail (this);
165 wxDebugContext::GetTail ()->m_next
= this;
166 this->m_prev
= wxDebugContext::GetTail ();
167 (void) wxDebugContext::SetTail (this);
174 Don't actually free up anything here as the space which is used
175 by the node will be free'd up when the whole block is free'd.
176 Returns 0 on error, non-zero on success.
178 int wxMemStruct::Unlink ()
183 if (wxDebugContext::GetHead () == 0 || wxDebugContext::GetTail () == 0) {
184 ErrorMsg ("Trying to remove node from empty list");
188 // Handle the part of the list before this node.
190 if (this != wxDebugContext::GetHead ()) {
191 ErrorMsg ("No previous node for non-head node");
194 (void) wxDebugContext::SetHead (m_next
);
196 if (! m_prev
->AssertIt ()) {
197 ErrorMsg ("Trashed previous pointer");
201 if (m_prev
->m_next
!= this) {
202 ErrorMsg ("List is inconsistent");
205 m_prev
->m_next
= m_next
;
208 // Handle the part of the list after this node.
210 if (this != wxDebugContext::GetTail ()) {
211 ErrorMsg ("No next node for non-tail node");
214 (void) wxDebugContext::SetTail (m_prev
);
216 if (! m_next
->AssertIt ()) {
217 ErrorMsg ("Trashed next pointer");
221 if (m_next
->m_prev
!= this) {
222 ErrorMsg ("List is inconsistent");
225 m_next
->m_prev
= m_prev
;
234 Checks a node and block of memory to see that the markers are still
237 int wxMemStruct::CheckBlock ()
241 if (m_firstMarker
!= MemStartCheck
) {
246 char * pointer
= wxDebugContext::MidMarkerPos ((char *) this);
247 if (* (wxMarkerType
*) pointer
!= MemMidCheck
) {
252 pointer
= wxDebugContext::EndMarkerPos ((char *) this, RequestSize ());
253 if (* (wxMarkerType
*) pointer
!= MemEndCheck
) {
263 Check the list of nodes to see if they are all ok.
265 int wxMemStruct::CheckAllPrevious ()
269 for (wxMemStruct
* st
= this->m_prev
; st
!= 0; st
= st
->m_prev
) {
271 nFailures
+= st
->CheckBlock ();
281 When we delete a node we set the id slot to a specific value and then test
282 against this to see if a nodes have been deleted previously. I don't
283 just set the entire memory to the fillChar because then I'd be overwriting
284 useful stuff like the vtbl which may be needed to output the error message
285 including the file name and line numbers. Without this info the whole point
286 of this class is lost!
288 void wxMemStruct::SetDeleted ()
293 int wxMemStruct::IsDeleted ()
295 return (m_id
== MemFillChar
);
300 Print out a single node. There are many far better ways of doing this
301 but this will suffice for now.
303 void wxMemStruct::PrintNode ()
307 wxObject
*obj
= (wxObject
*)m_actualData
;
308 wxClassInfo
*info
= obj
->GetClassInfo();
310 // Let's put this in standard form so IDEs can load the file at the appropriate
315 msg
.Printf(wxT("%s(%d): "), m_fileName
, (int)m_lineNum
);
317 if (info
&& info
->GetClassName())
318 msg
+= info
->GetClassName();
320 msg
+= wxT("object");
323 msg2
.Printf(wxT(" at 0x%lX, size %d"), (long)GetActualData(), (int)RequestSize());
333 msg
.Printf(wxT("%s(%d): "), m_fileName
, (int)m_lineNum
);
334 msg
+= wxT("non-object data");
336 msg2
.Printf(wxT(" at 0x%lX, size %d\n"), (long)GetActualData(), (int)RequestSize());
343 void wxMemStruct::Dump ()
345 if (!ValidateNode()) return;
349 wxObject
*obj
= (wxObject
*)m_actualData
;
353 msg
.Printf(wxT("%s(%d): "), m_fileName
, (int)m_lineNum
);
356 /* TODO: We no longer have a stream (using wxLogDebug) so we can't dump it.
357 * Instead, do what wxObject::Dump does.
358 * What should we do long-term, eliminate Dumping? Or specify
359 * that MyClass::Dump should use wxLogDebug? Ugh.
360 obj->Dump(wxDebugContext::GetStream());
363 if (obj
->GetClassInfo() && obj
->GetClassInfo()->GetClassName())
364 msg
+= obj
->GetClassInfo()->GetClassName();
366 msg
+= wxT("unknown object class");
369 msg2
.Printf(wxT(" at 0x%lX, size %d"), (long)GetActualData(), (int)RequestSize());
372 wxDebugContext::OutputDumpLine(msg
.c_str());
378 msg
.Printf(wxT("%s(%d): "), m_fileName
, (int)m_lineNum
);
381 msg2
.Printf(wxT("non-object data at 0x%lX, size %d"), (long)GetActualData(), (int)RequestSize() );
383 wxDebugContext::OutputDumpLine(msg
.c_str());
389 Validate a node. Check to see that the node is "clean" in the sense
390 that nothing has over/underwritten it etc.
392 int wxMemStruct::ValidateNode ()
394 char * startPointer
= (char *) this;
397 ErrorMsg ("Object already deleted");
399 // Can't use the error routines as we have no recognisable object.
401 wxLogMessage(wxT("Can't verify memory struct - all bets are off!"));
409 for (i = 0; i < wxDebugContext::TotSize (requestSize ()); i++)
410 cout << startPointer [i];
413 if (Marker () != MemStartCheck
)
415 if (* (wxMarkerType
*) wxDebugContext::MidMarkerPos (startPointer
) != MemMidCheck
)
417 if (* (wxMarkerType
*) wxDebugContext::EndMarkerPos (startPointer
,
422 // Back to before the extra buffer and check that
423 // we can still read what we originally wrote.
424 if (Marker () != MemStartCheck
||
425 * (wxMarkerType
*) wxDebugContext::MidMarkerPos (startPointer
)
427 * (wxMarkerType
*) wxDebugContext::EndMarkerPos (startPointer
,
428 RequestSize ()) != MemEndCheck
)
438 The wxDebugContext class.
441 wxMemStruct
*wxDebugContext::m_head
= NULL
;
442 wxMemStruct
*wxDebugContext::m_tail
= NULL
;
444 bool wxDebugContext::m_checkPrevious
= false;
445 int wxDebugContext::debugLevel
= 1;
446 bool wxDebugContext::debugOn
= true;
447 wxMemStruct
*wxDebugContext::checkPoint
= NULL
;
449 // For faster alignment calculation
450 static wxMarkerType markerCalc
[2];
451 int wxDebugContext::m_balign
= (int)((char *)&markerCalc
[1] - (char*)&markerCalc
[0]);
452 int wxDebugContext::m_balignmask
= (int)((char *)&markerCalc
[1] - (char*)&markerCalc
[0]) - 1;
454 // Pointer to global function to call at shutdown
455 wxShutdownNotifyFunction
wxDebugContext::sm_shutdownFn
;
457 wxDebugContext::wxDebugContext(void)
461 wxDebugContext::~wxDebugContext(void)
466 Work out the positions of the markers by creating an array of 2 markers
467 and comparing the addresses of the 2 elements. Use this number as the
468 alignment for markers.
470 size_t wxDebugContext::CalcAlignment ()
473 return (char *) &ar
[1] - (char *) &ar
[0];
477 char * wxDebugContext::StructPos (const char * buf
)
482 char * wxDebugContext::MidMarkerPos (const char * buf
)
484 return StructPos (buf
) + PaddedSize (sizeof (wxMemStruct
));
487 char * wxDebugContext::CallerMemPos (const char * buf
)
489 return MidMarkerPos (buf
) + PaddedSize (sizeof(wxMarkerType
));
493 char * wxDebugContext::EndMarkerPos (const char * buf
, const size_t size
)
495 return CallerMemPos (buf
) + PaddedSize (size
);
500 Slightly different as this takes a pointer to the start of the caller
501 requested region and returns a pointer to the start of the buffer.
503 char * wxDebugContext::StartPos (const char * caller
)
505 return ((char *) (caller
- wxDebugContext::PaddedSize (sizeof(wxMarkerType
)) -
506 wxDebugContext::PaddedSize (sizeof (wxMemStruct
))));
510 We may need padding between various parts of the allocated memory.
511 Given a size of memory, this returns the amount of memory which should
512 be allocated in order to allow for alignment of the following object.
514 I don't know how portable this stuff is, but it seems to work for me at
515 the moment. It would be real nice if I knew more about this!
517 // Note: this function is now obsolete (along with CalcAlignment)
518 // because the calculations are done statically, for greater speed.
520 size_t wxDebugContext::GetPadding (const size_t size
)
522 size_t pad
= size
% CalcAlignment ();
523 return (pad
) ? sizeof(wxMarkerType
) - pad
: 0;
526 size_t wxDebugContext::PaddedSize (const size_t size
)
528 // Added by Terry Farnham <TJRT@pacbell.net> to replace
529 // slow GetPadding call.
532 padb
= size
& m_balignmask
;
534 return(size
+ m_balign
- padb
);
540 Returns the total amount of memory which we need to get from the system
541 in order to satisfy a caller request. This includes space for the struct
542 plus markers and the caller's memory as well.
544 size_t wxDebugContext::TotSize (const size_t reqSize
)
546 return (PaddedSize (sizeof (wxMemStruct
)) + PaddedSize (reqSize
) +
547 2 * sizeof(wxMarkerType
));
552 Traverse the list of nodes executing the given function on each node.
554 void wxDebugContext::TraverseList (PmSFV func
, wxMemStruct
*from
)
557 from
= wxDebugContext::GetHead ();
559 wxMemStruct
* st
= NULL
;
560 for (st
= from
; st
!= 0; st
= st
->m_next
)
562 void* data
= st
->GetActualData();
563 // if ((data != (void*)m_debugStream) && (data != (void*) m_streamBuf))
564 if (data
!= (void*) wxLog::GetActiveTarget())
575 bool wxDebugContext::PrintList (void)
577 TraverseList ((PmSFV
)&wxMemStruct::PrintNode
, (checkPoint
? checkPoint
->m_next
: NULL
));
582 bool wxDebugContext::Dump(void)
585 const wxChar
* appName
= wxT("application");
589 appNameStr
= wxTheApp
->GetAppName();
590 appName
= appNameStr
.c_str();
591 OutputDumpLine(wxT("----- Memory dump of %s at %s -----"), appName
, static_cast<const wxChar
*>(wxNow().c_str()));
595 OutputDumpLine( wxT("----- Memory dump -----") );
599 TraverseList ((PmSFV
)&wxMemStruct::Dump
, (checkPoint
? checkPoint
->m_next
: NULL
));
601 OutputDumpLine(wxEmptyString
);
602 OutputDumpLine(wxEmptyString
);
607 struct wxDebugStatsStruct
611 wxChar
*instanceClass
;
612 wxDebugStatsStruct
*next
;
615 static wxDebugStatsStruct
*FindStatsStruct(wxDebugStatsStruct
*st
, wxChar
*name
)
619 if (wxStrcmp(st
->instanceClass
, name
) == 0)
626 static wxDebugStatsStruct
*InsertStatsStruct(wxDebugStatsStruct
*head
, wxDebugStatsStruct
*st
)
632 bool wxDebugContext::PrintStatistics(bool detailed
)
635 const wxChar
* appName
= wxT("application");
639 appNameStr
= wxTheApp
->GetAppName();
640 appName
= appNameStr
.c_str();
641 OutputDumpLine(wxT("----- Memory statistics of %s at %s -----"), appName
, static_cast<const wxChar
*>(wxNow().c_str()));
645 OutputDumpLine( wxT("----- Memory statistics -----") );
649 bool currentMode
= GetDebugMode();
652 long noNonObjectNodes
= 0;
653 long noObjectNodes
= 0;
656 wxDebugStatsStruct
*list
= NULL
;
658 wxMemStruct
*from
= (checkPoint
? checkPoint
->m_next
: NULL
);
660 from
= wxDebugContext::GetHead ();
663 for (st
= from
; st
!= 0; st
= st
->m_next
)
665 void* data
= st
->GetActualData();
666 if (detailed
&& (data
!= (void*) wxLog::GetActiveTarget()))
668 wxChar
*className
= (wxChar
*) wxT("nonobject");
669 if (st
->m_isObject
&& st
->GetActualData())
671 wxObject
*obj
= (wxObject
*)st
->GetActualData();
672 if (obj
->GetClassInfo()->GetClassName())
673 className
= (wxChar
*)obj
->GetClassInfo()->GetClassName();
675 wxDebugStatsStruct
*stats
= FindStatsStruct(list
, className
);
678 stats
= (wxDebugStatsStruct
*)malloc(sizeof(wxDebugStatsStruct
));
679 stats
->instanceClass
= className
;
680 stats
->instanceCount
= 0;
681 stats
->totalSize
= 0;
682 list
= InsertStatsStruct(list
, stats
);
684 stats
->instanceCount
++;
685 stats
->totalSize
+= st
->RequestSize();
688 if (data
!= (void*) wxLog::GetActiveTarget())
690 totalSize
+= st
->RequestSize();
702 OutputDumpLine(wxT("%ld objects of class %s, total size %ld"),
703 list
->instanceCount
, list
->instanceClass
, list
->totalSize
);
704 wxDebugStatsStruct
*old
= list
;
708 OutputDumpLine(wxEmptyString
);
711 SetDebugMode(currentMode
);
713 OutputDumpLine(wxT("Number of object items: %ld"), noObjectNodes
);
714 OutputDumpLine(wxT("Number of non-object items: %ld"), noNonObjectNodes
);
715 OutputDumpLine(wxT("Total allocated size: %ld"), totalSize
);
716 OutputDumpLine(wxEmptyString
);
717 OutputDumpLine(wxEmptyString
);
722 bool wxDebugContext::PrintClasses(void)
725 const wxChar
* appName
= wxT("application");
729 appNameStr
= wxTheApp
->GetAppName();
730 appName
= appNameStr
.c_str();
731 wxLogMessage(wxT("----- Classes in %s -----"), appName
);
736 const wxClassInfo
*info
;
738 for (wxClassInfo::const_iterator node
= wxClassInfo::begin_classinfo(),
739 end
= wxClassInfo::end_classinfo();
743 if (info
->GetClassName())
745 wxString
msg(info
->GetClassName());
748 if (info
->GetBaseClassName1() && !info
->GetBaseClassName2())
751 msg
+= info
->GetBaseClassName1();
753 else if (info
->GetBaseClassName1() && info
->GetBaseClassName2())
756 msg
+= info
->GetBaseClassName1() ;
758 msg
+= info
->GetBaseClassName2() ;
760 if (info
->GetConstructor())
761 msg
+= wxT(": dynamic");
767 wxLogMessage(wxEmptyString
);
768 wxLogMessage(wxT("There are %d classes derived from wxObject."), n
);
769 wxLogMessage(wxEmptyString
);
770 wxLogMessage(wxEmptyString
);
774 void wxDebugContext::SetCheckpoint(bool all
)
782 // Checks all nodes since checkpoint, or since start.
783 int wxDebugContext::Check(bool checkAll
)
787 wxMemStruct
*from
= (checkPoint
? checkPoint
->m_next
: NULL
);
788 if (!from
|| checkAll
)
789 from
= wxDebugContext::GetHead ();
791 for (wxMemStruct
* st
= from
; st
!= 0; st
= st
->m_next
)
794 nFailures
+= st
->CheckBlock ();
802 // Count the number of non-wxDebugContext-related objects
803 // that are outstanding
804 int wxDebugContext::CountObjectsLeft(bool sinceCheckpoint
)
808 wxMemStruct
*from
= NULL
;
809 if (sinceCheckpoint
&& checkPoint
)
810 from
= checkPoint
->m_next
;
812 from
= wxDebugContext::GetHead () ;
814 for (wxMemStruct
* st
= from
; st
!= 0; st
= st
->m_next
)
816 void* data
= st
->GetActualData();
817 if (data
!= (void*) wxLog::GetActiveTarget())
824 // This function is used to output the dump
825 void wxDebugContext::OutputDumpLine(const wxChar
*szFormat
, ...)
827 // a buffer of 2048 bytes should be long enough for a file name
832 va_start(argptr
, szFormat
);
833 buf
[WXSIZEOF(buf
)-1] = wxT('\0');
835 // keep 3 bytes for a \r\n\0
836 count
= wxVsnprintf(buf
, WXSIZEOF(buf
)-3, szFormat
, argptr
);
839 count
= WXSIZEOF(buf
)-3;
840 buf
[count
]=wxT('\r');
841 buf
[count
+1]=wxT('\n');
842 buf
[count
+2]=wxT('\0');
844 wxMessageOutputDebug dbgout
;
848 void wxDebugContext::SetShutdownNotifyFunction(wxShutdownNotifyFunction shutdownFn
)
850 sm_shutdownFn
= shutdownFn
;
854 #if USE_THREADSAFE_MEMORY_ALLOCATION
855 static bool memSectionOk
= false;
857 class MemoryCriticalSection
: public wxCriticalSection
860 MemoryCriticalSection() {
863 ~MemoryCriticalSection() {
864 memSectionOk
= false;
868 class MemoryCriticalSectionLocker
871 inline MemoryCriticalSectionLocker(wxCriticalSection
& critsect
)
872 : m_critsect(critsect
), m_locked(memSectionOk
) { if(m_locked
) m_critsect
.Enter(); }
873 inline ~MemoryCriticalSectionLocker() { if(m_locked
) m_critsect
.Leave(); }
876 // no assignment operator nor copy ctor
877 MemoryCriticalSectionLocker(const MemoryCriticalSectionLocker
&);
878 MemoryCriticalSectionLocker
& operator=(const MemoryCriticalSectionLocker
&);
880 wxCriticalSection
& m_critsect
;
884 static MemoryCriticalSection memLocker
;
886 #endif // USE_THREADSAFE_MEMORY_ALLOCATION
889 #if !(defined(__WINDOWS__) && (defined(WXUSINGDLL) || defined(WXMAKINGDLL_BASE)))
890 #if wxUSE_GLOBAL_MEMORY_OPERATORS
891 void * operator new (size_t size
, wxChar
* fileName
, int lineNum
)
893 return wxDebugAlloc(size
, fileName
, lineNum
, false, false);
896 void * operator new (size_t size
)
898 return wxDebugAlloc(size
, NULL
, 0, false);
901 void operator delete (void * buf
)
903 wxDebugFree(buf
, false);
906 #if wxUSE_ARRAY_MEMORY_OPERATORS
907 void * operator new[] (size_t size
)
909 return wxDebugAlloc(size
, NULL
, 0, false, true);
912 void * operator new[] (size_t size
, wxChar
* fileName
, int lineNum
)
914 return wxDebugAlloc(size
, fileName
, lineNum
, false, true);
917 void operator delete[] (void * buf
)
919 wxDebugFree(buf
, true);
921 #endif // wxUSE_ARRAY_MEMORY_OPERATORS
922 #endif // wxUSE_GLOBAL_MEMORY_OPERATORS
923 #endif // !(defined(__WINDOWS__) && (defined(WXUSINGDLL) || defined(WXMAKINGDLL_BASE)))
925 // TODO: store whether this is a vector or not.
926 void * wxDebugAlloc(size_t size
, wxChar
* fileName
, int lineNum
, bool isObject
, bool WXUNUSED(isVect
) )
928 #if USE_THREADSAFE_MEMORY_ALLOCATION
929 MemoryCriticalSectionLocker
lock(memLocker
);
932 // If not in debugging allocation mode, do the normal thing
933 // so we don't leave any trace of ourselves in the node list.
935 #if defined(__VISAGECPP__) && (__IBMCPP__ < 400 || __IBMC__ < 400 )
936 // VA 3.0 still has trouble in here
937 return (void *)malloc(size
);
939 if (!wxDebugContext::GetDebugMode())
941 return (void *)malloc(size
);
944 int totSize
= wxDebugContext::TotSize (size
);
945 char * buf
= (char *) malloc(totSize
);
947 wxLogMessage(wxT("Call to malloc (%ld) failed."), (long)size
);
950 wxMemStruct
* st
= (wxMemStruct
*)buf
;
951 st
->m_firstMarker
= MemStartCheck
;
952 st
->m_reqSize
= size
;
953 st
->m_fileName
= fileName
;
954 st
->m_lineNum
= lineNum
;
955 st
->m_id
= MemStructId
;
958 st
->m_isObject
= isObject
;
960 // Errors from Append() shouldn't really happen - but just in case!
961 if (st
->Append () == 0) {
962 st
->ErrorMsg ("Trying to append new node");
965 if (wxDebugContext::GetCheckPrevious ()) {
966 if (st
->CheckAllPrevious () < 0) {
967 st
->ErrorMsg ("Checking previous nodes");
971 // Set up the extra markers at the middle and end.
972 char * ptr
= wxDebugContext::MidMarkerPos (buf
);
973 * (wxMarkerType
*) ptr
= MemMidCheck
;
974 ptr
= wxDebugContext::EndMarkerPos (buf
, size
);
975 * (wxMarkerType
*) ptr
= MemEndCheck
;
977 // pointer returned points to the start of the caller's
979 void *m_actualData
= (void *) wxDebugContext::CallerMemPos (buf
);
980 st
->m_actualData
= m_actualData
;
985 // TODO: check whether was allocated as a vector
986 void wxDebugFree(void * buf
, bool WXUNUSED(isVect
) )
988 #if USE_THREADSAFE_MEMORY_ALLOCATION
989 MemoryCriticalSectionLocker
lock(memLocker
);
995 #if defined(__VISAGECPP__) && (__IBMCPP__ < 400 || __IBMC__ < 400 )
996 // VA 3.0 still has trouble in here
999 // If not in debugging allocation mode, do the normal thing
1000 // so we don't leave any trace of ourselves in the node list.
1001 if (!wxDebugContext::GetDebugMode())
1007 // Points to the start of the entire allocated area.
1008 char * startPointer
= wxDebugContext::StartPos ((char *) buf
);
1009 // Find the struct and make sure that it's identifiable.
1010 wxMemStruct
* st
= (wxMemStruct
*) wxDebugContext::StructPos (startPointer
);
1012 if (! st
->ValidateNode ())
1015 // If this is the current checkpoint, we need to
1016 // move the checkpoint back so it points to a valid
1018 if (st
== wxDebugContext::checkPoint
)
1019 wxDebugContext::checkPoint
= wxDebugContext::checkPoint
->m_prev
;
1021 if (! st
->Unlink ())
1023 st
->ErrorMsg ("Unlinking deleted node");
1026 // Now put in the fill char into the id slot and the caller requested
1027 // memory locations.
1029 (void) memset (wxDebugContext::CallerMemPos (startPointer
), MemFillChar
,
1030 st
->RequestSize ());
1035 // Trace: send output to the current debugging stream
1036 void wxTrace(const wxChar
* ...)
1039 wxFAIL_MSG(wxT("wxTrace is now obsolete. Please use wxDebugXXX instead."));
1042 static wxChar buffer
[512];
1047 wvsprintf(buffer
,fmt
,ap
) ;
1049 vsprintf(buffer
,fmt
,ap
) ;
1054 if (wxDebugContext::HasStream())
1056 wxDebugContext::GetStream() << buffer
;
1057 wxDebugContext::GetStream().flush();
1062 OutputDebugString((LPCTSTR
)buffer
) ;
1064 OutputDebugString((const char*) buffer
) ;
1067 fprintf(stderr
, buffer
);
1073 void wxTraceLevel(int, const wxChar
* ...)
1076 wxFAIL_MSG(wxT("wxTrace is now obsolete. Please use wxDebugXXX instead."));
1078 if (wxDebugContext::GetLevel() < level
)
1082 static wxChar buffer
[512];
1087 wxWvsprintf(buffer
,fmt
,ap
) ;
1089 vsprintf(buffer
,fmt
,ap
) ;
1094 if (wxDebugContext::HasStream())
1096 wxDebugContext::GetStream() << buffer
;
1097 wxDebugContext::GetStream().flush();
1102 OutputDebugString((LPCTSTR
)buffer
) ;
1104 OutputDebugString((const char*) buffer
) ;
1107 fprintf(stderr
, buffer
);
1112 //----------------------------------------------------------------------------
1113 // Final cleanup after all global objects in all files have been destroyed
1114 //----------------------------------------------------------------------------
1116 // Don't set it to 0 by dynamic initialization
1117 // Some compilers will really do the assignment later
1118 // All global variables are initialized to 0 at the very beginning, and this is just fine.
1119 int wxDebugContextDumpDelayCounter::sm_count
;
1121 wxDebugContextDumpDelayCounter::wxDebugContextDumpDelayCounter()
1126 wxDebugContextDumpDelayCounter::~wxDebugContextDumpDelayCounter()
1130 // Notify app if we've been asked to do that
1131 if( wxDebugContext::sm_shutdownFn
)
1132 wxDebugContext::sm_shutdownFn();
1137 void wxDebugContextDumpDelayCounter::DoDump()
1139 if (wxDebugContext::CountObjectsLeft(true) > 0)
1141 wxDebugContext::OutputDumpLine(wxT("There were memory leaks.\n"));
1142 wxDebugContext::Dump();
1143 wxDebugContext::PrintStatistics();
1147 // Even if there is nothing else, make sure that there is at
1148 // least one cleanup counter object
1149 static wxDebugContextDumpDelayCounter wxDebugContextDumpDelayCounter_One
;
1151 #endif // wxUSE_MEMORY_TRACING || wxUSE_DEBUG_CONTEXT