]>
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"
52 #if !defined(__WATCOMC__) && !(defined(__VMS__) && ( __VMS_VER < 70000000 ) )\
53 && !defined( __MWERKS__ ) && !defined(__SALFORDC__)
73 #include "wx/memory.h"
79 // wxDebugContext wxTheDebugContext;
81 Redefine new and delete so that we can pick up situations where:
82 - we overwrite or underwrite areas of malloc'd memory.
83 - we use uninitialise variables
84 Only do this in debug mode.
86 We change new to get enough memory to allocate a struct, followed
87 by the caller's requested memory, followed by a tag. The struct
88 is used to create a doubly linked list of these areas and also
89 contains another tag. The tags are used to determine when the area
90 has been over/under written.
95 Values which are used to set the markers which will be tested for
96 under/over write. There are 3 of these, one in the struct, one
97 immediately after the struct but before the caller requested memory and
98 one immediately after the requested memory.
100 #define MemStartCheck 0x23A8
101 #define MemMidCheck 0xA328
102 #define MemEndCheck 0x8A32
103 #define MemFillChar 0xAF
104 #define MemStructId 0x666D
107 External interface for the wxMemStruct class. Others are
108 defined inline within the class def. Here we only need to be able
109 to add and delete nodes from the list and handle errors in some way.
113 Used for internal "this shouldn't happen" type of errors.
115 void wxMemStruct::ErrorMsg (const char * mesg
)
117 wxLogMessage(wxT("wxWindows memory checking error: %s"), mesg
);
120 // << m_fileName << ' ' << m_lineNum << endl;
124 Used when we find an overwrite or an underwrite error.
126 void wxMemStruct::ErrorMsg ()
128 wxLogMessage(wxT("wxWindows over/underwrite memory error:"));
131 // cerr << m_fileName << ' ' << m_lineNum << endl;
136 We want to find out if pointers have been overwritten as soon as is
137 possible, so test everything before we dereference it. Of course it's still
138 quite possible that, if things have been overwritten, this function will
139 fall over, but the only way of dealing with that would cost too much in terms
142 int wxMemStruct::AssertList ()
144 if (wxDebugContext::GetHead () != 0 && ! (wxDebugContext::GetHead ())->AssertIt () ||
145 wxDebugContext::GetTail () != 0 && ! wxDebugContext::GetTail ()->AssertIt ()) {
146 ErrorMsg ("Head or tail pointers trashed");
154 Check that the thing we're pointing to has the correct id for a wxMemStruct
155 object and also that it's previous and next pointers are pointing at objects
156 which have valid ids.
157 This is definitely not perfect since we could fall over just trying to access
158 any of the slots which we use here, but I think it's about the best that I
159 can do without doing something like taking all new wxMemStruct pointers and
160 comparing them against all known pointer within the list and then only
161 doing this sort of check _after_ you've found the pointer in the list. That
162 would be safer, but also much more time consuming.
164 int wxMemStruct::AssertIt ()
166 return (m_id
== MemStructId
&&
167 (m_prev
== 0 || m_prev
->m_id
== MemStructId
) &&
168 (m_next
== 0 || m_next
->m_id
== MemStructId
));
173 Additions are always at the tail of the list.
174 Returns 0 on error, non-zero on success.
176 int wxMemStruct::Append ()
181 if (wxDebugContext::GetHead () == 0) {
182 if (wxDebugContext::GetTail () != 0) {
183 ErrorMsg ("Null list should have a null tail pointer");
186 (void) wxDebugContext::SetHead (this);
187 (void) wxDebugContext::SetTail (this);
189 wxDebugContext::GetTail ()->m_next
= this;
190 this->m_prev
= wxDebugContext::GetTail ();
191 (void) wxDebugContext::SetTail (this);
198 Don't actually free up anything here as the space which is used
199 by the node will be free'd up when the whole block is free'd.
200 Returns 0 on error, non-zero on success.
202 int wxMemStruct::Unlink ()
207 if (wxDebugContext::GetHead () == 0 || wxDebugContext::GetTail () == 0) {
208 ErrorMsg ("Trying to remove node from empty list");
212 // Handle the part of the list before this node.
214 if (this != wxDebugContext::GetHead ()) {
215 ErrorMsg ("No previous node for non-head node");
218 (void) wxDebugContext::SetHead (m_next
);
220 if (! m_prev
->AssertIt ()) {
221 ErrorMsg ("Trashed previous pointer");
225 if (m_prev
->m_next
!= this) {
226 ErrorMsg ("List is inconsistent");
229 m_prev
->m_next
= m_next
;
232 // Handle the part of the list after this node.
234 if (this != wxDebugContext::GetTail ()) {
235 ErrorMsg ("No next node for non-tail node");
238 (void) wxDebugContext::SetTail (m_prev
);
240 if (! m_next
->AssertIt ()) {
241 ErrorMsg ("Trashed next pointer");
245 if (m_next
->m_prev
!= this) {
246 ErrorMsg ("List is inconsistent");
249 m_next
->m_prev
= m_prev
;
258 Checks a node and block of memory to see that the markers are still
261 int wxMemStruct::CheckBlock ()
265 if (m_firstMarker
!= MemStartCheck
) {
270 char * pointer
= wxDebugContext::MidMarkerPos ((char *) this);
271 if (* (wxMarkerType
*) pointer
!= MemMidCheck
) {
276 pointer
= wxDebugContext::EndMarkerPos ((char *) this, RequestSize ());
277 if (* (wxMarkerType
*) pointer
!= MemEndCheck
) {
287 Check the list of nodes to see if they are all ok.
289 int wxMemStruct::CheckAllPrevious ()
293 for (wxMemStruct
* st
= this->m_prev
; st
!= 0; st
= st
->m_prev
) {
295 nFailures
+= st
->CheckBlock ();
305 When we delete a node we set the id slot to a specific value and then test
306 against this to see if a nodes have been deleted previously. I don't
307 just set the entire memory to the fillChar because then I'd be overwriting
308 useful stuff like the vtbl which may be needed to output the error message
309 including the file name and line numbers. Without this info the whole point
310 of this class is lost!
312 void wxMemStruct::SetDeleted ()
317 int wxMemStruct::IsDeleted ()
319 return (m_id
== MemFillChar
);
324 Print out a single node. There are many far better ways of doing this
325 but this will suffice for now.
327 void wxMemStruct::PrintNode ()
331 wxObject
*obj
= (wxObject
*)m_actualData
;
332 wxClassInfo
*info
= obj
->GetClassInfo();
334 // Let's put this in standard form so IDEs can load the file at the appropriate
336 wxString
msg(wxT(""));
339 msg
.Printf(wxT("%s(%d): "), m_fileName
, (int)m_lineNum
);
341 if (info
&& info
->GetClassName())
342 msg
+= info
->GetClassName();
344 msg
+= wxT("object");
347 msg2
.Printf(wxT(" at $%lX, size %d"), (long)GetActualData(), (int)RequestSize());
357 msg
.Printf(wxT("%s(%d): "), m_fileName
, (int)m_lineNum
);
358 msg
+= wxT("non-object data");
360 msg2
.Printf(wxT(" at $%lX, size %d\n"), (long)GetActualData(), (int)RequestSize());
367 void wxMemStruct::Dump ()
369 if (!ValidateNode()) return;
373 wxObject
*obj
= (wxObject
*)m_actualData
;
375 wxString
msg(wxT(""));
377 msg
.Printf(wxT("%s(%d): "), m_fileName
, (int)m_lineNum
);
380 /* TODO: We no longer have a stream (using wxLogDebug) so we can't dump it.
381 * Instead, do what wxObject::Dump does.
382 * What should we do long-term, eliminate Dumping? Or specify
383 * that MyClass::Dump should use wxLogDebug? Ugh.
384 obj->Dump(wxDebugContext::GetStream());
387 if (obj
->GetClassInfo() && obj
->GetClassInfo()->GetClassName())
388 msg
+= obj
->GetClassInfo()->GetClassName();
390 msg
+= wxT("unknown object class");
393 msg2
.Printf(wxT(" at $%lX, size %d"), (long)GetActualData(), (int)RequestSize());
400 wxString
msg(wxT(""));
402 msg
.Printf(wxT("%s(%d): "), m_fileName
, (int)m_lineNum
);
405 msg2
.Printf(wxT("non-object data at $%lX, size %d"), (long)GetActualData(), (int)RequestSize() );
413 Validate a node. Check to see that the node is "clean" in the sense
414 that nothing has over/underwritten it etc.
416 int wxMemStruct::ValidateNode ()
418 char * startPointer
= (char *) this;
421 ErrorMsg ("Object already deleted");
423 // Can't use the error routines as we have no recognisable object.
425 wxLogMessage(wxT("Can't verify memory struct - all bets are off!"));
433 for (i = 0; i < wxDebugContext::TotSize (requestSize ()); i++)
434 cout << startPointer [i];
437 if (Marker () != MemStartCheck
)
439 if (* (wxMarkerType
*) wxDebugContext::MidMarkerPos (startPointer
) != MemMidCheck
)
441 if (* (wxMarkerType
*) wxDebugContext::EndMarkerPos (startPointer
,
446 // Back to before the extra buffer and check that
447 // we can still read what we originally wrote.
448 if (Marker () != MemStartCheck
||
449 * (wxMarkerType
*) wxDebugContext::MidMarkerPos (startPointer
)
451 * (wxMarkerType
*) wxDebugContext::EndMarkerPos (startPointer
,
452 RequestSize ()) != MemEndCheck
)
462 The wxDebugContext class.
465 wxMemStruct
*wxDebugContext::m_head
= NULL
;
466 wxMemStruct
*wxDebugContext::m_tail
= NULL
;
467 // wxSTD ostream *wxDebugContext::m_debugStream = NULL;
468 // wxSTD streambuf *wxDebugContext::m_streamBuf = NULL;
470 // Must initialise these in wxEntry, and then delete them just before wxEntry exits
473 wxSTD streambuf
*wxDebugContext::m_streamBuf
= NULL
;
474 wxSTD ostream
*wxDebugContext::m_debugStream
= NULL
;
477 bool wxDebugContext::m_checkPrevious
= FALSE
;
478 int wxDebugContext::debugLevel
= 1;
479 bool wxDebugContext::debugOn
= TRUE
;
480 wxMemStruct
*wxDebugContext::checkPoint
= NULL
;
482 // For faster alignment calculation
483 static wxMarkerType markerCalc
[2];
484 int wxDebugContext::m_balign
= (int)((char *)&markerCalc
[1] - (char*)&markerCalc
[0]);
485 int wxDebugContext::m_balignmask
= (int)((char *)&markerCalc
[1] - (char*)&markerCalc
[0]) - 1;
487 wxDebugContext::wxDebugContext(void)
489 // m_streamBuf = new wxDebugStreamBuf;
490 // m_debugStream = new wxSTD ostream(m_streamBuf);
493 wxDebugContext::~wxDebugContext(void)
495 // SetStream(NULL, NULL);
499 * It's bizarre, but with BC++ 4.5, the value of str changes
500 * between SetFile and SetStream.
505 void wxDebugContext::SetStream(wxSTD ostream
*str
, wxSTD streambuf
*buf
)
509 m_debugStream
->flush();
510 delete m_debugStream
;
512 m_debugStream
= NULL
;
514 // Not allowed in Watcom (~streambuf is protected).
515 // Is this trying to say something significant to us??
519 wxSTD streambuf
* oldBuf
= m_streamBuf
;
528 bool wxDebugContext::SetFile(const wxString
& file
)
530 wxSTD ofstream
*str
= new wxSTD
ofstream(file
.mb_str());
544 bool wxDebugContext::SetStandardError(void)
548 #if !defined(_WINDLL)
549 wxDebugStreamBuf
*buf
= new wxDebugStreamBuf
;
550 wxSTD ostream
*stream
= new wxSTD
ostream(m_streamBuf
);
551 SetStream(stream
, buf
);
563 Work out the positions of the markers by creating an array of 2 markers
564 and comparing the addresses of the 2 elements. Use this number as the
565 alignment for markers.
567 size_t wxDebugContext::CalcAlignment ()
570 return (char *) &ar
[1] - (char *) &ar
[0];
574 char * wxDebugContext::StructPos (const char * buf
)
579 char * wxDebugContext::MidMarkerPos (const char * buf
)
581 return StructPos (buf
) + PaddedSize (sizeof (wxMemStruct
));
584 char * wxDebugContext::CallerMemPos (const char * buf
)
586 return MidMarkerPos (buf
) + PaddedSize (sizeof(wxMarkerType
));
590 char * wxDebugContext::EndMarkerPos (const char * buf
, const size_t size
)
592 return CallerMemPos (buf
) + PaddedSize (size
);
597 Slightly different as this takes a pointer to the start of the caller
598 requested region and returns a pointer to the start of the buffer.
600 char * wxDebugContext::StartPos (const char * caller
)
602 return ((char *) (caller
- wxDebugContext::PaddedSize (sizeof(wxMarkerType
)) -
603 wxDebugContext::PaddedSize (sizeof (wxMemStruct
))));
607 We may need padding between various parts of the allocated memory.
608 Given a size of memory, this returns the amount of memory which should
609 be allocated in order to allow for alignment of the following object.
611 I don't know how portable this stuff is, but it seems to work for me at
612 the moment. It would be real nice if I knew more about this!
614 // Note: this function is now obsolete (along with CalcAlignment)
615 // because the calculations are done statically, for greater speed.
617 size_t wxDebugContext::GetPadding (const size_t size
)
619 size_t pad
= size
% CalcAlignment ();
620 return (pad
) ? sizeof(wxMarkerType
) - pad
: 0;
623 size_t wxDebugContext::PaddedSize (const size_t size
)
625 // Added by Terry Farnham <TJRT@pacbell.net> to replace
626 // slow GetPadding call.
629 padb
= size
& m_balignmask
;
631 return(size
+ m_balign
- padb
);
637 return size
+ GetPadding (size
);
642 Returns the total amount of memory which we need to get from the system
643 in order to satisfy a caller request. This includes space for the struct
644 plus markers and the caller's memory as well.
646 size_t wxDebugContext::TotSize (const size_t reqSize
)
648 return (PaddedSize (sizeof (wxMemStruct
)) + PaddedSize (reqSize
) +
649 2 * sizeof(wxMarkerType
));
654 Traverse the list of nodes executing the given function on each node.
656 void wxDebugContext::TraverseList (PmSFV func
, wxMemStruct
*from
)
659 from
= wxDebugContext::GetHead ();
661 wxMemStruct
* st
= NULL
;
662 for (st
= from
; st
!= 0; st
= st
->m_next
)
664 void* data
= st
->GetActualData();
665 // if ((data != (void*)m_debugStream) && (data != (void*) m_streamBuf))
666 if (data
!= (void*) wxLog::GetActiveTarget())
677 bool wxDebugContext::PrintList (void)
683 TraverseList ((PmSFV
)&wxMemStruct::PrintNode
, (checkPoint
? checkPoint
->m_next
: (wxMemStruct
*)NULL
));
691 bool wxDebugContext::Dump(void)
699 wxChar
* appName
= wxT("application");
700 wxString
appNameStr("");
703 appNameStr
= wxTheApp
->GetAppName();
704 appName
= WXSTRINGCAST appNameStr
;
705 wxLogMessage(wxT("----- Memory dump of %s at %s -----"), appName
, WXSTRINGCAST
wxNow() );
709 wxLogMessage( wxT("----- Memory dump -----") );
712 TraverseList ((PmSFV
)&wxMemStruct::Dump
, (checkPoint
? checkPoint
->m_next
: (wxMemStruct
*)NULL
));
714 wxLogMessage( wxT("") );
715 wxLogMessage( wxT("") );
724 struct wxDebugStatsStruct
728 wxChar
*instanceClass
;
729 wxDebugStatsStruct
*next
;
732 static wxDebugStatsStruct
*FindStatsStruct(wxDebugStatsStruct
*st
, wxChar
*name
)
736 if (wxStrcmp(st
->instanceClass
, name
) == 0)
743 static wxDebugStatsStruct
*InsertStatsStruct(wxDebugStatsStruct
*head
, wxDebugStatsStruct
*st
)
750 bool wxDebugContext::PrintStatistics(bool detailed
)
758 wxChar
* appName
= wxT("application");
759 wxString
appNameStr(wxT(""));
762 appNameStr
= wxTheApp
->GetAppName();
763 appName
= WXSTRINGCAST appNameStr
;
764 wxLogMessage(wxT("----- Memory statistics of %s at %s -----"), appName
, WXSTRINGCAST
wxNow() );
768 wxLogMessage( wxT("----- Memory statistics -----") );
772 bool currentMode
= GetDebugMode();
775 long noNonObjectNodes
= 0;
776 long noObjectNodes
= 0;
779 wxDebugStatsStruct
*list
= NULL
;
781 wxMemStruct
*from
= (checkPoint
? checkPoint
->m_next
: (wxMemStruct
*)NULL
);
783 from
= wxDebugContext::GetHead ();
786 for (st
= from
; st
!= 0; st
= st
->m_next
)
788 void* data
= st
->GetActualData();
789 // if (detailed && (data != (void*)m_debugStream) && (data != (void*) m_streamBuf))
790 if (detailed
&& (data
!= (void*) wxLog::GetActiveTarget()))
792 wxChar
*className
= wxT("nonobject");
793 if (st
->m_isObject
&& st
->GetActualData())
795 wxObject
*obj
= (wxObject
*)st
->GetActualData();
796 if (obj
->GetClassInfo()->GetClassName())
797 className
= (wxChar
*)obj
->GetClassInfo()->GetClassName();
799 wxDebugStatsStruct
*stats
= FindStatsStruct(list
, className
);
802 stats
= (wxDebugStatsStruct
*)malloc(sizeof(wxDebugStatsStruct
));
803 stats
->instanceClass
= className
;
804 stats
->instanceCount
= 0;
805 stats
->totalSize
= 0;
806 list
= InsertStatsStruct(list
, stats
);
808 stats
->instanceCount
++;
809 stats
->totalSize
+= st
->RequestSize();
812 // if ((data != (void*)m_debugStream) && (data != (void*) m_streamBuf))
813 if (data
!= (void*) wxLog::GetActiveTarget())
815 totalSize
+= st
->RequestSize();
827 wxLogMessage(wxT("%ld objects of class %s, total size %ld"),
828 list
->instanceCount
, list
->instanceClass
, list
->totalSize
);
829 wxDebugStatsStruct
*old
= list
;
833 wxLogMessage(wxT(""));
836 SetDebugMode(currentMode
);
838 wxLogMessage(wxT("Number of object items: %ld"), noObjectNodes
);
839 wxLogMessage(wxT("Number of non-object items: %ld"), noNonObjectNodes
);
840 wxLogMessage(wxT("Total allocated size: %ld"), totalSize
);
841 wxLogMessage(wxT(""));
842 wxLogMessage(wxT(""));
851 bool wxDebugContext::PrintClasses(void)
858 wxChar
* appName
= wxT("application");
859 wxString
appNameStr(wxT(""));
862 appNameStr
= wxTheApp
->GetAppName();
863 appName
= WXSTRINGCAST appNameStr
;
864 wxLogMessage(wxT("----- Classes in %s -----"), appName
);
872 wxClassInfo::sm_classTable
->BeginFind();
873 node
= wxClassInfo::sm_classTable
->Next();
876 info
= (wxClassInfo
*)node
->Data();
877 if (info
->GetClassName())
879 wxString
msg(info
->GetClassName());
882 if (info
->GetBaseClassName1() && !info
->GetBaseClassName2())
885 msg
+= info
->GetBaseClassName1();
887 else if (info
->GetBaseClassName1() && info
->GetBaseClassName2())
890 msg
+= info
->GetBaseClassName1() ;
892 msg
+= info
->GetBaseClassName2() ;
894 if (info
->GetConstructor())
895 msg
+= wxT(": dynamic");
899 node
= wxClassInfo::sm_classTable
->Next();
902 wxLogMessage(wxT(""));
903 wxLogMessage(wxT("There are %d classes derived from wxObject."), n
);
904 wxLogMessage(wxT(""));
905 wxLogMessage(wxT(""));
909 void wxDebugContext::SetCheckpoint(bool all
)
917 // Checks all nodes since checkpoint, or since start.
918 int wxDebugContext::Check(bool checkAll
)
922 wxMemStruct
*from
= (checkPoint
? checkPoint
->m_next
: (wxMemStruct
*)NULL
);
923 if (!from
|| checkAll
)
924 from
= wxDebugContext::GetHead ();
926 for (wxMemStruct
* st
= from
; st
!= 0; st
= st
->m_next
)
929 nFailures
+= st
->CheckBlock ();
937 // Count the number of non-wxDebugContext-related objects
938 // that are outstanding
939 int wxDebugContext::CountObjectsLeft(bool sinceCheckpoint
)
943 wxMemStruct
*from
= NULL
;
944 if (sinceCheckpoint
&& checkPoint
)
945 from
= checkPoint
->m_next
;
947 from
= wxDebugContext::GetHead () ;
949 for (wxMemStruct
* st
= from
; st
!= 0; st
= st
->m_next
)
951 void* data
= st
->GetActualData();
952 // if ((data != (void*)m_debugStream) && (data != (void*) m_streamBuf))
953 if (data
!= (void*) wxLog::GetActiveTarget())
960 // TODO: store whether this is a vector or not.
961 void * wxDebugAlloc(size_t size
, wxChar
* fileName
, int lineNum
, bool isObject
, bool WXUNUSED(isVect
) )
963 // If not in debugging allocation mode, do the normal thing
964 // so we don't leave any trace of ourselves in the node list.
966 #if defined(__VISAGECPP__) && (__IBMCPP__ < 400 || __IBMC__ < 400 )
967 // VA 3.0 still has trouble in here
968 return (void *)malloc(size
);
970 if (!wxDebugContext::GetDebugMode())
972 return (void *)malloc(size
);
975 int totSize
= wxDebugContext::TotSize (size
);
976 char * buf
= (char *) malloc(totSize
);
978 wxLogMessage(wxT("Call to malloc (%ld) failed."), (long)size
);
981 wxMemStruct
* st
= (wxMemStruct
*)buf
;
982 st
->m_firstMarker
= MemStartCheck
;
983 st
->m_reqSize
= size
;
984 st
->m_fileName
= fileName
;
985 st
->m_lineNum
= lineNum
;
986 st
->m_id
= MemStructId
;
989 st
->m_isObject
= isObject
;
991 // Errors from Append() shouldn't really happen - but just in case!
992 if (st
->Append () == 0) {
993 st
->ErrorMsg ("Trying to append new node");
996 if (wxDebugContext::GetCheckPrevious ()) {
997 if (st
->CheckAllPrevious () < 0) {
998 st
->ErrorMsg ("Checking previous nodes");
1002 // Set up the extra markers at the middle and end.
1003 char * ptr
= wxDebugContext::MidMarkerPos (buf
);
1004 * (wxMarkerType
*) ptr
= MemMidCheck
;
1005 ptr
= wxDebugContext::EndMarkerPos (buf
, size
);
1006 * (wxMarkerType
*) ptr
= MemEndCheck
;
1008 // pointer returned points to the start of the caller's
1010 void *m_actualData
= (void *) wxDebugContext::CallerMemPos (buf
);
1011 st
->m_actualData
= m_actualData
;
1013 return m_actualData
;
1016 // TODO: check whether was allocated as a vector
1017 void wxDebugFree(void * buf
, bool WXUNUSED(isVect
) )
1022 #if defined(__VISAGECPP__) && (__IBMCPP__ < 400 || __IBMC__ < 400 )
1023 // VA 3.0 still has trouble in here
1026 // If not in debugging allocation mode, do the normal thing
1027 // so we don't leave any trace of ourselves in the node list.
1028 if (!wxDebugContext::GetDebugMode())
1034 // Points to the start of the entire allocated area.
1035 char * startPointer
= wxDebugContext::StartPos ((char *) buf
);
1036 // Find the struct and make sure that it's identifiable.
1037 wxMemStruct
* st
= (wxMemStruct
*) wxDebugContext::StructPos (startPointer
);
1039 if (! st
->ValidateNode ())
1042 // If this is the current checkpoint, we need to
1043 // move the checkpoint back so it points to a valid
1045 if (st
== wxDebugContext::checkPoint
)
1046 wxDebugContext::checkPoint
= wxDebugContext::checkPoint
->m_prev
;
1048 if (! st
->Unlink ())
1050 st
->ErrorMsg ("Unlinking deleted node");
1053 // Now put in the fill char into the id slot and the caller requested
1054 // memory locations.
1056 (void) memset (wxDebugContext::CallerMemPos (startPointer
), MemFillChar
,
1057 st
->RequestSize ());
1059 // Don't allow delayed freeing of memory in this version
1060 // if (!wxDebugContext::GetDelayFree())
1061 // free((void *)st);
1065 // Trace: send output to the current debugging stream
1066 void wxTrace(const wxChar
* ...)
1069 wxFAIL_MSG(wxT("wxTrace is now obsolete. Please use wxDebugXXX instead."));
1072 static wxChar buffer
[512];
1077 wvsprintf(buffer
,fmt
,ap
) ;
1079 vsprintf(buffer
,fmt
,ap
) ;
1084 if (wxDebugContext::HasStream())
1086 wxDebugContext::GetStream() << buffer
;
1087 wxDebugContext::GetStream().flush();
1092 OutputDebugString((LPCTSTR
)buffer
) ;
1094 OutputDebugString((const char*) buffer
) ;
1097 fprintf(stderr
, buffer
);
1103 void wxTraceLevel(int, const wxChar
* ...)
1106 wxFAIL_MSG(wxT("wxTrace is now obsolete. Please use wxDebugXXX instead."));
1108 if (wxDebugContext::GetLevel() < level
)
1112 static wxChar buffer
[512];
1117 wxWvsprintf(buffer
,fmt
,ap
) ;
1119 vsprintf(buffer
,fmt
,ap
) ;
1124 if (wxDebugContext::HasStream())
1126 wxDebugContext::GetStream() << buffer
;
1127 wxDebugContext::GetStream().flush();
1132 OutputDebugString((LPCTSTR
)buffer
) ;
1134 OutputDebugString((const char*) buffer
) ;
1137 fprintf(stderr
, buffer
);
1142 #else // wxUSE_MEMORY_TRACING && defined(__WXDEBUG__)
1143 void wxTrace(const char *WXUNUSED(fmt
) ...)
1147 void wxTraceLevel(int WXUNUSED(level
), const char *WXUNUSED(fmt
) ...)