]>
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 // For faster alignment calculation
477 static wxMarkerType markerCalc
[2];
478 int wxDebugContext::m_balign
= (int)((char *)&markerCalc
[1] - (char*)&markerCalc
[0]);
479 int wxDebugContext::m_balignmask
= (int)((char *)&markerCalc
[1] - (char*)&markerCalc
[0]) - 1;
481 wxDebugContext::wxDebugContext(void)
483 // m_streamBuf = new wxDebugStreamBuf;
484 // m_debugStream = new ostream(m_streamBuf);
487 wxDebugContext::~wxDebugContext(void)
489 SetStream(NULL
, NULL
);
493 * It's bizarre, but with BC++ 4.5, the value of str changes
494 * between SetFile and SetStream.
497 void wxDebugContext::SetStream(ostream
*str
, streambuf
*buf
)
501 m_debugStream
->flush();
502 delete m_debugStream
;
504 m_debugStream
= NULL
;
506 // Not allowed in Watcom (~streambuf is protected).
507 // Is this trying to say something significant to us??
511 streambuf
* oldBuf
= m_streamBuf
;
520 bool wxDebugContext::SetFile(const wxString
& file
)
522 ofstream
*str
= new ofstream(file
.fn_str());
536 bool wxDebugContext::SetStandardError(void)
540 #if !defined(_WINDLL)
541 wxDebugStreamBuf
*buf
= new wxDebugStreamBuf
;
542 ostream
*stream
= new ostream(m_streamBuf
);
543 SetStream(stream
, buf
);
554 Work out the positions of the markers by creating an array of 2 markers
555 and comparing the addresses of the 2 elements. Use this number as the
556 alignment for markers.
558 size_t wxDebugContext::CalcAlignment ()
561 return (char *) &ar
[1] - (char *) &ar
[0];
565 char * wxDebugContext::StructPos (const char * buf
)
570 char * wxDebugContext::MidMarkerPos (const char * buf
)
572 return StructPos (buf
) + PaddedSize (sizeof (wxMemStruct
));
575 char * wxDebugContext::CallerMemPos (const char * buf
)
577 return MidMarkerPos (buf
) + PaddedSize (sizeof(wxMarkerType
));
581 char * wxDebugContext::EndMarkerPos (const char * buf
, const size_t size
)
583 return CallerMemPos (buf
) + PaddedSize (size
);
588 Slightly different as this takes a pointer to the start of the caller
589 requested region and returns a pointer to the start of the buffer.
591 char * wxDebugContext::StartPos (const char * caller
)
593 return ((char *) (caller
- wxDebugContext::PaddedSize (sizeof(wxMarkerType
)) -
594 wxDebugContext::PaddedSize (sizeof (wxMemStruct
))));
598 We may need padding between various parts of the allocated memory.
599 Given a size of memory, this returns the amount of memory which should
600 be allocated in order to allow for alignment of the following object.
602 I don't know how portable this stuff is, but it seems to work for me at
603 the moment. It would be real nice if I knew more about this!
605 // Note: this function is now obsolete (along with CalcAlignment)
606 // because the calculations are done statically, for greater speed.
608 size_t wxDebugContext::GetPadding (const size_t size
)
610 size_t pad
= size
% CalcAlignment ();
611 return (pad
) ? sizeof(wxMarkerType
) - pad
: 0;
614 size_t wxDebugContext::PaddedSize (const size_t size
)
616 // Added by Terry Farnham <TJRT@pacbell.net> to replace
617 // slow GetPadding call.
620 padb
= size
& m_balignmask
;
622 return(size
+ m_balign
- padb
);
628 return size
+ GetPadding (size
);
633 Returns the total amount of memory which we need to get from the system
634 in order to satisfy a caller request. This includes space for the struct
635 plus markers and the caller's memory as well.
637 size_t wxDebugContext::TotSize (const size_t reqSize
)
639 return (PaddedSize (sizeof (wxMemStruct
)) + PaddedSize (reqSize
) +
640 2 * sizeof(wxMarkerType
));
645 Traverse the list of nodes executing the given function on each node.
647 void wxDebugContext::TraverseList (PmSFV func
, wxMemStruct
*from
)
650 from
= wxDebugContext::GetHead ();
652 for (wxMemStruct
* st
= from
; st
!= 0; st
= st
->m_next
)
654 void* data
= st
->GetActualData();
655 // if ((data != (void*)m_debugStream) && (data != (void*) m_streamBuf))
656 if (data
!= (void*) wxLog::GetActiveTarget())
667 bool wxDebugContext::PrintList (void)
673 TraverseList ((PmSFV
)&wxMemStruct::PrintNode
, (checkPoint
? checkPoint
->m_next
: (wxMemStruct
*)NULL
));
681 bool wxDebugContext::Dump(void)
689 wxChar
* appName
= wxT("application");
690 wxString
appNameStr("");
693 appNameStr
= wxTheApp
->GetAppName();
694 appName
= WXSTRINGCAST appNameStr
;
695 wxLogDebug(wxT("----- Memory dump of %s at %s -----"), appName
, WXSTRINGCAST
wxNow() );
699 wxLogDebug( wxT("----- Memory dump -----") );
702 TraverseList ((PmSFV
)&wxMemStruct::Dump
, (checkPoint
? checkPoint
->m_next
: (wxMemStruct
*)NULL
));
704 wxLogDebug( wxT("") );
705 wxLogDebug( wxT("") );
713 struct wxDebugStatsStruct
717 wxChar
*instanceClass
;
718 wxDebugStatsStruct
*next
;
721 static wxDebugStatsStruct
*FindStatsStruct(wxDebugStatsStruct
*st
, wxChar
*name
)
725 if (wxStrcmp(st
->instanceClass
, name
) == 0)
732 static wxDebugStatsStruct
*InsertStatsStruct(wxDebugStatsStruct
*head
, wxDebugStatsStruct
*st
)
738 bool wxDebugContext::PrintStatistics(bool detailed
)
746 wxChar
* appName
= wxT("application");
747 wxString
appNameStr(wxT(""));
750 appNameStr
= wxTheApp
->GetAppName();
751 appName
= WXSTRINGCAST appNameStr
;
752 wxLogDebug(wxT("----- Memory statistics of %s at %s -----"), appName
, WXSTRINGCAST
wxNow() );
756 wxLogDebug( wxT("----- Memory statistics -----") );
760 bool currentMode
= GetDebugMode();
763 long noNonObjectNodes
= 0;
764 long noObjectNodes
= 0;
767 wxDebugStatsStruct
*list
= NULL
;
769 wxMemStruct
*from
= (checkPoint
? checkPoint
->m_next
: (wxMemStruct
*)NULL
);
771 from
= wxDebugContext::GetHead ();
774 for (st
= from
; st
!= 0; st
= st
->m_next
)
776 void* data
= st
->GetActualData();
777 // if (detailed && (data != (void*)m_debugStream) && (data != (void*) m_streamBuf))
778 if (detailed
&& (data
!= (void*) wxLog::GetActiveTarget()))
780 wxChar
*className
= wxT("nonobject");
781 if (st
->m_isObject
&& st
->GetActualData())
783 wxObject
*obj
= (wxObject
*)st
->GetActualData();
784 if (obj
->GetClassInfo()->GetClassName())
785 className
= obj
->GetClassInfo()->GetClassName();
787 wxDebugStatsStruct
*stats
= FindStatsStruct(list
, className
);
790 stats
= (wxDebugStatsStruct
*)malloc(sizeof(wxDebugStatsStruct
));
791 stats
->instanceClass
= className
;
792 stats
->instanceCount
= 0;
793 stats
->totalSize
= 0;
794 list
= InsertStatsStruct(list
, stats
);
796 stats
->instanceCount
++;
797 stats
->totalSize
+= st
->RequestSize();
800 // if ((data != (void*)m_debugStream) && (data != (void*) m_streamBuf))
801 if (data
!= (void*) wxLog::GetActiveTarget())
803 totalSize
+= st
->RequestSize();
815 wxLogDebug(wxT("%ld objects of class %s, total size %ld"),
816 list
->instanceCount
, list
->instanceClass
, list
->totalSize
);
817 wxDebugStatsStruct
*old
= list
;
824 SetDebugMode(currentMode
);
826 wxLogDebug(wxT("Number of object items: %ld"), noObjectNodes
);
827 wxLogDebug(wxT("Number of non-object items: %ld"), noNonObjectNodes
);
828 wxLogDebug(wxT("Total allocated size: %ld"), totalSize
);
838 bool wxDebugContext::PrintClasses(void)
845 wxChar
* appName
= wxT("application");
846 wxString
appNameStr(wxT(""));
849 appNameStr
= wxTheApp
->GetAppName();
850 appName
= WXSTRINGCAST appNameStr
;
851 wxLogDebug(wxT("----- Classes in %s -----"), appName
);
859 wxClassInfo::sm_classTable
->BeginFind();
860 node
= wxClassInfo::sm_classTable
->Next();
863 info
= (wxClassInfo
*)node
->Data();
864 if (info
->GetClassName())
866 wxString
msg(info
->GetClassName());
869 if (info
->GetBaseClassName1() && !info
->GetBaseClassName2())
872 msg
+= info
->GetBaseClassName1();
874 else if (info
->GetBaseClassName1() && info
->GetBaseClassName2())
877 msg
+= info
->GetBaseClassName1() ;
879 msg
+= info
->GetBaseClassName2() ;
881 if (info
->GetConstructor())
882 msg
+= wxT(": dynamic");
886 node
= wxClassInfo::sm_classTable
->Next();
890 wxLogDebug(wxT("There are %d classes derived from wxObject."), n
);
896 void wxDebugContext::SetCheckpoint(bool all
)
904 // Checks all nodes since checkpoint, or since start.
905 int wxDebugContext::Check(bool checkAll
)
909 wxMemStruct
*from
= (checkPoint
? checkPoint
->m_next
: (wxMemStruct
*)NULL
);
910 if (!from
|| checkAll
)
911 from
= wxDebugContext::GetHead ();
913 for (wxMemStruct
* st
= from
; st
!= 0; st
= st
->m_next
)
916 nFailures
+= st
->CheckBlock ();
924 // Count the number of non-wxDebugContext-related objects
925 // that are outstanding
926 int wxDebugContext::CountObjectsLeft(bool sinceCheckpoint
)
930 wxMemStruct
*from
= NULL
;
931 if (sinceCheckpoint
&& checkPoint
)
932 from
= checkPoint
->m_next
;
934 from
= wxDebugContext::GetHead () ;
936 for (wxMemStruct
* st
= from
; st
!= 0; st
= st
->m_next
)
938 void* data
= st
->GetActualData();
939 // if ((data != (void*)m_debugStream) && (data != (void*) m_streamBuf))
940 if (data
!= (void*) wxLog::GetActiveTarget())
948 The global operator new used for everything apart from getting
949 dynamic storage within this function itself.
952 // We'll only do malloc and free for the moment: leave the interesting
953 // stuff for the wxObject versions.
955 #if defined(__WXDEBUG__) && wxUSE_GLOBAL_MEMORY_OPERATORS
961 // Seems OK all of a sudden. Maybe to do with linking with multithreaded library?
962 #if 0 // def __VISUALC__
963 #define NO_DEBUG_ALLOCATION
966 // Unfortunately ~wxDebugStreamBuf doesn't work (VC++ 5) when we enable the debugging
967 // code. I have no idea why. In BC++ 4.5, we have a similar problem the debug
968 // stream myseriously changing pointer address between being passed from SetFile to SetStream.
969 // See docs/msw/issues.txt.
970 void * operator new (size_t size
, wxChar
* fileName
, int lineNum
)
972 #ifdef NO_DEBUG_ALLOCATION
975 return wxDebugAlloc(size
, fileName
, lineNum
, FALSE
, FALSE
);
979 // Added JACS 25/11/98
980 void * operator new (size_t size
)
982 #ifdef NO_DEBUG_ALLOCATION
985 return wxDebugAlloc(size
, NULL
, 0, FALSE
);
989 #if wxUSE_ARRAY_MEMORY_OPERATORS
990 void * operator new[] (size_t size
)
992 #ifdef NO_DEBUG_ALLOCATION
995 return wxDebugAlloc(size
, NULL
, 0, FALSE
, TRUE
);
1000 #if wxUSE_ARRAY_MEMORY_OPERATORS
1001 void * operator new[] (size_t size
, wxChar
* fileName
, int lineNum
)
1003 #ifdef NO_DEBUG_ALLOCATION
1004 return malloc(size
);
1006 return wxDebugAlloc(size
, fileName
, lineNum
, FALSE
, TRUE
);
1011 #if !defined(__VISAGECPP__) // already defines this by default
1012 void operator delete (void * buf
)
1014 #ifdef NO_DEBUG_ALLOCATION
1023 #if defined(__VISUALC__) && (__VISUALC__ >= 1200)
1024 void operator delete(void* pData
, wxChar
* /* fileName */, int /* lineNum */)
1026 wxDebugFree(pData
, FALSE
);
1028 // New operator 21/11/1998
1029 void operator delete[](void* pData
, char* /* fileName */, int /* lineNum */)
1031 wxDebugFree(pData
, TRUE
);
1035 #if wxUSE_ARRAY_MEMORY_OPERATORS
1037 void operator delete[] (void * buf
)
1039 #ifdef NO_DEBUG_ALLOCATION
1042 wxDebugFree(buf
, TRUE
);
1049 // TODO: store whether this is a vector or not.
1050 void * wxDebugAlloc(size_t size
, wxChar
* fileName
, int lineNum
, bool isObject
, bool WXUNUSED(isVect
) )
1052 // If not in debugging allocation mode, do the normal thing
1053 // so we don't leave any trace of ourselves in the node list.
1055 if (!wxDebugContext::GetDebugMode())
1057 return (void *)malloc(size
);
1060 int totSize
= wxDebugContext::TotSize (size
);
1061 char * buf
= (char *) malloc(totSize
);
1063 wxLogDebug(wxT("Call to malloc (%ld) failed."), (long)size
);
1066 wxMemStruct
* st
= (wxMemStruct
*)buf
;
1067 st
->m_firstMarker
= MemStartCheck
;
1068 st
->m_reqSize
= size
;
1069 st
->m_fileName
= fileName
;
1070 st
->m_lineNum
= lineNum
;
1071 st
->m_id
= MemStructId
;
1074 st
->m_isObject
= isObject
;
1076 // Errors from Append() shouldn't really happen - but just in case!
1077 if (st
->Append () == 0) {
1078 st
->ErrorMsg ("Trying to append new node");
1081 if (wxDebugContext::GetCheckPrevious ()) {
1082 if (st
->CheckAllPrevious () < 0) {
1083 st
->ErrorMsg ("Checking previous nodes");
1087 // Set up the extra markers at the middle and end.
1088 char * ptr
= wxDebugContext::MidMarkerPos (buf
);
1089 * (wxMarkerType
*) ptr
= MemMidCheck
;
1090 ptr
= wxDebugContext::EndMarkerPos (buf
, size
);
1091 * (wxMarkerType
*) ptr
= MemEndCheck
;
1093 // pointer returned points to the start of the caller's
1095 void *m_actualData
= (void *) wxDebugContext::CallerMemPos (buf
);
1096 st
->m_actualData
= m_actualData
;
1098 return m_actualData
;
1101 // TODO: check whether was allocated as a vector
1102 void wxDebugFree(void * buf
, bool WXUNUSED(isVect
) )
1107 // If not in debugging allocation mode, do the normal thing
1108 // so we don't leave any trace of ourselves in the node list.
1109 if (!wxDebugContext::GetDebugMode())
1115 // Points to the start of the entire allocated area.
1116 char * startPointer
= wxDebugContext::StartPos ((char *) buf
);
1117 // Find the struct and make sure that it's identifiable.
1118 wxMemStruct
* st
= (wxMemStruct
*) wxDebugContext::StructPos (startPointer
);
1120 if (! st
->ValidateNode ())
1123 // If this is the current checkpoint, we need to
1124 // move the checkpoint back so it points to a valid
1126 if (st
== wxDebugContext::checkPoint
)
1127 wxDebugContext::checkPoint
= wxDebugContext::checkPoint
->m_prev
;
1129 if (! st
->Unlink ())
1131 st
->ErrorMsg ("Unlinking deleted node");
1134 // Now put in the fill char into the id slot and the caller requested
1135 // memory locations.
1137 (void) memset (wxDebugContext::CallerMemPos (startPointer
), MemFillChar
,
1138 st
->RequestSize ());
1140 // Don't allow delayed freeing of memory in this version
1141 // if (!wxDebugContext::GetDelayFree())
1142 // free((void *)st);
1146 // Trace: send output to the current debugging stream
1147 void wxTrace(const wxChar
*fmt
...)
1150 static wxChar buffer
[512];
1155 wvsprintf(buffer
,fmt
,ap
) ;
1157 vsprintf(buffer
,fmt
,ap
) ;
1162 if (wxDebugContext::HasStream())
1164 wxDebugContext::GetStream() << buffer
;
1165 wxDebugContext::GetStream().flush();
1170 OutputDebugString((LPCTSTR
)buffer
) ;
1172 OutputDebugString((const char*) buffer
) ;
1175 fprintf(stderr
, buffer
);
1180 void wxTraceLevel(int level
, const wxChar
*fmt
...)
1182 if (wxDebugContext::GetLevel() < level
)
1186 static wxChar buffer
[512];
1191 wvsprintf(buffer
,fmt
,ap
) ;
1193 vsprintf(buffer
,fmt
,ap
) ;
1198 if (wxDebugContext::HasStream())
1200 wxDebugContext::GetStream() << buffer
;
1201 wxDebugContext::GetStream().flush();
1206 OutputDebugString((LPCTSTR
)buffer
) ;
1208 OutputDebugString((const char*) buffer
) ;
1211 fprintf(stderr
, buffer
);
1215 #else // wxUSE_MEMORY_TRACING && defined(__WXDEBUG__)
1216 void wxTrace(const char *WXUNUSED(fmt
) ...)
1220 void wxTraceLevel(int WXUNUSED(level
), const char *WXUNUSED(fmt
) ...)