]>
git.saurik.com Git - wxWidgets.git/blob - src/common/memory.cpp
1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: Memory checking implementation
4 // Author: Arthur Seaton, Julian Smart
8 // Copyright: (c) Julian Smart and Markus Holzem
9 // Licence: wxWindows license
10 /////////////////////////////////////////////////////////////////////////////
13 #pragma implementation "memory.h"
16 // For compilers that support precompilation, includes "wx.h".
17 #include "wx/wxprec.h"
27 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
30 // #pragma implementation
41 #include "wx/ioswrap.h"
49 #if !defined(__WATCOMC__) && !(defined(__VMS__) && ( __VMS_VER < 70000000 ) )\
50 && !defined( __MWERKS__ ) && !defined(__SALFORDC__)
70 #include "wx/memory.h"
76 // wxDebugContext wxTheDebugContext;
78 Redefine new and delete so that we can pick up situations where:
79 - we overwrite or underwrite areas of malloc'd memory.
80 - we use uninitialise variables
81 Only do this in debug mode.
83 We change new to get enough memory to allocate a struct, followed
84 by the caller's requested memory, followed by a tag. The struct
85 is used to create a doubly linked list of these areas and also
86 contains another tag. The tags are used to determine when the area
87 has been over/under written.
92 Values which are used to set the markers which will be tested for
93 under/over write. There are 3 of these, one in the struct, one
94 immediately after the struct but before the caller requested memory and
95 one immediately after the requested memory.
97 #define MemStartCheck 0x23A8
98 #define MemMidCheck 0xA328
99 #define MemEndCheck 0x8A32
100 #define MemFillChar 0xAF
101 #define MemStructId 0x666D
104 External interface for the wxMemStruct class. Others are
105 defined inline within the class def. Here we only need to be able
106 to add and delete nodes from the list and handle errors in some way.
110 Used for internal "this shouldn't happen" type of errors.
112 void wxMemStruct::ErrorMsg (const char * mesg
)
114 wxLogDebug(wxT("wxWindows memory checking error: %s"), mesg
);
117 // << m_fileName << ' ' << m_lineNum << endl;
121 Used when we find an overwrite or an underwrite error.
123 void wxMemStruct::ErrorMsg ()
125 wxLogDebug(wxT("wxWindows over/underwrite memory error:"));
128 // cerr << m_fileName << ' ' << m_lineNum << endl;
133 We want to find out if pointers have been overwritten as soon as is
134 possible, so test everything before we dereference it. Of course it's still
135 quite possible that, if things have been overwritten, this function will
136 fall over, but the only way of dealing with that would cost too much in terms
139 int wxMemStruct::AssertList ()
141 if (wxDebugContext::GetHead () != 0 && ! (wxDebugContext::GetHead ())->AssertIt () ||
142 wxDebugContext::GetTail () != 0 && ! wxDebugContext::GetTail ()->AssertIt ()) {
143 ErrorMsg ("Head or tail pointers trashed");
151 Check that the thing we're pointing to has the correct id for a wxMemStruct
152 object and also that it's previous and next pointers are pointing at objects
153 which have valid ids.
154 This is definitely not perfect since we could fall over just trying to access
155 any of the slots which we use here, but I think it's about the best that I
156 can do without doing something like taking all new wxMemStruct pointers and
157 comparing them against all known pointer within the list and then only
158 doing this sort of check _after_ you've found the pointer in the list. That
159 would be safer, but also much more time consuming.
161 int wxMemStruct::AssertIt ()
163 return (m_id
== MemStructId
&&
164 (m_prev
== 0 || m_prev
->m_id
== MemStructId
) &&
165 (m_next
== 0 || m_next
->m_id
== MemStructId
));
170 Additions are always at the tail of the list.
171 Returns 0 on error, non-zero on success.
173 int wxMemStruct::Append ()
178 if (wxDebugContext::GetHead () == 0) {
179 if (wxDebugContext::GetTail () != 0) {
180 ErrorMsg ("Null list should have a null tail pointer");
183 (void) wxDebugContext::SetHead (this);
184 (void) wxDebugContext::SetTail (this);
186 wxDebugContext::GetTail ()->m_next
= this;
187 this->m_prev
= wxDebugContext::GetTail ();
188 (void) wxDebugContext::SetTail (this);
195 Don't actually free up anything here as the space which is used
196 by the node will be free'd up when the whole block is free'd.
197 Returns 0 on error, non-zero on success.
199 int wxMemStruct::Unlink ()
204 if (wxDebugContext::GetHead () == 0 || wxDebugContext::GetTail () == 0) {
205 ErrorMsg ("Trying to remove node from empty list");
209 // Handle the part of the list before this node.
211 if (this != wxDebugContext::GetHead ()) {
212 ErrorMsg ("No previous node for non-head node");
215 (void) wxDebugContext::SetHead (m_next
);
217 if (! m_prev
->AssertIt ()) {
218 ErrorMsg ("Trashed previous pointer");
222 if (m_prev
->m_next
!= this) {
223 ErrorMsg ("List is inconsistent");
226 m_prev
->m_next
= m_next
;
229 // Handle the part of the list after this node.
231 if (this != wxDebugContext::GetTail ()) {
232 ErrorMsg ("No next node for non-tail node");
235 (void) wxDebugContext::SetTail (m_prev
);
237 if (! m_next
->AssertIt ()) {
238 ErrorMsg ("Trashed next pointer");
242 if (m_next
->m_prev
!= this) {
243 ErrorMsg ("List is inconsistent");
246 m_next
->m_prev
= m_prev
;
255 Checks a node and block of memory to see that the markers are still
258 int wxMemStruct::CheckBlock ()
262 if (m_firstMarker
!= MemStartCheck
) {
267 char * pointer
= wxDebugContext::MidMarkerPos ((char *) this);
268 if (* (wxMarkerType
*) pointer
!= MemMidCheck
) {
273 pointer
= wxDebugContext::EndMarkerPos ((char *) this, RequestSize ());
274 if (* (wxMarkerType
*) pointer
!= MemEndCheck
) {
284 Check the list of nodes to see if they are all ok.
286 int wxMemStruct::CheckAllPrevious ()
290 for (wxMemStruct
* st
= this->m_prev
; st
!= 0; st
= st
->m_prev
) {
292 nFailures
+= st
->CheckBlock ();
302 When we delete a node we set the id slot to a specific value and then test
303 against this to see if a nodes have been deleted previously. I don't
304 just set the entire memory to the fillChar because then I'd be overwriting
305 useful stuff like the vtbl which may be needed to output the error message
306 including the file name and line numbers. Without this info the whole point
307 of this class is lost!
309 void wxMemStruct::SetDeleted ()
314 int wxMemStruct::IsDeleted ()
316 return (m_id
== MemFillChar
);
321 Print out a single node. There are many far better ways of doing this
322 but this will suffice for now.
324 void wxMemStruct::PrintNode ()
328 wxObject
*obj
= (wxObject
*)m_actualData
;
329 wxClassInfo
*info
= obj
->GetClassInfo();
331 // Let's put this in standard form so IDEs can load the file at the appropriate
333 wxString
msg(wxT(""));
336 msg
.Printf(wxT("%s(%d): "), m_fileName
, (int)m_lineNum
);
338 if (info
&& info
->GetClassName())
339 msg
+= info
->GetClassName();
341 msg
+= wxT("object");
344 msg2
.Printf(wxT(" at $%lX, size %d"), (long)GetActualData(), (int)RequestSize());
354 msg
.Printf(wxT("%s(%d): "), m_fileName
, (int)m_lineNum
);
355 msg
+= wxT("non-object data");
357 msg2
.Printf(wxT(" at $%lX, size %d\n"), (long)GetActualData(), (int)RequestSize());
364 void wxMemStruct::Dump ()
366 if (!ValidateNode()) return;
370 wxObject
*obj
= (wxObject
*)m_actualData
;
372 wxString
msg(wxT(""));
374 msg
.Printf(wxT("%s(%d): "), m_fileName
, (int)m_lineNum
);
377 /* TODO: We no longer have a stream (using wxLogDebug) so we can't dump it.
378 * Instead, do what wxObject::Dump does.
379 * What should we do long-term, eliminate Dumping? Or specify
380 * that MyClass::Dump should use wxLogDebug? Ugh.
381 obj->Dump(wxDebugContext::GetStream());
384 if (obj
->GetClassInfo() && obj
->GetClassInfo()->GetClassName())
385 msg
+= obj
->GetClassInfo()->GetClassName();
387 msg
+= wxT("unknown object class");
390 msg2
.Printf(wxT(" at $%lX, size %d"), (long)GetActualData(), (int)RequestSize());
397 wxString
msg(wxT(""));
399 msg
.Printf(wxT("%s(%d): "), m_fileName
, (int)m_lineNum
);
402 msg2
.Printf(wxT("non-object data at $%lX, size %d"), (long)GetActualData(), (int)RequestSize() );
410 Validate a node. Check to see that the node is "clean" in the sense
411 that nothing has over/underwritten it etc.
413 int wxMemStruct::ValidateNode ()
415 char * startPointer
= (char *) this;
418 ErrorMsg ("Object already deleted");
420 // Can't use the error routines as we have no recognisable object.
422 wxLogDebug(wxT("Can't verify memory struct - all bets are off!"));
430 for (i = 0; i < wxDebugContext::TotSize (requestSize ()); i++)
431 cout << startPointer [i];
434 if (Marker () != MemStartCheck
)
436 if (* (wxMarkerType
*) wxDebugContext::MidMarkerPos (startPointer
) != MemMidCheck
)
438 if (* (wxMarkerType
*) wxDebugContext::EndMarkerPos (startPointer
,
443 // Back to before the extra buffer and check that
444 // we can still read what we originally wrote.
445 if (Marker () != MemStartCheck
||
446 * (wxMarkerType
*) wxDebugContext::MidMarkerPos (startPointer
)
448 * (wxMarkerType
*) wxDebugContext::EndMarkerPos (startPointer
,
449 RequestSize ()) != MemEndCheck
)
459 The wxDebugContext class.
462 wxMemStruct
*wxDebugContext::m_head
= NULL
;
463 wxMemStruct
*wxDebugContext::m_tail
= NULL
;
464 // ostream *wxDebugContext::m_debugStream = NULL;
465 // streambuf *wxDebugContext::m_streamBuf = NULL;
467 // Must initialise these in wxEntry, and then delete them just before wxEntry exits
468 streambuf
*wxDebugContext::m_streamBuf
= NULL
;
469 ostream
*wxDebugContext::m_debugStream
= NULL
;
471 bool wxDebugContext::m_checkPrevious
= FALSE
;
472 int wxDebugContext::debugLevel
= 1;
473 bool wxDebugContext::debugOn
= TRUE
;
474 wxMemStruct
*wxDebugContext::checkPoint
= NULL
;
476 wxDebugContext::wxDebugContext(void)
478 // m_streamBuf = new wxDebugStreamBuf;
479 // m_debugStream = new ostream(m_streamBuf);
482 wxDebugContext::~wxDebugContext(void)
484 SetStream(NULL
, NULL
);
488 * It's bizarre, but with BC++ 4.5, the value of str changes
489 * between SetFile and SetStream.
492 void wxDebugContext::SetStream(ostream
*str
, streambuf
*buf
)
496 m_debugStream
->flush();
497 delete m_debugStream
;
499 m_debugStream
= NULL
;
501 // Not allowed in Watcom (~streambuf is protected).
502 // Is this trying to say something significant to us??
506 streambuf
* oldBuf
= m_streamBuf
;
515 bool wxDebugContext::SetFile(const wxString
& file
)
517 ofstream
*str
= new ofstream(file
.fn_str());
531 bool wxDebugContext::SetStandardError(void)
535 #if !defined(_WINDLL)
536 wxDebugStreamBuf
*buf
= new wxDebugStreamBuf
;
537 ostream
*stream
= new ostream(m_streamBuf
);
538 SetStream(stream
, buf
);
549 Work out the positions of the markers by creating an array of 2 markers
550 and comparing the addresses of the 2 elements. Use this number as the
551 alignment for markers.
553 size_t wxDebugContext::CalcAlignment ()
556 return (char *) &ar
[1] - (char *) &ar
[0];
560 char * wxDebugContext::StructPos (const char * buf
)
565 char * wxDebugContext::MidMarkerPos (const char * buf
)
567 return StructPos (buf
) + PaddedSize (sizeof (wxMemStruct
));
570 char * wxDebugContext::CallerMemPos (const char * buf
)
572 return MidMarkerPos (buf
) + PaddedSize (sizeof(wxMarkerType
));
576 char * wxDebugContext::EndMarkerPos (const char * buf
, const size_t size
)
578 return CallerMemPos (buf
) + PaddedSize (size
);
583 Slightly different as this takes a pointer to the start of the caller
584 requested region and returns a pointer to the start of the buffer.
586 char * wxDebugContext::StartPos (const char * caller
)
588 return ((char *) (caller
- wxDebugContext::PaddedSize (sizeof(wxMarkerType
)) -
589 wxDebugContext::PaddedSize (sizeof (wxMemStruct
))));
593 We may need padding between various parts of the allocated memory.
594 Given a size of memory, this returns the amount of memory which should
595 be allocated in order to allow for alignment of the following object.
597 I don't know how portable this stuff is, but it seems to work for me at
598 the moment. It would be real nice if I knew more about this!
600 size_t wxDebugContext::GetPadding (const size_t size
)
602 size_t pad
= size
% CalcAlignment ();
603 return (pad
) ? sizeof(wxMarkerType
) - pad
: 0;
608 size_t wxDebugContext::PaddedSize (const size_t size
)
610 return size
+ GetPadding (size
);
614 Returns the total amount of memory which we need to get from the system
615 in order to satisfy a caller request. This includes space for the struct
616 plus markers and the caller's memory as well.
618 size_t wxDebugContext::TotSize (const size_t reqSize
)
620 return (PaddedSize (sizeof (wxMemStruct
)) + PaddedSize (reqSize
) +
621 2 * sizeof(wxMarkerType
));
626 Traverse the list of nodes executing the given function on each node.
628 void wxDebugContext::TraverseList (PmSFV func
, wxMemStruct
*from
)
631 from
= wxDebugContext::GetHead ();
633 for (wxMemStruct
* st
= from
; st
!= 0; st
= st
->m_next
)
635 void* data
= st
->GetActualData();
636 // if ((data != (void*)m_debugStream) && (data != (void*) m_streamBuf))
637 if (data
!= (void*) wxLog::GetActiveTarget())
648 bool wxDebugContext::PrintList (void)
654 TraverseList ((PmSFV
)&wxMemStruct::PrintNode
, (checkPoint
? checkPoint
->m_next
: (wxMemStruct
*)NULL
));
662 bool wxDebugContext::Dump(void)
670 wxChar
* appName
= wxT("application");
671 wxString
appNameStr("");
674 appNameStr
= wxTheApp
->GetAppName();
675 appName
= WXSTRINGCAST appNameStr
;
676 wxLogDebug(wxT("----- Memory dump of %s at %s -----"), appName
, WXSTRINGCAST
wxNow() );
680 wxLogDebug( wxT("----- Memory dump -----") );
683 TraverseList ((PmSFV
)&wxMemStruct::Dump
, (checkPoint
? checkPoint
->m_next
: (wxMemStruct
*)NULL
));
685 wxLogDebug( wxT("") );
686 wxLogDebug( wxT("") );
694 struct wxDebugStatsStruct
698 wxChar
*instanceClass
;
699 wxDebugStatsStruct
*next
;
702 static wxDebugStatsStruct
*FindStatsStruct(wxDebugStatsStruct
*st
, wxChar
*name
)
706 if (wxStrcmp(st
->instanceClass
, name
) == 0)
713 static wxDebugStatsStruct
*InsertStatsStruct(wxDebugStatsStruct
*head
, wxDebugStatsStruct
*st
)
719 bool wxDebugContext::PrintStatistics(bool detailed
)
727 wxChar
* appName
= wxT("application");
728 wxString
appNameStr(wxT(""));
731 appNameStr
= wxTheApp
->GetAppName();
732 appName
= WXSTRINGCAST appNameStr
;
733 wxLogDebug(wxT("----- Memory statistics of %s at %s -----"), appName
, WXSTRINGCAST
wxNow() );
737 wxLogDebug( wxT("----- Memory statistics -----") );
741 bool currentMode
= GetDebugMode();
744 long noNonObjectNodes
= 0;
745 long noObjectNodes
= 0;
748 wxDebugStatsStruct
*list
= NULL
;
750 wxMemStruct
*from
= (checkPoint
? checkPoint
->m_next
: (wxMemStruct
*)NULL
);
752 from
= wxDebugContext::GetHead ();
755 for (st
= from
; st
!= 0; st
= st
->m_next
)
757 void* data
= st
->GetActualData();
758 // if (detailed && (data != (void*)m_debugStream) && (data != (void*) m_streamBuf))
759 if (detailed
&& (data
!= (void*) wxLog::GetActiveTarget()))
761 wxChar
*className
= wxT("nonobject");
762 if (st
->m_isObject
&& st
->GetActualData())
764 wxObject
*obj
= (wxObject
*)st
->GetActualData();
765 if (obj
->GetClassInfo()->GetClassName())
766 className
= obj
->GetClassInfo()->GetClassName();
768 wxDebugStatsStruct
*stats
= FindStatsStruct(list
, className
);
771 stats
= (wxDebugStatsStruct
*)malloc(sizeof(wxDebugStatsStruct
));
772 stats
->instanceClass
= className
;
773 stats
->instanceCount
= 0;
774 stats
->totalSize
= 0;
775 list
= InsertStatsStruct(list
, stats
);
777 stats
->instanceCount
++;
778 stats
->totalSize
+= st
->RequestSize();
781 // if ((data != (void*)m_debugStream) && (data != (void*) m_streamBuf))
782 if (data
!= (void*) wxLog::GetActiveTarget())
784 totalSize
+= st
->RequestSize();
796 wxLogDebug(wxT("%ld objects of class %s, total size %ld"),
797 list
->instanceCount
, list
->instanceClass
, list
->totalSize
);
798 wxDebugStatsStruct
*old
= list
;
805 SetDebugMode(currentMode
);
807 wxLogDebug(wxT("Number of object items: %ld"), noObjectNodes
);
808 wxLogDebug(wxT("Number of non-object items: %ld"), noNonObjectNodes
);
809 wxLogDebug(wxT("Total allocated size: %ld"), totalSize
);
819 bool wxDebugContext::PrintClasses(void)
826 wxChar
* appName
= wxT("application");
827 wxString
appNameStr(wxT(""));
830 appNameStr
= wxTheApp
->GetAppName();
831 appName
= WXSTRINGCAST appNameStr
;
832 wxLogDebug(wxT("----- Classes in %s -----"), appName
);
840 wxClassInfo::sm_classTable
->BeginFind();
841 node
= wxClassInfo::sm_classTable
->Next();
844 info
= (wxClassInfo
*)node
->Data();
845 if (info
->GetClassName())
847 wxString
msg(info
->GetClassName());
850 if (info
->GetBaseClassName1() && !info
->GetBaseClassName2())
853 msg
+= info
->GetBaseClassName1();
855 else if (info
->GetBaseClassName1() && info
->GetBaseClassName2())
858 msg
+= info
->GetBaseClassName1() ;
860 msg
+= info
->GetBaseClassName2() ;
862 if (info
->GetConstructor())
863 msg
+= wxT(": dynamic");
867 node
= wxClassInfo::sm_classTable
->Next();
871 wxLogDebug(wxT("There are %d classes derived from wxObject."), n
);
877 void wxDebugContext::SetCheckpoint(bool all
)
885 // Checks all nodes since checkpoint, or since start.
886 int wxDebugContext::Check(bool checkAll
)
890 wxMemStruct
*from
= (checkPoint
? checkPoint
->m_next
: (wxMemStruct
*)NULL
);
891 if (!from
|| checkAll
)
892 from
= wxDebugContext::GetHead ();
894 for (wxMemStruct
* st
= from
; st
!= 0; st
= st
->m_next
)
897 nFailures
+= st
->CheckBlock ();
905 // Count the number of non-wxDebugContext-related objects
906 // that are outstanding
907 int wxDebugContext::CountObjectsLeft(bool sinceCheckpoint
)
911 wxMemStruct
*from
= NULL
;
912 if (sinceCheckpoint
&& checkPoint
)
913 from
= checkPoint
->m_next
;
915 from
= wxDebugContext::GetHead () ;
917 for (wxMemStruct
* st
= from
; st
!= 0; st
= st
->m_next
)
919 void* data
= st
->GetActualData();
920 // if ((data != (void*)m_debugStream) && (data != (void*) m_streamBuf))
921 if (data
!= (void*) wxLog::GetActiveTarget())
929 The global operator new used for everything apart from getting
930 dynamic storage within this function itself.
933 // We'll only do malloc and free for the moment: leave the interesting
934 // stuff for the wxObject versions.
936 #if defined(__WXDEBUG__) && wxUSE_GLOBAL_MEMORY_OPERATORS
942 // Seems OK all of a sudden. Maybe to do with linking with multithreaded library?
943 #if 0 // def __VISUALC__
944 #define NO_DEBUG_ALLOCATION
947 // Unfortunately ~wxDebugStreamBuf doesn't work (VC++ 5) when we enable the debugging
948 // code. I have no idea why. In BC++ 4.5, we have a similar problem the debug
949 // stream myseriously changing pointer address between being passed from SetFile to SetStream.
950 // See docs/msw/issues.txt.
951 void * operator new (size_t size
, wxChar
* fileName
, int lineNum
)
953 #ifdef NO_DEBUG_ALLOCATION
956 return wxDebugAlloc(size
, fileName
, lineNum
, FALSE
, FALSE
);
960 // Added JACS 25/11/98
961 void * operator new (size_t size
)
963 #ifdef NO_DEBUG_ALLOCATION
966 return wxDebugAlloc(size
, NULL
, 0, FALSE
);
970 #if wxUSE_ARRAY_MEMORY_OPERATORS
971 void * operator new[] (size_t size
)
973 #ifdef NO_DEBUG_ALLOCATION
976 return wxDebugAlloc(size
, NULL
, 0, FALSE
, TRUE
);
981 #if wxUSE_ARRAY_MEMORY_OPERATORS
982 void * operator new[] (size_t size
, wxChar
* fileName
, int lineNum
)
984 #ifdef NO_DEBUG_ALLOCATION
987 return wxDebugAlloc(size
, fileName
, lineNum
, FALSE
, TRUE
);
992 #if !defined(__VISAGECPP__) // already defines this by default
993 void operator delete (void * buf
)
995 #ifdef NO_DEBUG_ALLOCATION
1004 #if defined(__VISUALC__) && (__VISUALC__ >= 1200)
1005 void operator delete(void* pData
, wxChar
* /* fileName */, int /* lineNum */)
1007 // ::operator delete(pData);
1008 // JACS 21/11/1998: surely we need to call wxDebugFree?
1009 wxDebugFree(pData
, FALSE
);
1011 // New operator 21/11/1998
1012 void operator delete[](void* pData
, char* /* fileName */, int /* lineNum */)
1014 wxDebugFree(pData
, TRUE
);
1018 #if wxUSE_ARRAY_MEMORY_OPERATORS
1020 void operator delete[] (void * buf
)
1022 #ifdef NO_DEBUG_ALLOCATION
1025 wxDebugFree(buf
, TRUE
);
1032 // TODO: store whether this is a vector or not.
1033 void * wxDebugAlloc(size_t size
, wxChar
* fileName
, int lineNum
, bool isObject
, bool WXUNUSED(isVect
) )
1035 // If not in debugging allocation mode, do the normal thing
1036 // so we don't leave any trace of ourselves in the node list.
1038 if (!wxDebugContext::GetDebugMode())
1040 return (void *)malloc(size
);
1043 int totSize
= wxDebugContext::TotSize (size
);
1044 char * buf
= (char *) malloc(totSize
);
1046 wxLogDebug(wxT("Call to malloc (%ld) failed."), (long)size
);
1049 wxMemStruct
* st
= (wxMemStruct
*)buf
;
1050 st
->m_firstMarker
= MemStartCheck
;
1051 st
->m_reqSize
= size
;
1052 st
->m_fileName
= fileName
;
1053 st
->m_lineNum
= lineNum
;
1054 st
->m_id
= MemStructId
;
1057 st
->m_isObject
= isObject
;
1059 // Errors from Append() shouldn't really happen - but just in case!
1060 if (st
->Append () == 0) {
1061 st
->ErrorMsg ("Trying to append new node");
1064 if (wxDebugContext::GetCheckPrevious ()) {
1065 if (st
->CheckAllPrevious () < 0) {
1066 st
->ErrorMsg ("Checking previous nodes");
1070 // Set up the extra markers at the middle and end.
1071 char * ptr
= wxDebugContext::MidMarkerPos (buf
);
1072 * (wxMarkerType
*) ptr
= MemMidCheck
;
1073 ptr
= wxDebugContext::EndMarkerPos (buf
, size
);
1074 * (wxMarkerType
*) ptr
= MemEndCheck
;
1076 // pointer returned points to the start of the caller's
1078 void *m_actualData
= (void *) wxDebugContext::CallerMemPos (buf
);
1079 st
->m_actualData
= m_actualData
;
1081 return m_actualData
;
1084 // TODO: check whether was allocated as a vector
1085 void wxDebugFree(void * buf
, bool WXUNUSED(isVect
) )
1090 // If not in debugging allocation mode, do the normal thing
1091 // so we don't leave any trace of ourselves in the node list.
1092 if (!wxDebugContext::GetDebugMode())
1098 // Points to the start of the entire allocated area.
1099 char * startPointer
= wxDebugContext::StartPos ((char *) buf
);
1100 // Find the struct and make sure that it's identifiable.
1101 wxMemStruct
* st
= (wxMemStruct
*) wxDebugContext::StructPos (startPointer
);
1103 if (! st
->ValidateNode ())
1106 // If this is the current checkpoint, we need to
1107 // move the checkpoint back so it points to a valid
1109 if (st
== wxDebugContext::checkPoint
)
1110 wxDebugContext::checkPoint
= wxDebugContext::checkPoint
->m_prev
;
1112 if (! st
->Unlink ())
1114 st
->ErrorMsg ("Unlinking deleted node");
1117 // Now put in the fill char into the id slot and the caller requested
1118 // memory locations.
1120 (void) memset (wxDebugContext::CallerMemPos (startPointer
), MemFillChar
,
1121 st
->RequestSize ());
1123 // Don't allow delayed freeing of memory in this version
1124 // if (!wxDebugContext::GetDelayFree())
1125 // free((void *)st);
1129 // Trace: send output to the current debugging stream
1130 void wxTrace(const wxChar
*fmt
...)
1133 static wxChar buffer
[512];
1138 wvsprintf(buffer
,fmt
,ap
) ;
1140 vsprintf(buffer
,fmt
,ap
) ;
1145 if (wxDebugContext::HasStream())
1147 wxDebugContext::GetStream() << buffer
;
1148 wxDebugContext::GetStream().flush();
1153 OutputDebugString((LPCTSTR
)buffer
) ;
1155 OutputDebugString((const char*) buffer
) ;
1158 fprintf(stderr
, buffer
);
1163 void wxTraceLevel(int level
, const wxChar
*fmt
...)
1165 if (wxDebugContext::GetLevel() < level
)
1169 static wxChar buffer
[512];
1174 wvsprintf(buffer
,fmt
,ap
) ;
1176 vsprintf(buffer
,fmt
,ap
) ;
1181 if (wxDebugContext::HasStream())
1183 wxDebugContext::GetStream() << buffer
;
1184 wxDebugContext::GetStream().flush();
1189 OutputDebugString((LPCTSTR
)buffer
) ;
1191 OutputDebugString((const char*) buffer
) ;
1194 fprintf(stderr
, buffer
);
1198 #else // wxUSE_MEMORY_TRACING && defined(__WXDEBUG__)
1199 void wxTrace(const char *WXUNUSED(fmt
) ...)
1203 void wxTraceLevel(int WXUNUSED(level
), const char *WXUNUSED(fmt
) ...)