]>
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__) && !defined( __MWERKS__ ) && !defined(__SALFORDC__)
69 #include "wx/memory.h"
75 // wxDebugContext wxTheDebugContext;
77 Redefine new and delete so that we can pick up situations where:
78 - we overwrite or underwrite areas of malloc'd memory.
79 - we use uninitialise variables
80 Only do this in debug mode.
82 We change new to get enough memory to allocate a struct, followed
83 by the caller's requested memory, followed by a tag. The struct
84 is used to create a doubly linked list of these areas and also
85 contains another tag. The tags are used to determine when the area
86 has been over/under written.
91 Values which are used to set the markers which will be tested for
92 under/over write. There are 3 of these, one in the struct, one
93 immediately after the struct but before the caller requested memory and
94 one immediately after the requested memory.
96 #define MemStartCheck 0x23A8
97 #define MemMidCheck 0xA328
98 #define MemEndCheck 0x8A32
99 #define MemFillChar 0xAF
100 #define MemStructId 0x666D
103 External interface for the wxMemStruct class. Others are
104 defined inline within the class def. Here we only need to be able
105 to add and delete nodes from the list and handle errors in some way.
109 Used for internal "this shouldn't happen" type of errors.
111 void wxMemStruct::ErrorMsg (const char * mesg
)
113 wxLogDebug(T("wxWindows memory checking error: %s"), mesg
);
116 // << m_fileName << ' ' << m_lineNum << endl;
120 Used when we find an overwrite or an underwrite error.
122 void wxMemStruct::ErrorMsg ()
124 wxLogDebug(T("wxWindows over/underwrite memory error:"));
127 // cerr << m_fileName << ' ' << m_lineNum << endl;
132 We want to find out if pointers have been overwritten as soon as is
133 possible, so test everything before we dereference it. Of course it's still
134 quite possible that, if things have been overwritten, this function will
135 fall over, but the only way of dealing with that would cost too much in terms
138 int wxMemStruct::AssertList ()
140 if (wxDebugContext::GetHead () != 0 && ! (wxDebugContext::GetHead ())->AssertIt () ||
141 wxDebugContext::GetTail () != 0 && ! wxDebugContext::GetTail ()->AssertIt ()) {
142 ErrorMsg ("Head or tail pointers trashed");
150 Check that the thing we're pointing to has the correct id for a wxMemStruct
151 object and also that it's previous and next pointers are pointing at objects
152 which have valid ids.
153 This is definitely not perfect since we could fall over just trying to access
154 any of the slots which we use here, but I think it's about the best that I
155 can do without doing something like taking all new wxMemStruct pointers and
156 comparing them against all known pointer within the list and then only
157 doing this sort of check _after_ you've found the pointer in the list. That
158 would be safer, but also much more time consuming.
160 int wxMemStruct::AssertIt ()
162 return (m_id
== MemStructId
&&
163 (m_prev
== 0 || m_prev
->m_id
== MemStructId
) &&
164 (m_next
== 0 || m_next
->m_id
== MemStructId
));
169 Additions are always at the tail of the list.
170 Returns 0 on error, non-zero on success.
172 int wxMemStruct::Append ()
177 if (wxDebugContext::GetHead () == 0) {
178 if (wxDebugContext::GetTail () != 0) {
179 ErrorMsg ("Null list should have a null tail pointer");
182 (void) wxDebugContext::SetHead (this);
183 (void) wxDebugContext::SetTail (this);
185 wxDebugContext::GetTail ()->m_next
= this;
186 this->m_prev
= wxDebugContext::GetTail ();
187 (void) wxDebugContext::SetTail (this);
194 Don't actually free up anything here as the space which is used
195 by the node will be free'd up when the whole block is free'd.
196 Returns 0 on error, non-zero on success.
198 int wxMemStruct::Unlink ()
203 if (wxDebugContext::GetHead () == 0 || wxDebugContext::GetTail () == 0) {
204 ErrorMsg ("Trying to remove node from empty list");
208 // Handle the part of the list before this node.
210 if (this != wxDebugContext::GetHead ()) {
211 ErrorMsg ("No previous node for non-head node");
214 (void) wxDebugContext::SetHead (m_next
);
216 if (! m_prev
->AssertIt ()) {
217 ErrorMsg ("Trashed previous pointer");
221 if (m_prev
->m_next
!= this) {
222 ErrorMsg ("List is inconsistent");
225 m_prev
->m_next
= m_next
;
228 // Handle the part of the list after this node.
230 if (this != wxDebugContext::GetTail ()) {
231 ErrorMsg ("No next node for non-tail node");
234 (void) wxDebugContext::SetTail (m_prev
);
236 if (! m_next
->AssertIt ()) {
237 ErrorMsg ("Trashed next pointer");
241 if (m_next
->m_prev
!= this) {
242 ErrorMsg ("List is inconsistent");
245 m_next
->m_prev
= m_prev
;
254 Checks a node and block of memory to see that the markers are still
257 int wxMemStruct::CheckBlock ()
261 if (m_firstMarker
!= MemStartCheck
) {
266 char * pointer
= wxDebugContext::MidMarkerPos ((char *) this);
267 if (* (wxMarkerType
*) pointer
!= MemMidCheck
) {
272 pointer
= wxDebugContext::EndMarkerPos ((char *) this, RequestSize ());
273 if (* (wxMarkerType
*) pointer
!= MemEndCheck
) {
283 Check the list of nodes to see if they are all ok.
285 int wxMemStruct::CheckAllPrevious ()
289 for (wxMemStruct
* st
= this->m_prev
; st
!= 0; st
= st
->m_prev
) {
291 nFailures
+= st
->CheckBlock ();
301 When we delete a node we set the id slot to a specific value and then test
302 against this to see if a nodes have been deleted previously. I don't
303 just set the entire memory to the fillChar because then I'd be overwriting
304 useful stuff like the vtbl which may be needed to output the error message
305 including the file name and line numbers. Without this info the whole point
306 of this class is lost!
308 void wxMemStruct::SetDeleted ()
313 int wxMemStruct::IsDeleted ()
315 return (m_id
== MemFillChar
);
320 Print out a single node. There are many far better ways of doing this
321 but this will suffice for now.
323 void wxMemStruct::PrintNode ()
327 wxObject
*obj
= (wxObject
*)m_actualData
;
328 wxClassInfo
*info
= obj
->GetClassInfo();
330 // Let's put this in standard form so IDEs can load the file at the appropriate
335 msg
.Printf(T("%s(%d): "), m_fileName
, (int)m_lineNum
);
337 if (info
&& info
->GetClassName())
338 msg
+= info
->GetClassName();
343 msg2
.Printf(T(" at $%lX, size %d"), (long)GetActualData(), (int)RequestSize());
353 msg
.Printf(T("%s(%d): "), m_fileName
, (int)m_lineNum
);
354 msg
+= T("non-object data");
356 msg2
.Printf(T(" at $%lX, size %d\n"), (long)GetActualData(), (int)RequestSize());
363 void wxMemStruct::Dump ()
365 if (!ValidateNode()) return;
369 wxObject
*obj
= (wxObject
*)m_actualData
;
373 msg
.Printf(T("%s(%d): "), m_fileName
, (int)m_lineNum
);
376 /* TODO: We no longer have a stream (using wxLogDebug) so we can't dump it.
377 * Instead, do what wxObject::Dump does.
378 * What should we do long-term, eliminate Dumping? Or specify
379 * that MyClass::Dump should use wxLogDebug? Ugh.
380 obj->Dump(wxDebugContext::GetStream());
383 if (obj
->GetClassInfo() && obj
->GetClassInfo()->GetClassName())
384 msg
+= obj
->GetClassInfo()->GetClassName();
386 msg
+= T("unknown object class");
389 msg2
.Printf(T(" at $%lX, size %d"), (long)GetActualData(), (int)RequestSize());
398 msg
.Printf(T("%s(%d): "), m_fileName
, (int)m_lineNum
);
401 msg2
.Printf(T("non-object data at $%lX, size %d"), (long)GetActualData(), (int)RequestSize() );
409 Validate a node. Check to see that the node is "clean" in the sense
410 that nothing has over/underwritten it etc.
412 int wxMemStruct::ValidateNode ()
414 char * startPointer
= (char *) this;
417 ErrorMsg ("Object already deleted");
419 // Can't use the error routines as we have no recognisable object.
421 wxLogDebug(T("Can't verify memory struct - all bets are off!"));
429 for (i = 0; i < wxDebugContext::TotSize (requestSize ()); i++)
430 cout << startPointer [i];
433 if (Marker () != MemStartCheck
)
435 if (* (wxMarkerType
*) wxDebugContext::MidMarkerPos (startPointer
) != MemMidCheck
)
437 if (* (wxMarkerType
*) wxDebugContext::EndMarkerPos (startPointer
,
442 // Back to before the extra buffer and check that
443 // we can still read what we originally wrote.
444 if (Marker () != MemStartCheck
||
445 * (wxMarkerType
*) wxDebugContext::MidMarkerPos (startPointer
)
447 * (wxMarkerType
*) wxDebugContext::EndMarkerPos (startPointer
,
448 RequestSize ()) != MemEndCheck
)
458 The wxDebugContext class.
461 wxMemStruct
*wxDebugContext::m_head
= NULL
;
462 wxMemStruct
*wxDebugContext::m_tail
= NULL
;
463 // ostream *wxDebugContext::m_debugStream = NULL;
464 // streambuf *wxDebugContext::m_streamBuf = NULL;
466 // Must initialise these in wxEntry, and then delete them just before wxEntry exits
467 streambuf
*wxDebugContext::m_streamBuf
= NULL
;
468 ostream
*wxDebugContext::m_debugStream
= NULL
;
470 bool wxDebugContext::m_checkPrevious
= FALSE
;
471 int wxDebugContext::debugLevel
= 1;
472 bool wxDebugContext::debugOn
= TRUE
;
473 wxMemStruct
*wxDebugContext::checkPoint
= NULL
;
475 wxDebugContext::wxDebugContext(void)
477 // m_streamBuf = new wxDebugStreamBuf;
478 // m_debugStream = new ostream(m_streamBuf);
481 wxDebugContext::~wxDebugContext(void)
483 SetStream(NULL
, NULL
);
487 * It's bizarre, but with BC++ 4.5, the value of str changes
488 * between SetFile and SetStream.
491 void wxDebugContext::SetStream(ostream
*str
, streambuf
*buf
)
495 m_debugStream
->flush();
496 delete m_debugStream
;
498 m_debugStream
= NULL
;
500 // Not allowed in Watcom (~streambuf is protected).
501 // Is this trying to say something significant to us??
505 streambuf
* oldBuf
= m_streamBuf
;
514 bool wxDebugContext::SetFile(const wxString
& file
)
516 ofstream
*str
= new ofstream(file
.fn_str());
530 bool wxDebugContext::SetStandardError(void)
534 #if !defined(_WINDLL)
535 wxDebugStreamBuf
*buf
= new wxDebugStreamBuf
;
536 ostream
*stream
= new ostream(m_streamBuf
);
537 SetStream(stream
, buf
);
548 Work out the positions of the markers by creating an array of 2 markers
549 and comparing the addresses of the 2 elements. Use this number as the
550 alignment for markers.
552 size_t wxDebugContext::CalcAlignment ()
555 return (char *) &ar
[1] - (char *) &ar
[0];
559 char * wxDebugContext::StructPos (const char * buf
)
564 char * wxDebugContext::MidMarkerPos (const char * buf
)
566 return StructPos (buf
) + PaddedSize (sizeof (wxMemStruct
));
569 char * wxDebugContext::CallerMemPos (const char * buf
)
571 return MidMarkerPos (buf
) + PaddedSize (sizeof(wxMarkerType
));
575 char * wxDebugContext::EndMarkerPos (const char * buf
, const size_t size
)
577 return CallerMemPos (buf
) + PaddedSize (size
);
582 Slightly different as this takes a pointer to the start of the caller
583 requested region and returns a pointer to the start of the buffer.
585 char * wxDebugContext::StartPos (const char * caller
)
587 return ((char *) (caller
- wxDebugContext::PaddedSize (sizeof(wxMarkerType
)) -
588 wxDebugContext::PaddedSize (sizeof (wxMemStruct
))));
592 We may need padding between various parts of the allocated memory.
593 Given a size of memory, this returns the amount of memory which should
594 be allocated in order to allow for alignment of the following object.
596 I don't know how portable this stuff is, but it seems to work for me at
597 the moment. It would be real nice if I knew more about this!
599 size_t wxDebugContext::GetPadding (const size_t size
)
601 size_t pad
= size
% CalcAlignment ();
602 return (pad
) ? sizeof(wxMarkerType
) - pad
: 0;
607 size_t wxDebugContext::PaddedSize (const size_t size
)
609 return size
+ GetPadding (size
);
613 Returns the total amount of memory which we need to get from the system
614 in order to satisfy a caller request. This includes space for the struct
615 plus markers and the caller's memory as well.
617 size_t wxDebugContext::TotSize (const size_t reqSize
)
619 return (PaddedSize (sizeof (wxMemStruct
)) + PaddedSize (reqSize
) +
620 2 * sizeof(wxMarkerType
));
625 Traverse the list of nodes executing the given function on each node.
627 void wxDebugContext::TraverseList (PmSFV func
, wxMemStruct
*from
)
630 from
= wxDebugContext::GetHead ();
632 for (wxMemStruct
* st
= from
; st
!= 0; st
= st
->m_next
)
634 void* data
= st
->GetActualData();
635 // if ((data != (void*)m_debugStream) && (data != (void*) m_streamBuf))
636 if (data
!= (void*) wxLog::GetActiveTarget())
647 bool wxDebugContext::PrintList (void)
653 TraverseList ((PmSFV
)&wxMemStruct::PrintNode
, (checkPoint
? checkPoint
->m_next
: (wxMemStruct
*)NULL
));
661 bool wxDebugContext::Dump(void)
669 wxChar
* appName
= T("application");
670 wxString
appNameStr("");
673 appNameStr
= wxTheApp
->GetAppName();
674 appName
= WXSTRINGCAST appNameStr
;
675 wxLogDebug(T("----- Memory dump of %s at %s -----"), appName
, WXSTRINGCAST
wxNow() );
679 wxLogDebug( T("----- Memory dump -----") );
682 TraverseList ((PmSFV
)&wxMemStruct::Dump
, (checkPoint
? checkPoint
->m_next
: (wxMemStruct
*)NULL
));
693 struct wxDebugStatsStruct
697 wxChar
*instanceClass
;
698 wxDebugStatsStruct
*next
;
701 static wxDebugStatsStruct
*FindStatsStruct(wxDebugStatsStruct
*st
, wxChar
*name
)
705 if (wxStrcmp(st
->instanceClass
, name
) == 0)
712 static wxDebugStatsStruct
*InsertStatsStruct(wxDebugStatsStruct
*head
, wxDebugStatsStruct
*st
)
718 bool wxDebugContext::PrintStatistics(bool detailed
)
726 wxChar
* appName
= T("application");
727 wxString
appNameStr(T(""));
730 appNameStr
= wxTheApp
->GetAppName();
731 appName
= WXSTRINGCAST appNameStr
;
732 wxLogDebug(T("----- Memory statistics of %s at %s -----"), appName
, WXSTRINGCAST
wxNow() );
736 wxLogDebug( T("----- Memory statistics -----") );
740 bool currentMode
= GetDebugMode();
743 long noNonObjectNodes
= 0;
744 long noObjectNodes
= 0;
747 wxDebugStatsStruct
*list
= NULL
;
749 wxMemStruct
*from
= (checkPoint
? checkPoint
->m_next
: (wxMemStruct
*)NULL
);
751 from
= wxDebugContext::GetHead ();
754 for (st
= from
; st
!= 0; st
= st
->m_next
)
756 void* data
= st
->GetActualData();
757 // if (detailed && (data != (void*)m_debugStream) && (data != (void*) m_streamBuf))
758 if (detailed
&& (data
!= (void*) wxLog::GetActiveTarget()))
760 wxChar
*className
= T("nonobject");
761 if (st
->m_isObject
&& st
->GetActualData())
763 wxObject
*obj
= (wxObject
*)st
->GetActualData();
764 if (obj
->GetClassInfo()->GetClassName())
765 className
= obj
->GetClassInfo()->GetClassName();
767 wxDebugStatsStruct
*stats
= FindStatsStruct(list
, className
);
770 stats
= (wxDebugStatsStruct
*)malloc(sizeof(wxDebugStatsStruct
));
771 stats
->instanceClass
= className
;
772 stats
->instanceCount
= 0;
773 stats
->totalSize
= 0;
774 list
= InsertStatsStruct(list
, stats
);
776 stats
->instanceCount
++;
777 stats
->totalSize
+= st
->RequestSize();
780 // if ((data != (void*)m_debugStream) && (data != (void*) m_streamBuf))
781 if (data
!= (void*) wxLog::GetActiveTarget())
783 totalSize
+= st
->RequestSize();
795 wxLogDebug(T("%ld objects of class %s, total size %ld"),
796 list
->instanceCount
, list
->instanceClass
, list
->totalSize
);
797 wxDebugStatsStruct
*old
= list
;
804 SetDebugMode(currentMode
);
806 wxLogDebug(T("Number of object items: %ld"), noObjectNodes
);
807 wxLogDebug(T("Number of non-object items: %ld"), noNonObjectNodes
);
808 wxLogDebug(T("Total allocated size: %ld"), totalSize
);
818 bool wxDebugContext::PrintClasses(void)
825 wxChar
* appName
= T("application");
826 wxString
appNameStr(T(""));
829 appNameStr
= wxTheApp
->GetAppName();
830 appName
= WXSTRINGCAST appNameStr
;
831 wxLogDebug(T("----- Classes in %s -----"), appName
);
839 wxClassInfo::sm_classTable
->BeginFind();
840 node
= wxClassInfo::sm_classTable
->Next();
843 info
= (wxClassInfo
*)node
->Data();
844 if (info
->GetClassName())
846 wxString
msg(info
->GetClassName());
849 if (info
->GetBaseClassName1() && !info
->GetBaseClassName2())
852 msg
+= info
->GetBaseClassName1();
854 else if (info
->GetBaseClassName1() && info
->GetBaseClassName2())
857 msg
+= info
->GetBaseClassName1() ;
859 msg
+= info
->GetBaseClassName2() ;
861 if (info
->GetConstructor())
862 msg
+= T(": dynamic");
866 node
= wxClassInfo::sm_classTable
->Next();
870 wxLogDebug(T("There are %d classes derived from wxObject."), n
);
876 void wxDebugContext::SetCheckpoint(bool all
)
884 // Checks all nodes since checkpoint, or since start.
885 int wxDebugContext::Check(bool checkAll
)
889 wxMemStruct
*from
= (checkPoint
? checkPoint
->m_next
: (wxMemStruct
*)NULL
);
890 if (!from
|| checkAll
)
891 from
= wxDebugContext::GetHead ();
893 for (wxMemStruct
* st
= from
; st
!= 0; st
= st
->m_next
)
896 nFailures
+= st
->CheckBlock ();
904 // Count the number of non-wxDebugContext-related objects
905 // that are outstanding
906 int wxDebugContext::CountObjectsLeft(bool sinceCheckpoint
)
910 wxMemStruct
*from
= NULL
;
911 if (sinceCheckpoint
&& checkPoint
)
912 from
= checkPoint
->m_next
;
914 from
= wxDebugContext::GetHead () ;
916 for (wxMemStruct
* st
= from
; st
!= 0; st
= st
->m_next
)
918 void* data
= st
->GetActualData();
919 // if ((data != (void*)m_debugStream) && (data != (void*) m_streamBuf))
920 if (data
!= (void*) wxLog::GetActiveTarget())
928 The global operator new used for everything apart from getting
929 dynamic storage within this function itself.
932 // We'll only do malloc and free for the moment: leave the interesting
933 // stuff for the wxObject versions.
935 #if defined(__WXDEBUG__) && wxUSE_GLOBAL_MEMORY_OPERATORS
941 // Seems OK all of a sudden. Maybe to do with linking with multithreaded library?
942 #if 0 // def __VISUALC__
943 #define NO_DEBUG_ALLOCATION
946 // Unfortunately ~wxDebugStreamBuf doesn't work (VC++ 5) when we enable the debugging
947 // code. I have no idea why. In BC++ 4.5, we have a similar problem the debug
948 // stream myseriously changing pointer address between being passed from SetFile to SetStream.
949 // See docs/msw/issues.txt.
950 void * operator new (size_t size
, wxChar
* fileName
, int lineNum
)
952 #ifdef NO_DEBUG_ALLOCATION
955 return wxDebugAlloc(size
, fileName
, lineNum
, FALSE
, FALSE
);
959 // Added JACS 25/11/98
960 void * operator new (size_t size
)
962 #ifdef NO_DEBUG_ALLOCATION
965 return wxDebugAlloc(size
, NULL
, 0, FALSE
);
969 #if wxUSE_ARRAY_MEMORY_OPERATORS
970 void * operator new[] (size_t size
)
972 #ifdef NO_DEBUG_ALLOCATION
975 return wxDebugAlloc(size
, NULL
, 0, FALSE
, TRUE
);
980 #if wxUSE_ARRAY_MEMORY_OPERATORS
981 void * operator new[] (size_t size
, wxChar
* fileName
, int lineNum
)
983 #ifdef NO_DEBUG_ALLOCATION
986 return wxDebugAlloc(size
, fileName
, lineNum
, FALSE
, TRUE
);
991 void operator delete (void * buf
)
993 #ifdef NO_DEBUG_ALLOCATION
1001 #if defined(__VISUALC__) && (__VISUALC__ >= 1200)
1002 void operator delete(void* pData
, wxChar
* /* fileName */, int /* lineNum */)
1004 // ::operator delete(pData);
1005 // JACS 21/11/1998: surely we need to call wxDebugFree?
1006 wxDebugFree(pData
, FALSE
);
1008 // New operator 21/11/1998
1009 void operator delete[](void* pData
, char* /* fileName */, int /* lineNum */)
1011 wxDebugFree(pData
, TRUE
);
1015 #if wxUSE_ARRAY_MEMORY_OPERATORS
1017 void operator delete[] (void * buf
)
1019 #ifdef NO_DEBUG_ALLOCATION
1022 wxDebugFree(buf
, TRUE
);
1029 // TODO: store whether this is a vector or not.
1030 void * wxDebugAlloc(size_t size
, wxChar
* fileName
, int lineNum
, bool isObject
, bool WXUNUSED(isVect
) )
1032 // If not in debugging allocation mode, do the normal thing
1033 // so we don't leave any trace of ourselves in the node list.
1035 if (!wxDebugContext::GetDebugMode())
1037 return (void *)malloc(size
);
1040 int totSize
= wxDebugContext::TotSize (size
);
1041 char * buf
= (char *) malloc(totSize
);
1043 wxLogDebug(T("Call to malloc (%ld) failed."), (long)size
);
1046 wxMemStruct
* st
= (wxMemStruct
*)buf
;
1047 st
->m_firstMarker
= MemStartCheck
;
1048 st
->m_reqSize
= size
;
1049 st
->m_fileName
= fileName
;
1050 st
->m_lineNum
= lineNum
;
1051 st
->m_id
= MemStructId
;
1054 st
->m_isObject
= isObject
;
1056 // Errors from Append() shouldn't really happen - but just in case!
1057 if (st
->Append () == 0) {
1058 st
->ErrorMsg ("Trying to append new node");
1061 if (wxDebugContext::GetCheckPrevious ()) {
1062 if (st
->CheckAllPrevious () < 0) {
1063 st
->ErrorMsg ("Checking previous nodes");
1067 // Set up the extra markers at the middle and end.
1068 char * ptr
= wxDebugContext::MidMarkerPos (buf
);
1069 * (wxMarkerType
*) ptr
= MemMidCheck
;
1070 ptr
= wxDebugContext::EndMarkerPos (buf
, size
);
1071 * (wxMarkerType
*) ptr
= MemEndCheck
;
1073 // pointer returned points to the start of the caller's
1075 void *m_actualData
= (void *) wxDebugContext::CallerMemPos (buf
);
1076 st
->m_actualData
= m_actualData
;
1078 return m_actualData
;
1081 // TODO: check whether was allocated as a vector
1082 void wxDebugFree(void * buf
, bool WXUNUSED(isVect
) )
1087 // If not in debugging allocation mode, do the normal thing
1088 // so we don't leave any trace of ourselves in the node list.
1089 if (!wxDebugContext::GetDebugMode())
1095 // Points to the start of the entire allocated area.
1096 char * startPointer
= wxDebugContext::StartPos ((char *) buf
);
1097 // Find the struct and make sure that it's identifiable.
1098 wxMemStruct
* st
= (wxMemStruct
*) wxDebugContext::StructPos (startPointer
);
1100 if (! st
->ValidateNode ())
1103 // If this is the current checkpoint, we need to
1104 // move the checkpoint back so it points to a valid
1106 if (st
== wxDebugContext::checkPoint
)
1107 wxDebugContext::checkPoint
= wxDebugContext::checkPoint
->m_prev
;
1109 if (! st
->Unlink ())
1111 st
->ErrorMsg ("Unlinking deleted node");
1114 // Now put in the fill char into the id slot and the caller requested
1115 // memory locations.
1117 (void) memset (wxDebugContext::CallerMemPos (startPointer
), MemFillChar
,
1118 st
->RequestSize ());
1120 // Don't allow delayed freeing of memory in this version
1121 // if (!wxDebugContext::GetDelayFree())
1122 // free((void *)st);
1126 // Trace: send output to the current debugging stream
1127 void wxTrace(const wxChar
*fmt
...)
1130 static wxChar buffer
[512];
1135 wvsprintf(buffer
,fmt
,ap
) ;
1137 vsprintf(buffer
,fmt
,ap
) ;
1142 if (wxDebugContext::HasStream())
1144 wxDebugContext::GetStream() << buffer
;
1145 wxDebugContext::GetStream().flush();
1150 OutputDebugString((LPCTSTR
)buffer
) ;
1152 OutputDebugString((const char*) buffer
) ;
1155 fprintf(stderr
, buffer
);
1160 void wxTraceLevel(int level
, const wxChar
*fmt
...)
1162 if (wxDebugContext::GetLevel() < level
)
1166 static wxChar buffer
[512];
1171 wvsprintf(buffer
,fmt
,ap
) ;
1173 vsprintf(buffer
,fmt
,ap
) ;
1178 if (wxDebugContext::HasStream())
1180 wxDebugContext::GetStream() << buffer
;
1181 wxDebugContext::GetStream().flush();
1186 OutputDebugString((LPCTSTR
)buffer
) ;
1188 OutputDebugString((const char*) buffer
) ;
1191 fprintf(stderr
, buffer
);
1195 #else // wxUSE_MEMORY_TRACING && defined(__WXDEBUG__)
1196 void wxTrace(const char *WXUNUSED(fmt
) ...)
1200 void wxTraceLevel(int WXUNUSED(level
), const char *WXUNUSED(fmt
) ...)