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() && !wxDebugContext::GetHead()->AssertIt()) ||
122 (wxDebugContext::GetTail() && !wxDebugContext::GetTail()->AssertIt()))
124 ErrorMsg ("Head or tail pointers trashed");
132 Check that the thing we're pointing to has the correct id for a wxMemStruct
133 object and also that it's previous and next pointers are pointing at objects
134 which have valid ids.
135 This is definitely not perfect since we could fall over just trying to access
136 any of the slots which we use here, but I think it's about the best that I
137 can do without doing something like taking all new wxMemStruct pointers and
138 comparing them against all known pointer within the list and then only
139 doing this sort of check _after_ you've found the pointer in the list. That
140 would be safer, but also much more time consuming.
142 int wxMemStruct::AssertIt ()
144 return (m_id
== MemStructId
&&
145 (m_prev
== 0 || m_prev
->m_id
== MemStructId
) &&
146 (m_next
== 0 || m_next
->m_id
== MemStructId
));
151 Additions are always at the tail of the list.
152 Returns 0 on error, non-zero on success.
154 int wxMemStruct::Append ()
159 if (wxDebugContext::GetHead () == 0) {
160 if (wxDebugContext::GetTail () != 0) {
161 ErrorMsg ("Null list should have a null tail pointer");
164 (void) wxDebugContext::SetHead (this);
165 (void) wxDebugContext::SetTail (this);
167 wxDebugContext::GetTail ()->m_next
= this;
168 this->m_prev
= wxDebugContext::GetTail ();
169 (void) wxDebugContext::SetTail (this);
176 Don't actually free up anything here as the space which is used
177 by the node will be free'd up when the whole block is free'd.
178 Returns 0 on error, non-zero on success.
180 int wxMemStruct::Unlink ()
185 if (wxDebugContext::GetHead () == 0 || wxDebugContext::GetTail () == 0) {
186 ErrorMsg ("Trying to remove node from empty list");
190 // Handle the part of the list before this node.
192 if (this != wxDebugContext::GetHead ()) {
193 ErrorMsg ("No previous node for non-head node");
196 (void) wxDebugContext::SetHead (m_next
);
198 if (! m_prev
->AssertIt ()) {
199 ErrorMsg ("Trashed previous pointer");
203 if (m_prev
->m_next
!= this) {
204 ErrorMsg ("List is inconsistent");
207 m_prev
->m_next
= m_next
;
210 // Handle the part of the list after this node.
212 if (this != wxDebugContext::GetTail ()) {
213 ErrorMsg ("No next node for non-tail node");
216 (void) wxDebugContext::SetTail (m_prev
);
218 if (! m_next
->AssertIt ()) {
219 ErrorMsg ("Trashed next pointer");
223 if (m_next
->m_prev
!= this) {
224 ErrorMsg ("List is inconsistent");
227 m_next
->m_prev
= m_prev
;
236 Checks a node and block of memory to see that the markers are still
239 int wxMemStruct::CheckBlock ()
243 if (m_firstMarker
!= MemStartCheck
) {
248 char * pointer
= wxDebugContext::MidMarkerPos ((char *) this);
249 if (* (wxMarkerType
*) pointer
!= MemMidCheck
) {
254 pointer
= wxDebugContext::EndMarkerPos ((char *) this, RequestSize ());
255 if (* (wxMarkerType
*) pointer
!= MemEndCheck
) {
265 Check the list of nodes to see if they are all ok.
267 int wxMemStruct::CheckAllPrevious ()
271 for (wxMemStruct
* st
= this->m_prev
; st
!= 0; st
= st
->m_prev
) {
273 nFailures
+= st
->CheckBlock ();
283 When we delete a node we set the id slot to a specific value and then test
284 against this to see if a nodes have been deleted previously. I don't
285 just set the entire memory to the fillChar because then I'd be overwriting
286 useful stuff like the vtbl which may be needed to output the error message
287 including the file name and line numbers. Without this info the whole point
288 of this class is lost!
290 void wxMemStruct::SetDeleted ()
295 int wxMemStruct::IsDeleted ()
297 return (m_id
== MemFillChar
);
302 Print out a single node. There are many far better ways of doing this
303 but this will suffice for now.
305 void wxMemStruct::PrintNode ()
309 wxObject
*obj
= (wxObject
*)m_actualData
;
310 wxClassInfo
*info
= obj
->GetClassInfo();
312 // Let's put this in standard form so IDEs can load the file at the appropriate
317 msg
.Printf(wxT("%s(%d): "), m_fileName
, (int)m_lineNum
);
319 if (info
&& info
->GetClassName())
320 msg
+= info
->GetClassName();
322 msg
+= wxT("object");
325 msg2
.Printf(wxT(" at 0x%lX, size %d"), (long)GetActualData(), (int)RequestSize());
335 msg
.Printf(wxT("%s(%d): "), m_fileName
, (int)m_lineNum
);
336 msg
+= wxT("non-object data");
338 msg2
.Printf(wxT(" at 0x%lX, size %d\n"), (long)GetActualData(), (int)RequestSize());
345 void wxMemStruct::Dump ()
347 if (!ValidateNode()) return;
351 wxObject
*obj
= (wxObject
*)m_actualData
;
355 msg
.Printf(wxT("%s(%d): "), m_fileName
, (int)m_lineNum
);
358 /* TODO: We no longer have a stream (using wxLogDebug) so we can't dump it.
359 * Instead, do what wxObject::Dump does.
360 * What should we do long-term, eliminate Dumping? Or specify
361 * that MyClass::Dump should use wxLogDebug? Ugh.
362 obj->Dump(wxDebugContext::GetStream());
365 if (obj
->GetClassInfo() && obj
->GetClassInfo()->GetClassName())
366 msg
+= obj
->GetClassInfo()->GetClassName();
368 msg
+= wxT("unknown object class");
371 msg2
.Printf(wxT(" at 0x%lX, size %d"), (long)GetActualData(), (int)RequestSize());
374 wxDebugContext::OutputDumpLine(msg
.c_str());
380 msg
.Printf(wxT("%s(%d): "), m_fileName
, (int)m_lineNum
);
383 msg2
.Printf(wxT("non-object data at 0x%lX, size %d"), (long)GetActualData(), (int)RequestSize() );
385 wxDebugContext::OutputDumpLine(msg
.c_str());
391 Validate a node. Check to see that the node is "clean" in the sense
392 that nothing has over/underwritten it etc.
394 int wxMemStruct::ValidateNode ()
396 char * startPointer
= (char *) this;
399 ErrorMsg ("Object already deleted");
401 // Can't use the error routines as we have no recognisable object.
403 wxLogMessage(wxT("Can't verify memory struct - all bets are off!"));
411 for (i = 0; i < wxDebugContext::TotSize (requestSize ()); i++)
412 cout << startPointer [i];
415 if (Marker () != MemStartCheck
)
417 if (* (wxMarkerType
*) wxDebugContext::MidMarkerPos (startPointer
) != MemMidCheck
)
419 if (* (wxMarkerType
*) wxDebugContext::EndMarkerPos (startPointer
,
424 // Back to before the extra buffer and check that
425 // we can still read what we originally wrote.
426 if (Marker () != MemStartCheck
||
427 * (wxMarkerType
*) wxDebugContext::MidMarkerPos (startPointer
)
429 * (wxMarkerType
*) wxDebugContext::EndMarkerPos (startPointer
,
430 RequestSize ()) != MemEndCheck
)
440 The wxDebugContext class.
443 wxMemStruct
*wxDebugContext::m_head
= NULL
;
444 wxMemStruct
*wxDebugContext::m_tail
= NULL
;
446 bool wxDebugContext::m_checkPrevious
= false;
447 int wxDebugContext::debugLevel
= 1;
448 bool wxDebugContext::debugOn
= true;
449 wxMemStruct
*wxDebugContext::checkPoint
= NULL
;
451 // For faster alignment calculation
452 static wxMarkerType markerCalc
[2];
453 int wxDebugContext::m_balign
= (int)((char *)&markerCalc
[1] - (char*)&markerCalc
[0]);
454 int wxDebugContext::m_balignmask
= (int)((char *)&markerCalc
[1] - (char*)&markerCalc
[0]) - 1;
456 // Pointer to global function to call at shutdown
457 wxShutdownNotifyFunction
wxDebugContext::sm_shutdownFn
;
459 wxDebugContext::wxDebugContext(void)
463 wxDebugContext::~wxDebugContext(void)
468 Work out the positions of the markers by creating an array of 2 markers
469 and comparing the addresses of the 2 elements. Use this number as the
470 alignment for markers.
472 size_t wxDebugContext::CalcAlignment ()
475 return (char *) &ar
[1] - (char *) &ar
[0];
479 char * wxDebugContext::StructPos (const char * buf
)
484 char * wxDebugContext::MidMarkerPos (const char * buf
)
486 return StructPos (buf
) + PaddedSize (sizeof (wxMemStruct
));
489 char * wxDebugContext::CallerMemPos (const char * buf
)
491 return MidMarkerPos (buf
) + PaddedSize (sizeof(wxMarkerType
));
495 char * wxDebugContext::EndMarkerPos (const char * buf
, const size_t size
)
497 return CallerMemPos (buf
) + PaddedSize (size
);
502 Slightly different as this takes a pointer to the start of the caller
503 requested region and returns a pointer to the start of the buffer.
505 char * wxDebugContext::StartPos (const char * caller
)
507 return ((char *) (caller
- wxDebugContext::PaddedSize (sizeof(wxMarkerType
)) -
508 wxDebugContext::PaddedSize (sizeof (wxMemStruct
))));
512 We may need padding between various parts of the allocated memory.
513 Given a size of memory, this returns the amount of memory which should
514 be allocated in order to allow for alignment of the following object.
516 I don't know how portable this stuff is, but it seems to work for me at
517 the moment. It would be real nice if I knew more about this!
519 // Note: this function is now obsolete (along with CalcAlignment)
520 // because the calculations are done statically, for greater speed.
522 size_t wxDebugContext::GetPadding (const size_t size
)
524 size_t pad
= size
% CalcAlignment ();
525 return (pad
) ? sizeof(wxMarkerType
) - pad
: 0;
528 size_t wxDebugContext::PaddedSize (const size_t size
)
530 // Added by Terry Farnham <TJRT@pacbell.net> to replace
531 // slow GetPadding call.
534 padb
= size
& m_balignmask
;
536 return(size
+ m_balign
- padb
);
542 Returns the total amount of memory which we need to get from the system
543 in order to satisfy a caller request. This includes space for the struct
544 plus markers and the caller's memory as well.
546 size_t wxDebugContext::TotSize (const size_t reqSize
)
548 return (PaddedSize (sizeof (wxMemStruct
)) + PaddedSize (reqSize
) +
549 2 * sizeof(wxMarkerType
));
554 Traverse the list of nodes executing the given function on each node.
556 void wxDebugContext::TraverseList (PmSFV func
, wxMemStruct
*from
)
559 from
= wxDebugContext::GetHead ();
561 wxMemStruct
* st
= NULL
;
562 for (st
= from
; st
!= 0; st
= st
->m_next
)
564 void* data
= st
->GetActualData();
565 // if ((data != (void*)m_debugStream) && (data != (void*) m_streamBuf))
566 if (data
!= (void*) wxLog::GetActiveTarget())
577 bool wxDebugContext::PrintList (void)
579 TraverseList ((PmSFV
)&wxMemStruct::PrintNode
, (checkPoint
? checkPoint
->m_next
: NULL
));
584 bool wxDebugContext::Dump(void)
587 const wxChar
* appName
= wxT("application");
591 appNameStr
= wxTheApp
->GetAppName();
592 appName
= appNameStr
.c_str();
593 OutputDumpLine(wxT("----- Memory dump of %s at %s -----"), appName
, static_cast<const wxChar
*>(wxNow().c_str()));
597 OutputDumpLine( wxT("----- Memory dump -----") );
601 TraverseList ((PmSFV
)&wxMemStruct::Dump
, (checkPoint
? checkPoint
->m_next
: NULL
));
603 OutputDumpLine(wxEmptyString
);
604 OutputDumpLine(wxEmptyString
);
609 struct wxDebugStatsStruct
613 wxChar
*instanceClass
;
614 wxDebugStatsStruct
*next
;
617 static wxDebugStatsStruct
*FindStatsStruct(wxDebugStatsStruct
*st
, wxChar
*name
)
621 if (wxStrcmp(st
->instanceClass
, name
) == 0)
628 static wxDebugStatsStruct
*InsertStatsStruct(wxDebugStatsStruct
*head
, wxDebugStatsStruct
*st
)
634 bool wxDebugContext::PrintStatistics(bool detailed
)
637 const wxChar
* appName
= wxT("application");
641 appNameStr
= wxTheApp
->GetAppName();
642 appName
= appNameStr
.c_str();
643 OutputDumpLine(wxT("----- Memory statistics of %s at %s -----"), appName
, static_cast<const wxChar
*>(wxNow().c_str()));
647 OutputDumpLine( wxT("----- Memory statistics -----") );
651 bool currentMode
= GetDebugMode();
654 long noNonObjectNodes
= 0;
655 long noObjectNodes
= 0;
658 wxDebugStatsStruct
*list
= NULL
;
660 wxMemStruct
*from
= (checkPoint
? checkPoint
->m_next
: NULL
);
662 from
= wxDebugContext::GetHead ();
665 for (st
= from
; st
!= 0; st
= st
->m_next
)
667 void* data
= st
->GetActualData();
668 if (detailed
&& (data
!= (void*) wxLog::GetActiveTarget()))
670 wxChar
*className
= (wxChar
*) wxT("nonobject");
671 if (st
->m_isObject
&& st
->GetActualData())
673 wxObject
*obj
= (wxObject
*)st
->GetActualData();
674 if (obj
->GetClassInfo()->GetClassName())
675 className
= (wxChar
*)obj
->GetClassInfo()->GetClassName();
677 wxDebugStatsStruct
*stats
= FindStatsStruct(list
, className
);
680 stats
= (wxDebugStatsStruct
*)malloc(sizeof(wxDebugStatsStruct
));
681 stats
->instanceClass
= className
;
682 stats
->instanceCount
= 0;
683 stats
->totalSize
= 0;
684 list
= InsertStatsStruct(list
, stats
);
686 stats
->instanceCount
++;
687 stats
->totalSize
+= st
->RequestSize();
690 if (data
!= (void*) wxLog::GetActiveTarget())
692 totalSize
+= st
->RequestSize();
704 OutputDumpLine(wxT("%ld objects of class %s, total size %ld"),
705 list
->instanceCount
, list
->instanceClass
, list
->totalSize
);
706 wxDebugStatsStruct
*old
= list
;
710 OutputDumpLine(wxEmptyString
);
713 SetDebugMode(currentMode
);
715 OutputDumpLine(wxT("Number of object items: %ld"), noObjectNodes
);
716 OutputDumpLine(wxT("Number of non-object items: %ld"), noNonObjectNodes
);
717 OutputDumpLine(wxT("Total allocated size: %ld"), totalSize
);
718 OutputDumpLine(wxEmptyString
);
719 OutputDumpLine(wxEmptyString
);
724 bool wxDebugContext::PrintClasses(void)
727 const wxChar
* appName
= wxT("application");
731 appNameStr
= wxTheApp
->GetAppName();
732 appName
= appNameStr
.c_str();
733 wxLogMessage(wxT("----- Classes in %s -----"), appName
);
738 const wxClassInfo
*info
;
740 for (wxClassInfo::const_iterator node
= wxClassInfo::begin_classinfo(),
741 end
= wxClassInfo::end_classinfo();
745 if (info
->GetClassName())
747 wxString
msg(info
->GetClassName());
750 if (info
->GetBaseClassName1() && !info
->GetBaseClassName2())
753 msg
+= info
->GetBaseClassName1();
755 else if (info
->GetBaseClassName1() && info
->GetBaseClassName2())
758 msg
+= info
->GetBaseClassName1() ;
760 msg
+= info
->GetBaseClassName2() ;
762 if (info
->GetConstructor())
763 msg
+= wxT(": dynamic");
769 wxLogMessage(wxEmptyString
);
770 wxLogMessage(wxT("There are %d classes derived from wxObject."), n
);
771 wxLogMessage(wxEmptyString
);
772 wxLogMessage(wxEmptyString
);
776 void wxDebugContext::SetCheckpoint(bool all
)
784 // Checks all nodes since checkpoint, or since start.
785 int wxDebugContext::Check(bool checkAll
)
789 wxMemStruct
*from
= (checkPoint
? checkPoint
->m_next
: NULL
);
790 if (!from
|| checkAll
)
791 from
= wxDebugContext::GetHead ();
793 for (wxMemStruct
* st
= from
; st
!= 0; st
= st
->m_next
)
796 nFailures
+= st
->CheckBlock ();
804 // Count the number of non-wxDebugContext-related objects
805 // that are outstanding
806 int wxDebugContext::CountObjectsLeft(bool sinceCheckpoint
)
810 wxMemStruct
*from
= NULL
;
811 if (sinceCheckpoint
&& checkPoint
)
812 from
= checkPoint
->m_next
;
814 from
= wxDebugContext::GetHead () ;
816 for (wxMemStruct
* st
= from
; st
!= 0; st
= st
->m_next
)
818 void* data
= st
->GetActualData();
819 if (data
!= (void*) wxLog::GetActiveTarget())
826 // This function is used to output the dump
827 void wxDebugContext::OutputDumpLine(const wxChar
*szFormat
, ...)
829 // a buffer of 2048 bytes should be long enough for a file name
834 va_start(argptr
, szFormat
);
835 buf
[WXSIZEOF(buf
)-1] = wxT('\0');
837 // keep 3 bytes for a \r\n\0
838 count
= wxVsnprintf(buf
, WXSIZEOF(buf
)-3, szFormat
, argptr
);
841 count
= WXSIZEOF(buf
)-3;
842 buf
[count
]=wxT('\r');
843 buf
[count
+1]=wxT('\n');
844 buf
[count
+2]=wxT('\0');
846 wxMessageOutputDebug dbgout
;
850 void wxDebugContext::SetShutdownNotifyFunction(wxShutdownNotifyFunction shutdownFn
)
852 sm_shutdownFn
= shutdownFn
;
856 #if USE_THREADSAFE_MEMORY_ALLOCATION
857 static bool memSectionOk
= false;
859 class MemoryCriticalSection
: public wxCriticalSection
862 MemoryCriticalSection() {
865 ~MemoryCriticalSection() {
866 memSectionOk
= false;
870 class MemoryCriticalSectionLocker
873 inline MemoryCriticalSectionLocker(wxCriticalSection
& critsect
)
874 : m_critsect(critsect
), m_locked(memSectionOk
) { if(m_locked
) m_critsect
.Enter(); }
875 inline ~MemoryCriticalSectionLocker() { if(m_locked
) m_critsect
.Leave(); }
878 // no assignment operator nor copy ctor
879 MemoryCriticalSectionLocker(const MemoryCriticalSectionLocker
&);
880 MemoryCriticalSectionLocker
& operator=(const MemoryCriticalSectionLocker
&);
882 wxCriticalSection
& m_critsect
;
886 static MemoryCriticalSection memLocker
;
888 #endif // USE_THREADSAFE_MEMORY_ALLOCATION
891 #if !(defined(__WXMSW__) && (defined(WXUSINGDLL) || defined(WXMAKINGDLL_BASE)))
892 #if wxUSE_GLOBAL_MEMORY_OPERATORS
893 void * operator new (size_t size
, wxChar
* fileName
, int lineNum
)
895 return wxDebugAlloc(size
, fileName
, lineNum
, false, false);
898 void * operator new (size_t size
)
900 return wxDebugAlloc(size
, NULL
, 0, false);
903 void operator delete (void * buf
)
905 wxDebugFree(buf
, false);
908 #if wxUSE_ARRAY_MEMORY_OPERATORS
909 void * operator new[] (size_t size
)
911 return wxDebugAlloc(size
, NULL
, 0, false, true);
914 void * operator new[] (size_t size
, wxChar
* fileName
, int lineNum
)
916 return wxDebugAlloc(size
, fileName
, lineNum
, false, true);
919 void operator delete[] (void * buf
)
921 wxDebugFree(buf
, true);
923 #endif // wxUSE_ARRAY_MEMORY_OPERATORS
924 #endif // wxUSE_GLOBAL_MEMORY_OPERATORS
925 #endif // !(defined(__WXMSW__) && (defined(WXUSINGDLL) || defined(WXMAKINGDLL_BASE)))
927 // TODO: store whether this is a vector or not.
928 void * wxDebugAlloc(size_t size
, wxChar
* fileName
, int lineNum
, bool isObject
, bool WXUNUSED(isVect
) )
930 #if USE_THREADSAFE_MEMORY_ALLOCATION
931 MemoryCriticalSectionLocker
lock(memLocker
);
934 // If not in debugging allocation mode, do the normal thing
935 // so we don't leave any trace of ourselves in the node list.
937 #if defined(__VISAGECPP__) && (__IBMCPP__ < 400 || __IBMC__ < 400 )
938 // VA 3.0 still has trouble in here
939 return (void *)malloc(size
);
941 if (!wxDebugContext::GetDebugMode())
943 return (void *)malloc(size
);
946 int totSize
= wxDebugContext::TotSize (size
);
947 char * buf
= (char *) malloc(totSize
);
949 wxLogMessage(wxT("Call to malloc (%ld) failed."), (long)size
);
952 wxMemStruct
* st
= (wxMemStruct
*)buf
;
953 st
->m_firstMarker
= MemStartCheck
;
954 st
->m_reqSize
= size
;
955 st
->m_fileName
= fileName
;
956 st
->m_lineNum
= lineNum
;
957 st
->m_id
= MemStructId
;
960 st
->m_isObject
= isObject
;
962 // Errors from Append() shouldn't really happen - but just in case!
963 if (st
->Append () == 0) {
964 st
->ErrorMsg ("Trying to append new node");
967 if (wxDebugContext::GetCheckPrevious ()) {
968 if (st
->CheckAllPrevious () < 0) {
969 st
->ErrorMsg ("Checking previous nodes");
973 // Set up the extra markers at the middle and end.
974 char * ptr
= wxDebugContext::MidMarkerPos (buf
);
975 * (wxMarkerType
*) ptr
= MemMidCheck
;
976 ptr
= wxDebugContext::EndMarkerPos (buf
, size
);
977 * (wxMarkerType
*) ptr
= MemEndCheck
;
979 // pointer returned points to the start of the caller's
981 void *m_actualData
= (void *) wxDebugContext::CallerMemPos (buf
);
982 st
->m_actualData
= m_actualData
;
987 // TODO: check whether was allocated as a vector
988 void wxDebugFree(void * buf
, bool WXUNUSED(isVect
) )
990 #if USE_THREADSAFE_MEMORY_ALLOCATION
991 MemoryCriticalSectionLocker
lock(memLocker
);
997 #if defined(__VISAGECPP__) && (__IBMCPP__ < 400 || __IBMC__ < 400 )
998 // VA 3.0 still has trouble in here
1001 // If not in debugging allocation mode, do the normal thing
1002 // so we don't leave any trace of ourselves in the node list.
1003 if (!wxDebugContext::GetDebugMode())
1009 // Points to the start of the entire allocated area.
1010 char * startPointer
= wxDebugContext::StartPos ((char *) buf
);
1011 // Find the struct and make sure that it's identifiable.
1012 wxMemStruct
* st
= (wxMemStruct
*) wxDebugContext::StructPos (startPointer
);
1014 if (! st
->ValidateNode ())
1017 // If this is the current checkpoint, we need to
1018 // move the checkpoint back so it points to a valid
1020 if (st
== wxDebugContext::checkPoint
)
1021 wxDebugContext::checkPoint
= wxDebugContext::checkPoint
->m_prev
;
1023 if (! st
->Unlink ())
1025 st
->ErrorMsg ("Unlinking deleted node");
1028 // Now put in the fill char into the id slot and the caller requested
1029 // memory locations.
1031 (void) memset (wxDebugContext::CallerMemPos (startPointer
), MemFillChar
,
1032 st
->RequestSize ());
1037 // Trace: send output to the current debugging stream
1038 void wxTrace(const wxChar
* ...)
1041 wxFAIL_MSG(wxT("wxTrace is now obsolete. Please use wxDebugXXX instead."));
1044 static wxChar buffer
[512];
1049 wvsprintf(buffer
,fmt
,ap
) ;
1051 vsprintf(buffer
,fmt
,ap
) ;
1056 if (wxDebugContext::HasStream())
1058 wxDebugContext::GetStream() << buffer
;
1059 wxDebugContext::GetStream().flush();
1064 OutputDebugString((LPCTSTR
)buffer
) ;
1066 OutputDebugString((const char*) buffer
) ;
1069 fprintf(stderr
, buffer
);
1075 void wxTraceLevel(int, const wxChar
* ...)
1078 wxFAIL_MSG(wxT("wxTrace is now obsolete. Please use wxDebugXXX instead."));
1080 if (wxDebugContext::GetLevel() < level
)
1084 static wxChar buffer
[512];
1089 wxWvsprintf(buffer
,fmt
,ap
) ;
1091 vsprintf(buffer
,fmt
,ap
) ;
1096 if (wxDebugContext::HasStream())
1098 wxDebugContext::GetStream() << buffer
;
1099 wxDebugContext::GetStream().flush();
1104 OutputDebugString((LPCTSTR
)buffer
) ;
1106 OutputDebugString((const char*) buffer
) ;
1109 fprintf(stderr
, buffer
);
1114 //----------------------------------------------------------------------------
1115 // Final cleanup after all global objects in all files have been destroyed
1116 //----------------------------------------------------------------------------
1118 // Don't set it to 0 by dynamic initialization
1119 // Some compilers will really do the assignment later
1120 // All global variables are initialized to 0 at the very beginning, and this is just fine.
1121 int wxDebugContextDumpDelayCounter::sm_count
;
1123 wxDebugContextDumpDelayCounter::wxDebugContextDumpDelayCounter()
1128 wxDebugContextDumpDelayCounter::~wxDebugContextDumpDelayCounter()
1132 // Notify app if we've been asked to do that
1133 if( wxDebugContext::sm_shutdownFn
)
1134 wxDebugContext::sm_shutdownFn();
1139 void wxDebugContextDumpDelayCounter::DoDump()
1141 if (wxDebugContext::CountObjectsLeft(true) > 0)
1143 wxDebugContext::OutputDumpLine(wxT("There were memory leaks.\n"));
1144 wxDebugContext::Dump();
1145 wxDebugContext::PrintStatistics();
1149 // Even if there is nothing else, make sure that there is at
1150 // least one cleanup counter object
1151 static wxDebugContextDumpDelayCounter wxDebugContextDumpDelayCounter_One
;
1153 #endif // wxUSE_MEMORY_TRACING || wxUSE_DEBUG_CONTEXT