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 wxUSE_MEMORY_TRACING || wxUSE_DEBUG_CONTEXT
21 #include "wx/memory.h"
25 #include "wx/msw/wrapwin.h"
34 #include "wx/thread.h"
39 #include "wx/ioswrap.h"
41 #if !defined(__WATCOMC__) && !(defined(__VMS__) && ( __VMS_VER < 70000000 ) )\
42 && !defined( __MWERKS__ )
50 #define USE_THREADSAFE_MEMORY_ALLOCATION 1
52 #define USE_THREADSAFE_MEMORY_ALLOCATION 0
60 // wxDebugContext wxTheDebugContext;
62 Redefine new and delete so that we can pick up situations where:
63 - we overwrite or underwrite areas of malloc'd memory.
64 - we use uninitialise variables
65 Only do this in debug mode.
67 We change new to get enough memory to allocate a struct, followed
68 by the caller's requested memory, followed by a tag. The struct
69 is used to create a doubly linked list of these areas and also
70 contains another tag. The tags are used to determine when the area
71 has been over/under written.
76 Values which are used to set the markers which will be tested for
77 under/over write. There are 3 of these, one in the struct, one
78 immediately after the struct but before the caller requested memory and
79 one immediately after the requested memory.
81 #define MemStartCheck 0x23A8
82 #define MemMidCheck 0xA328
83 #define MemEndCheck 0x8A32
84 #define MemFillChar 0xAF
85 #define MemStructId 0x666D
88 External interface for the wxMemStruct class. Others are
89 defined inline within the class def. Here we only need to be able
90 to add and delete nodes from the list and handle errors in some way.
94 Used for internal "this shouldn't happen" type of errors.
96 void wxMemStruct::ErrorMsg (const char * mesg
)
98 wxLogMessage(wxT("wxWidgets memory checking error: %s"), mesg
);
103 Used when we find an overwrite or an underwrite error.
105 void wxMemStruct::ErrorMsg ()
107 wxLogMessage(wxT("wxWidgets over/underwrite memory error:"));
113 We want to find out if pointers have been overwritten as soon as is
114 possible, so test everything before we dereference it. Of course it's still
115 quite possible that, if things have been overwritten, this function will
116 fall over, but the only way of dealing with that would cost too much in terms
119 int wxMemStruct::AssertList ()
121 if (wxDebugContext::GetHead () != 0 && ! (wxDebugContext::GetHead ())->AssertIt () ||
122 wxDebugContext::GetTail () != 0 && ! wxDebugContext::GetTail ()->AssertIt ()) {
123 ErrorMsg ("Head or tail pointers trashed");
131 Check that the thing we're pointing to has the correct id for a wxMemStruct
132 object and also that it's previous and next pointers are pointing at objects
133 which have valid ids.
134 This is definitely not perfect since we could fall over just trying to access
135 any of the slots which we use here, but I think it's about the best that I
136 can do without doing something like taking all new wxMemStruct pointers and
137 comparing them against all known pointer within the list and then only
138 doing this sort of check _after_ you've found the pointer in the list. That
139 would be safer, but also much more time consuming.
141 int wxMemStruct::AssertIt ()
143 return (m_id
== MemStructId
&&
144 (m_prev
== 0 || m_prev
->m_id
== MemStructId
) &&
145 (m_next
== 0 || m_next
->m_id
== MemStructId
));
150 Additions are always at the tail of the list.
151 Returns 0 on error, non-zero on success.
153 int wxMemStruct::Append ()
158 if (wxDebugContext::GetHead () == 0) {
159 if (wxDebugContext::GetTail () != 0) {
160 ErrorMsg ("Null list should have a null tail pointer");
163 (void) wxDebugContext::SetHead (this);
164 (void) wxDebugContext::SetTail (this);
166 wxDebugContext::GetTail ()->m_next
= this;
167 this->m_prev
= wxDebugContext::GetTail ();
168 (void) wxDebugContext::SetTail (this);
175 Don't actually free up anything here as the space which is used
176 by the node will be free'd up when the whole block is free'd.
177 Returns 0 on error, non-zero on success.
179 int wxMemStruct::Unlink ()
184 if (wxDebugContext::GetHead () == 0 || wxDebugContext::GetTail () == 0) {
185 ErrorMsg ("Trying to remove node from empty list");
189 // Handle the part of the list before this node.
191 if (this != wxDebugContext::GetHead ()) {
192 ErrorMsg ("No previous node for non-head node");
195 (void) wxDebugContext::SetHead (m_next
);
197 if (! m_prev
->AssertIt ()) {
198 ErrorMsg ("Trashed previous pointer");
202 if (m_prev
->m_next
!= this) {
203 ErrorMsg ("List is inconsistent");
206 m_prev
->m_next
= m_next
;
209 // Handle the part of the list after this node.
211 if (this != wxDebugContext::GetTail ()) {
212 ErrorMsg ("No next node for non-tail node");
215 (void) wxDebugContext::SetTail (m_prev
);
217 if (! m_next
->AssertIt ()) {
218 ErrorMsg ("Trashed next pointer");
222 if (m_next
->m_prev
!= this) {
223 ErrorMsg ("List is inconsistent");
226 m_next
->m_prev
= m_prev
;
235 Checks a node and block of memory to see that the markers are still
238 int wxMemStruct::CheckBlock ()
242 if (m_firstMarker
!= MemStartCheck
) {
247 char * pointer
= wxDebugContext::MidMarkerPos ((char *) this);
248 if (* (wxMarkerType
*) pointer
!= MemMidCheck
) {
253 pointer
= wxDebugContext::EndMarkerPos ((char *) this, RequestSize ());
254 if (* (wxMarkerType
*) pointer
!= MemEndCheck
) {
264 Check the list of nodes to see if they are all ok.
266 int wxMemStruct::CheckAllPrevious ()
270 for (wxMemStruct
* st
= this->m_prev
; st
!= 0; st
= st
->m_prev
) {
272 nFailures
+= st
->CheckBlock ();
282 When we delete a node we set the id slot to a specific value and then test
283 against this to see if a nodes have been deleted previously. I don't
284 just set the entire memory to the fillChar because then I'd be overwriting
285 useful stuff like the vtbl which may be needed to output the error message
286 including the file name and line numbers. Without this info the whole point
287 of this class is lost!
289 void wxMemStruct::SetDeleted ()
294 int wxMemStruct::IsDeleted ()
296 return (m_id
== MemFillChar
);
301 Print out a single node. There are many far better ways of doing this
302 but this will suffice for now.
304 void wxMemStruct::PrintNode ()
308 wxObject
*obj
= (wxObject
*)m_actualData
;
309 wxClassInfo
*info
= obj
->GetClassInfo();
311 // Let's put this in standard form so IDEs can load the file at the appropriate
316 msg
.Printf(wxT("%s(%d): "), m_fileName
, (int)m_lineNum
);
318 if (info
&& info
->GetClassName())
319 msg
+= info
->GetClassName();
321 msg
+= wxT("object");
324 msg2
.Printf(wxT(" at 0x%lX, size %d"), (long)GetActualData(), (int)RequestSize());
334 msg
.Printf(wxT("%s(%d): "), m_fileName
, (int)m_lineNum
);
335 msg
+= wxT("non-object data");
337 msg2
.Printf(wxT(" at 0x%lX, size %d\n"), (long)GetActualData(), (int)RequestSize());
344 void wxMemStruct::Dump ()
346 if (!ValidateNode()) return;
350 wxObject
*obj
= (wxObject
*)m_actualData
;
354 msg
.Printf(wxT("%s(%d): "), m_fileName
, (int)m_lineNum
);
357 /* TODO: We no longer have a stream (using wxLogDebug) so we can't dump it.
358 * Instead, do what wxObject::Dump does.
359 * What should we do long-term, eliminate Dumping? Or specify
360 * that MyClass::Dump should use wxLogDebug? Ugh.
361 obj->Dump(wxDebugContext::GetStream());
364 if (obj
->GetClassInfo() && obj
->GetClassInfo()->GetClassName())
365 msg
+= obj
->GetClassInfo()->GetClassName();
367 msg
+= wxT("unknown object class");
370 msg2
.Printf(wxT(" at 0x%lX, size %d"), (long)GetActualData(), (int)RequestSize());
373 wxDebugContext::OutputDumpLine(msg
.c_str());
379 msg
.Printf(wxT("%s(%d): "), m_fileName
, (int)m_lineNum
);
382 msg2
.Printf(wxT("non-object data at 0x%lX, size %d"), (long)GetActualData(), (int)RequestSize() );
384 wxDebugContext::OutputDumpLine(msg
.c_str());
390 Validate a node. Check to see that the node is "clean" in the sense
391 that nothing has over/underwritten it etc.
393 int wxMemStruct::ValidateNode ()
395 char * startPointer
= (char *) this;
398 ErrorMsg ("Object already deleted");
400 // Can't use the error routines as we have no recognisable object.
402 wxLogMessage(wxT("Can't verify memory struct - all bets are off!"));
410 for (i = 0; i < wxDebugContext::TotSize (requestSize ()); i++)
411 cout << startPointer [i];
414 if (Marker () != MemStartCheck
)
416 if (* (wxMarkerType
*) wxDebugContext::MidMarkerPos (startPointer
) != MemMidCheck
)
418 if (* (wxMarkerType
*) wxDebugContext::EndMarkerPos (startPointer
,
423 // Back to before the extra buffer and check that
424 // we can still read what we originally wrote.
425 if (Marker () != MemStartCheck
||
426 * (wxMarkerType
*) wxDebugContext::MidMarkerPos (startPointer
)
428 * (wxMarkerType
*) wxDebugContext::EndMarkerPos (startPointer
,
429 RequestSize ()) != MemEndCheck
)
439 The wxDebugContext class.
442 wxMemStruct
*wxDebugContext::m_head
= NULL
;
443 wxMemStruct
*wxDebugContext::m_tail
= NULL
;
445 bool wxDebugContext::m_checkPrevious
= false;
446 int wxDebugContext::debugLevel
= 1;
447 bool wxDebugContext::debugOn
= true;
448 wxMemStruct
*wxDebugContext::checkPoint
= NULL
;
450 // For faster alignment calculation
451 static wxMarkerType markerCalc
[2];
452 int wxDebugContext::m_balign
= (int)((char *)&markerCalc
[1] - (char*)&markerCalc
[0]);
453 int wxDebugContext::m_balignmask
= (int)((char *)&markerCalc
[1] - (char*)&markerCalc
[0]) - 1;
455 // Pointer to global function to call at shutdown
456 wxShutdownNotifyFunction
wxDebugContext::sm_shutdownFn
;
458 wxDebugContext::wxDebugContext(void)
462 wxDebugContext::~wxDebugContext(void)
467 Work out the positions of the markers by creating an array of 2 markers
468 and comparing the addresses of the 2 elements. Use this number as the
469 alignment for markers.
471 size_t wxDebugContext::CalcAlignment ()
474 return (char *) &ar
[1] - (char *) &ar
[0];
478 char * wxDebugContext::StructPos (const char * buf
)
483 char * wxDebugContext::MidMarkerPos (const char * buf
)
485 return StructPos (buf
) + PaddedSize (sizeof (wxMemStruct
));
488 char * wxDebugContext::CallerMemPos (const char * buf
)
490 return MidMarkerPos (buf
) + PaddedSize (sizeof(wxMarkerType
));
494 char * wxDebugContext::EndMarkerPos (const char * buf
, const size_t size
)
496 return CallerMemPos (buf
) + PaddedSize (size
);
501 Slightly different as this takes a pointer to the start of the caller
502 requested region and returns a pointer to the start of the buffer.
504 char * wxDebugContext::StartPos (const char * caller
)
506 return ((char *) (caller
- wxDebugContext::PaddedSize (sizeof(wxMarkerType
)) -
507 wxDebugContext::PaddedSize (sizeof (wxMemStruct
))));
511 We may need padding between various parts of the allocated memory.
512 Given a size of memory, this returns the amount of memory which should
513 be allocated in order to allow for alignment of the following object.
515 I don't know how portable this stuff is, but it seems to work for me at
516 the moment. It would be real nice if I knew more about this!
518 // Note: this function is now obsolete (along with CalcAlignment)
519 // because the calculations are done statically, for greater speed.
521 size_t wxDebugContext::GetPadding (const size_t size
)
523 size_t pad
= size
% CalcAlignment ();
524 return (pad
) ? sizeof(wxMarkerType
) - pad
: 0;
527 size_t wxDebugContext::PaddedSize (const size_t size
)
529 // Added by Terry Farnham <TJRT@pacbell.net> to replace
530 // slow GetPadding call.
533 padb
= size
& m_balignmask
;
535 return(size
+ m_balign
- padb
);
541 Returns the total amount of memory which we need to get from the system
542 in order to satisfy a caller request. This includes space for the struct
543 plus markers and the caller's memory as well.
545 size_t wxDebugContext::TotSize (const size_t reqSize
)
547 return (PaddedSize (sizeof (wxMemStruct
)) + PaddedSize (reqSize
) +
548 2 * sizeof(wxMarkerType
));
553 Traverse the list of nodes executing the given function on each node.
555 void wxDebugContext::TraverseList (PmSFV func
, wxMemStruct
*from
)
558 from
= wxDebugContext::GetHead ();
560 wxMemStruct
* st
= NULL
;
561 for (st
= from
; st
!= 0; st
= st
->m_next
)
563 void* data
= st
->GetActualData();
564 // if ((data != (void*)m_debugStream) && (data != (void*) m_streamBuf))
565 if (data
!= (void*) wxLog::GetActiveTarget())
576 bool wxDebugContext::PrintList (void)
578 TraverseList ((PmSFV
)&wxMemStruct::PrintNode
, (checkPoint
? checkPoint
->m_next
: NULL
));
583 bool wxDebugContext::Dump(void)
586 const wxChar
* appName
= wxT("application");
590 appNameStr
= wxTheApp
->GetAppName();
591 appName
= appNameStr
.c_str();
592 OutputDumpLine(wxT("----- Memory dump of %s at %s -----"), appName
, static_cast<const wxChar
*>(wxNow().c_str()));
596 OutputDumpLine( wxT("----- Memory dump -----") );
600 TraverseList ((PmSFV
)&wxMemStruct::Dump
, (checkPoint
? checkPoint
->m_next
: NULL
));
602 OutputDumpLine(wxEmptyString
);
603 OutputDumpLine(wxEmptyString
);
608 struct wxDebugStatsStruct
612 wxChar
*instanceClass
;
613 wxDebugStatsStruct
*next
;
616 static wxDebugStatsStruct
*FindStatsStruct(wxDebugStatsStruct
*st
, wxChar
*name
)
620 if (wxStrcmp(st
->instanceClass
, name
) == 0)
627 static wxDebugStatsStruct
*InsertStatsStruct(wxDebugStatsStruct
*head
, wxDebugStatsStruct
*st
)
633 bool wxDebugContext::PrintStatistics(bool detailed
)
636 const wxChar
* appName
= wxT("application");
640 appNameStr
= wxTheApp
->GetAppName();
641 appName
= appNameStr
.c_str();
642 OutputDumpLine(wxT("----- Memory statistics of %s at %s -----"), appName
, static_cast<const wxChar
*>(wxNow().c_str()));
646 OutputDumpLine( wxT("----- Memory statistics -----") );
650 bool currentMode
= GetDebugMode();
653 long noNonObjectNodes
= 0;
654 long noObjectNodes
= 0;
657 wxDebugStatsStruct
*list
= NULL
;
659 wxMemStruct
*from
= (checkPoint
? checkPoint
->m_next
: NULL
);
661 from
= wxDebugContext::GetHead ();
664 for (st
= from
; st
!= 0; st
= st
->m_next
)
666 void* data
= st
->GetActualData();
667 if (detailed
&& (data
!= (void*) wxLog::GetActiveTarget()))
669 wxChar
*className
= (wxChar
*) wxT("nonobject");
670 if (st
->m_isObject
&& st
->GetActualData())
672 wxObject
*obj
= (wxObject
*)st
->GetActualData();
673 if (obj
->GetClassInfo()->GetClassName())
674 className
= (wxChar
*)obj
->GetClassInfo()->GetClassName();
676 wxDebugStatsStruct
*stats
= FindStatsStruct(list
, className
);
679 stats
= (wxDebugStatsStruct
*)malloc(sizeof(wxDebugStatsStruct
));
680 stats
->instanceClass
= className
;
681 stats
->instanceCount
= 0;
682 stats
->totalSize
= 0;
683 list
= InsertStatsStruct(list
, stats
);
685 stats
->instanceCount
++;
686 stats
->totalSize
+= st
->RequestSize();
689 if (data
!= (void*) wxLog::GetActiveTarget())
691 totalSize
+= st
->RequestSize();
703 OutputDumpLine(wxT("%ld objects of class %s, total size %ld"),
704 list
->instanceCount
, list
->instanceClass
, list
->totalSize
);
705 wxDebugStatsStruct
*old
= list
;
709 OutputDumpLine(wxEmptyString
);
712 SetDebugMode(currentMode
);
714 OutputDumpLine(wxT("Number of object items: %ld"), noObjectNodes
);
715 OutputDumpLine(wxT("Number of non-object items: %ld"), noNonObjectNodes
);
716 OutputDumpLine(wxT("Total allocated size: %ld"), totalSize
);
717 OutputDumpLine(wxEmptyString
);
718 OutputDumpLine(wxEmptyString
);
723 bool wxDebugContext::PrintClasses(void)
726 const wxChar
* appName
= wxT("application");
730 appNameStr
= wxTheApp
->GetAppName();
731 appName
= appNameStr
.c_str();
732 wxLogMessage(wxT("----- Classes in %s -----"), appName
);
737 const wxClassInfo
*info
;
739 for (wxClassInfo::const_iterator node
= wxClassInfo::begin_classinfo(),
740 end
= wxClassInfo::end_classinfo();
744 if (info
->GetClassName())
746 wxString
msg(info
->GetClassName());
749 if (info
->GetBaseClassName1() && !info
->GetBaseClassName2())
752 msg
+= info
->GetBaseClassName1();
754 else if (info
->GetBaseClassName1() && info
->GetBaseClassName2())
757 msg
+= info
->GetBaseClassName1() ;
759 msg
+= info
->GetBaseClassName2() ;
761 if (info
->GetConstructor())
762 msg
+= wxT(": dynamic");
768 wxLogMessage(wxEmptyString
);
769 wxLogMessage(wxT("There are %d classes derived from wxObject."), n
);
770 wxLogMessage(wxEmptyString
);
771 wxLogMessage(wxEmptyString
);
775 void wxDebugContext::SetCheckpoint(bool all
)
783 // Checks all nodes since checkpoint, or since start.
784 int wxDebugContext::Check(bool checkAll
)
788 wxMemStruct
*from
= (checkPoint
? checkPoint
->m_next
: NULL
);
789 if (!from
|| checkAll
)
790 from
= wxDebugContext::GetHead ();
792 for (wxMemStruct
* st
= from
; st
!= 0; st
= st
->m_next
)
795 nFailures
+= st
->CheckBlock ();
803 // Count the number of non-wxDebugContext-related objects
804 // that are outstanding
805 int wxDebugContext::CountObjectsLeft(bool sinceCheckpoint
)
809 wxMemStruct
*from
= NULL
;
810 if (sinceCheckpoint
&& checkPoint
)
811 from
= checkPoint
->m_next
;
813 from
= wxDebugContext::GetHead () ;
815 for (wxMemStruct
* st
= from
; st
!= 0; st
= st
->m_next
)
817 void* data
= st
->GetActualData();
818 if (data
!= (void*) wxLog::GetActiveTarget())
825 // This function is used to output the dump
826 void wxDebugContext::OutputDumpLine(const wxChar
*szFormat
, ...)
828 // a buffer of 2048 bytes should be long enough for a file name
833 va_start(argptr
, szFormat
);
834 buf
[WXSIZEOF(buf
)-1] = _T('\0');
836 // keep 3 bytes for a \r\n\0
837 count
= wxVsnprintf(buf
, WXSIZEOF(buf
)-3, szFormat
, argptr
);
840 count
= WXSIZEOF(buf
)-3;
842 buf
[count
+1]=_T('\n');
843 buf
[count
+2]=_T('\0');
845 wxMessageOutputDebug dbgout
;
849 void wxDebugContext::SetShutdownNotifyFunction(wxShutdownNotifyFunction shutdownFn
)
851 sm_shutdownFn
= shutdownFn
;
855 #if USE_THREADSAFE_MEMORY_ALLOCATION
856 static bool memSectionOk
= false;
858 class MemoryCriticalSection
: public wxCriticalSection
861 MemoryCriticalSection() {
864 ~MemoryCriticalSection() {
865 memSectionOk
= false;
869 class MemoryCriticalSectionLocker
872 inline MemoryCriticalSectionLocker(wxCriticalSection
& critsect
)
873 : m_critsect(critsect
), m_locked(memSectionOk
) { if(m_locked
) m_critsect
.Enter(); }
874 inline ~MemoryCriticalSectionLocker() { if(m_locked
) m_critsect
.Leave(); }
877 // no assignment operator nor copy ctor
878 MemoryCriticalSectionLocker(const MemoryCriticalSectionLocker
&);
879 MemoryCriticalSectionLocker
& operator=(const MemoryCriticalSectionLocker
&);
881 wxCriticalSection
& m_critsect
;
885 static MemoryCriticalSection memLocker
;
887 #endif // USE_THREADSAFE_MEMORY_ALLOCATION
890 #if !(defined(__WXMSW__) && (defined(WXUSINGDLL) || defined(WXMAKINGDLL_BASE)))
891 #if wxUSE_GLOBAL_MEMORY_OPERATORS
892 void * operator new (size_t size
, wxChar
* fileName
, int lineNum
)
894 return wxDebugAlloc(size
, fileName
, lineNum
, false, false);
897 void * operator new (size_t size
)
899 return wxDebugAlloc(size
, NULL
, 0, false);
902 void operator delete (void * buf
)
904 wxDebugFree(buf
, false);
907 #if wxUSE_ARRAY_MEMORY_OPERATORS
908 void * operator new[] (size_t size
)
910 return wxDebugAlloc(size
, NULL
, 0, false, true);
913 void * operator new[] (size_t size
, wxChar
* fileName
, int lineNum
)
915 return wxDebugAlloc(size
, fileName
, lineNum
, false, true);
918 void operator delete[] (void * buf
)
920 wxDebugFree(buf
, true);
922 #endif // wxUSE_ARRAY_MEMORY_OPERATORS
923 #endif // wxUSE_GLOBAL_MEMORY_OPERATORS
924 #endif // !(defined(__WXMSW__) && (defined(WXUSINGDLL) || defined(WXMAKINGDLL_BASE)))
926 // TODO: store whether this is a vector or not.
927 void * wxDebugAlloc(size_t size
, wxChar
* fileName
, int lineNum
, bool isObject
, bool WXUNUSED(isVect
) )
929 #if USE_THREADSAFE_MEMORY_ALLOCATION
930 MemoryCriticalSectionLocker
lock(memLocker
);
933 // If not in debugging allocation mode, do the normal thing
934 // so we don't leave any trace of ourselves in the node list.
936 #if defined(__VISAGECPP__) && (__IBMCPP__ < 400 || __IBMC__ < 400 )
937 // VA 3.0 still has trouble in here
938 return (void *)malloc(size
);
940 if (!wxDebugContext::GetDebugMode())
942 return (void *)malloc(size
);
945 int totSize
= wxDebugContext::TotSize (size
);
946 char * buf
= (char *) malloc(totSize
);
948 wxLogMessage(wxT("Call to malloc (%ld) failed."), (long)size
);
951 wxMemStruct
* st
= (wxMemStruct
*)buf
;
952 st
->m_firstMarker
= MemStartCheck
;
953 st
->m_reqSize
= size
;
954 st
->m_fileName
= fileName
;
955 st
->m_lineNum
= lineNum
;
956 st
->m_id
= MemStructId
;
959 st
->m_isObject
= isObject
;
961 // Errors from Append() shouldn't really happen - but just in case!
962 if (st
->Append () == 0) {
963 st
->ErrorMsg ("Trying to append new node");
966 if (wxDebugContext::GetCheckPrevious ()) {
967 if (st
->CheckAllPrevious () < 0) {
968 st
->ErrorMsg ("Checking previous nodes");
972 // Set up the extra markers at the middle and end.
973 char * ptr
= wxDebugContext::MidMarkerPos (buf
);
974 * (wxMarkerType
*) ptr
= MemMidCheck
;
975 ptr
= wxDebugContext::EndMarkerPos (buf
, size
);
976 * (wxMarkerType
*) ptr
= MemEndCheck
;
978 // pointer returned points to the start of the caller's
980 void *m_actualData
= (void *) wxDebugContext::CallerMemPos (buf
);
981 st
->m_actualData
= m_actualData
;
986 // TODO: check whether was allocated as a vector
987 void wxDebugFree(void * buf
, bool WXUNUSED(isVect
) )
989 #if USE_THREADSAFE_MEMORY_ALLOCATION
990 MemoryCriticalSectionLocker
lock(memLocker
);
996 #if defined(__VISAGECPP__) && (__IBMCPP__ < 400 || __IBMC__ < 400 )
997 // VA 3.0 still has trouble in here
1000 // If not in debugging allocation mode, do the normal thing
1001 // so we don't leave any trace of ourselves in the node list.
1002 if (!wxDebugContext::GetDebugMode())
1008 // Points to the start of the entire allocated area.
1009 char * startPointer
= wxDebugContext::StartPos ((char *) buf
);
1010 // Find the struct and make sure that it's identifiable.
1011 wxMemStruct
* st
= (wxMemStruct
*) wxDebugContext::StructPos (startPointer
);
1013 if (! st
->ValidateNode ())
1016 // If this is the current checkpoint, we need to
1017 // move the checkpoint back so it points to a valid
1019 if (st
== wxDebugContext::checkPoint
)
1020 wxDebugContext::checkPoint
= wxDebugContext::checkPoint
->m_prev
;
1022 if (! st
->Unlink ())
1024 st
->ErrorMsg ("Unlinking deleted node");
1027 // Now put in the fill char into the id slot and the caller requested
1028 // memory locations.
1030 (void) memset (wxDebugContext::CallerMemPos (startPointer
), MemFillChar
,
1031 st
->RequestSize ());
1036 // Trace: send output to the current debugging stream
1037 void wxTrace(const wxChar
* ...)
1040 wxFAIL_MSG(wxT("wxTrace is now obsolete. Please use wxDebugXXX instead."));
1043 static wxChar buffer
[512];
1048 wvsprintf(buffer
,fmt
,ap
) ;
1050 vsprintf(buffer
,fmt
,ap
) ;
1055 if (wxDebugContext::HasStream())
1057 wxDebugContext::GetStream() << buffer
;
1058 wxDebugContext::GetStream().flush();
1063 OutputDebugString((LPCTSTR
)buffer
) ;
1065 OutputDebugString((const char*) buffer
) ;
1068 fprintf(stderr
, buffer
);
1074 void wxTraceLevel(int, const wxChar
* ...)
1077 wxFAIL_MSG(wxT("wxTrace is now obsolete. Please use wxDebugXXX instead."));
1079 if (wxDebugContext::GetLevel() < level
)
1083 static wxChar buffer
[512];
1088 wxWvsprintf(buffer
,fmt
,ap
) ;
1090 vsprintf(buffer
,fmt
,ap
) ;
1095 if (wxDebugContext::HasStream())
1097 wxDebugContext::GetStream() << buffer
;
1098 wxDebugContext::GetStream().flush();
1103 OutputDebugString((LPCTSTR
)buffer
) ;
1105 OutputDebugString((const char*) buffer
) ;
1108 fprintf(stderr
, buffer
);
1113 //----------------------------------------------------------------------------
1114 // Final cleanup after all global objects in all files have been destroyed
1115 //----------------------------------------------------------------------------
1117 // Don't set it to 0 by dynamic initialization
1118 // Some compilers will really do the assignment later
1119 // All global variables are initialized to 0 at the very beginning, and this is just fine.
1120 int wxDebugContextDumpDelayCounter::sm_count
;
1122 wxDebugContextDumpDelayCounter::wxDebugContextDumpDelayCounter()
1127 wxDebugContextDumpDelayCounter::~wxDebugContextDumpDelayCounter()
1131 // Notify app if we've been asked to do that
1132 if( wxDebugContext::sm_shutdownFn
)
1133 wxDebugContext::sm_shutdownFn();
1138 void wxDebugContextDumpDelayCounter::DoDump()
1140 if (wxDebugContext::CountObjectsLeft(true) > 0)
1142 wxDebugContext::OutputDumpLine(wxT("There were memory leaks.\n"));
1143 wxDebugContext::Dump();
1144 wxDebugContext::PrintStatistics();
1148 // Even if there is nothing else, make sure that there is at
1149 // least one cleanup counter object
1150 static wxDebugContextDumpDelayCounter wxDebugContextDumpDelayCounter_One
;
1152 #endif // wxUSE_MEMORY_TRACING || wxUSE_DEBUG_CONTEXT