]>
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
52 #if !defined(__WATCOMC__) && !defined(__VMS__) && !defined( __MWERKS__ )
72 #include "wx/memory.h"
78 // wxDebugContext wxTheDebugContext;
80 Redefine new and delete so that we can pick up situations where:
81 - we overwrite or underwrite areas of malloc'd memory.
82 - we use uninitialise variables
83 Only do this in debug mode.
85 We change new to get enough memory to allocate a struct, followed
86 by the caller's requested memory, followed by a tag. The struct
87 is used to create a doubly linked list of these areas and also
88 contains another tag. The tags are used to determine when the area
89 has been over/under written.
94 Values which are used to set the markers which will be tested for
95 under/over write. There are 3 of these, one in the struct, one
96 immediately after the struct but before the caller requested memory and
97 one immediately after the requested memory.
99 #define MemStartCheck 0x23A8
100 #define MemMidCheck 0xA328
101 #define MemEndCheck 0x8A32
102 #define MemFillChar 0xAF
103 #define MemStructId 0x666D
106 External interface for the wxMemStruct class. Others are
107 defined inline within the class def. Here we only need to be able
108 to add and delete nodes from the list and handle errors in some way.
112 Used for internal "this shouldn't happen" type of errors.
114 void wxMemStruct::ErrorMsg (const char * mesg
)
116 wxLogDebug("wxWindows memory checking error: %s", mesg
);
119 // << m_fileName << ' ' << m_lineNum << endl;
123 Used when we find an overwrite or an underwrite error.
125 void wxMemStruct::ErrorMsg ()
127 wxLogDebug("wxWindows over/underwrite memory error:");
130 // cerr << m_fileName << ' ' << m_lineNum << endl;
135 We want to find out if pointers have been overwritten as soon as is
136 possible, so test everything before we dereference it. Of course it's still
137 quite possible that, if things have been overwritten, this function will
138 fall over, but the only way of dealing with that would cost too much in terms
141 int wxMemStruct::AssertList ()
143 if (wxDebugContext::GetHead () != 0 && ! (wxDebugContext::GetHead ())->AssertIt () ||
144 wxDebugContext::GetTail () != 0 && ! wxDebugContext::GetTail ()->AssertIt ()) {
145 ErrorMsg ("Head or tail pointers trashed");
153 Check that the thing we're pointing to has the correct id for a wxMemStruct
154 object and also that it's previous and next pointers are pointing at objects
155 which have valid ids.
156 This is definitely not perfect since we could fall over just trying to access
157 any of the slots which we use here, but I think it's about the best that I
158 can do without doing something like taking all new wxMemStruct pointers and
159 comparing them against all known pointer within the list and then only
160 doing this sort of check _after_ you've found the pointer in the list. That
161 would be safer, but also much more time consuming.
163 int wxMemStruct::AssertIt ()
165 return (m_id
== MemStructId
&&
166 (m_prev
== 0 || m_prev
->m_id
== MemStructId
) &&
167 (m_next
== 0 || m_next
->m_id
== MemStructId
));
172 Additions are always at the tail of the list.
173 Returns 0 on error, non-zero on success.
175 int wxMemStruct::Append ()
180 if (wxDebugContext::GetHead () == 0) {
181 if (wxDebugContext::GetTail () != 0) {
182 ErrorMsg ("Null list should have a null tail pointer");
185 (void) wxDebugContext::SetHead (this);
186 (void) wxDebugContext::SetTail (this);
188 wxDebugContext::GetTail ()->m_next
= this;
189 this->m_prev
= wxDebugContext::GetTail ();
190 (void) wxDebugContext::SetTail (this);
197 Don't actually free up anything here as the space which is used
198 by the node will be free'd up when the whole block is free'd.
199 Returns 0 on error, non-zero on success.
201 int wxMemStruct::Unlink ()
206 if (wxDebugContext::GetHead () == 0 || wxDebugContext::GetTail () == 0) {
207 ErrorMsg ("Trying to remove node from empty list");
211 // Handle the part of the list before this node.
213 if (this != wxDebugContext::GetHead ()) {
214 ErrorMsg ("No previous node for non-head node");
217 (void) wxDebugContext::SetHead (m_next
);
219 if (! m_prev
->AssertIt ()) {
220 ErrorMsg ("Trashed previous pointer");
224 if (m_prev
->m_next
!= this) {
225 ErrorMsg ("List is inconsistent");
228 m_prev
->m_next
= m_next
;
231 // Handle the part of the list after this node.
233 if (this != wxDebugContext::GetTail ()) {
234 ErrorMsg ("No next node for non-tail node");
237 (void) wxDebugContext::SetTail (m_prev
);
239 if (! m_next
->AssertIt ()) {
240 ErrorMsg ("Trashed next pointer");
244 if (m_next
->m_prev
!= this) {
245 ErrorMsg ("List is inconsistent");
248 m_next
->m_prev
= m_prev
;
257 Checks a node and block of memory to see that the markers are still
260 int wxMemStruct::CheckBlock ()
264 if (m_firstMarker
!= MemStartCheck
) {
269 char * pointer
= wxDebugContext::MidMarkerPos ((char *) this);
270 if (* (wxMarkerType
*) pointer
!= MemMidCheck
) {
275 pointer
= wxDebugContext::EndMarkerPos ((char *) this, RequestSize ());
276 if (* (wxMarkerType
*) pointer
!= MemEndCheck
) {
286 Check the list of nodes to see if they are all ok.
288 int wxMemStruct::CheckAllPrevious ()
292 for (wxMemStruct
* st
= this->m_prev
; st
!= 0; st
= st
->m_prev
) {
294 nFailures
+= st
->CheckBlock ();
304 When we delete a node we set the id slot to a specific value and then test
305 against this to see if a nodes have been deleted previously. I don't
306 just set the entire memory to the fillChar because then I'd be overwriting
307 useful stuff like the vtbl which may be needed to output the error message
308 including the file name and line numbers. Without this info the whole point
309 of this class is lost!
311 void wxMemStruct::SetDeleted ()
316 int wxMemStruct::IsDeleted ()
318 return (m_id
== MemFillChar
);
323 Print out a single node. There are many far better ways of doing this
324 but this will suffice for now.
326 void wxMemStruct::PrintNode ()
330 wxObject
*obj
= (wxObject
*)m_actualData
;
331 wxClassInfo
*info
= obj
->GetClassInfo();
333 // Let's put this in standard form so IDEs can load the file at the appropriate
338 msg
.Printf("%s(%d): ", m_fileName
, (int)m_lineNum
);
340 if (info
&& info
->GetClassName())
341 msg
+= info
->GetClassName();
346 msg2
.Printf(" at $%lX, size %d", (long)GetActualData(), (int)RequestSize());
356 msg
.Printf("%s(%d): ", m_fileName
, (int)m_lineNum
);
357 msg
+= ("non-object data");
359 msg2
.Printf(" at $%lX, size %d\n", (long)GetActualData(), (int)RequestSize());
366 void wxMemStruct::Dump ()
368 if (!ValidateNode()) return;
372 wxObject
*obj
= (wxObject
*)m_actualData
;
376 msg
.Printf("%s(%d): ", m_fileName
, (int)m_lineNum
);
379 /* TODO: We no longer have a stream (using wxLogDebug) so we can't dump it.
380 * Instead, do what wxObject::Dump does.
381 * What should we do long-term, eliminate Dumping? Or specify
382 * that MyClass::Dump should use wxLogDebug? Ugh.
383 obj->Dump(wxDebugContext::GetStream());
386 if (obj
->GetClassInfo() && obj
->GetClassInfo()->GetClassName())
387 msg
+= obj
->GetClassInfo()->GetClassName();
389 msg
+= "unknown object class";
392 msg2
.Printf(" at $%lX, size %d", (long)GetActualData(), (int)RequestSize());
401 msg
.Printf("%s(%d): ", m_fileName
, (int)m_lineNum
);
404 msg2
.Printf("non-object data at $%lX, size %d", (long)GetActualData(), (int)RequestSize() );
412 Validate a node. Check to see that the node is "clean" in the sense
413 that nothing has over/underwritten it etc.
415 int wxMemStruct::ValidateNode ()
417 char * startPointer
= (char *) this;
420 ErrorMsg ("Object already deleted");
422 // Can't use the error routines as we have no recognisable object.
424 wxLogDebug("Can't verify memory struct - all bets are off!");
432 for (i = 0; i < wxDebugContext::TotSize (requestSize ()); i++)
433 cout << startPointer [i];
436 if (Marker () != MemStartCheck
)
438 if (* (wxMarkerType
*) wxDebugContext::MidMarkerPos (startPointer
) != MemMidCheck
)
440 if (* (wxMarkerType
*) wxDebugContext::EndMarkerPos (startPointer
,
445 // Back to before the extra buffer and check that
446 // we can still read what we originally wrote.
447 if (Marker () != MemStartCheck
||
448 * (wxMarkerType
*) wxDebugContext::MidMarkerPos (startPointer
)
450 * (wxMarkerType
*) wxDebugContext::EndMarkerPos (startPointer
,
451 RequestSize ()) != MemEndCheck
)
461 The wxDebugContext class.
464 wxMemStruct
*wxDebugContext::m_head
= NULL
;
465 wxMemStruct
*wxDebugContext::m_tail
= NULL
;
466 // ostream *wxDebugContext::m_debugStream = NULL;
467 // streambuf *wxDebugContext::m_streamBuf = NULL;
469 // Must initialise these in wxEntry, and then delete them just before wxEntry exits
470 streambuf
*wxDebugContext::m_streamBuf
= NULL
;
471 ostream
*wxDebugContext::m_debugStream
= NULL
;
473 bool wxDebugContext::m_checkPrevious
= FALSE
;
474 int wxDebugContext::debugLevel
= 1;
475 bool wxDebugContext::debugOn
= TRUE
;
476 wxMemStruct
*wxDebugContext::checkPoint
= NULL
;
478 wxDebugContext::wxDebugContext(void)
480 // m_streamBuf = new wxDebugStreamBuf;
481 // m_debugStream = new ostream(m_streamBuf);
484 wxDebugContext::~wxDebugContext(void)
486 SetStream(NULL
, NULL
);
490 * It's bizarre, but with BC++ 4.5, the value of str changes
491 * between SetFile and SetStream.
494 void wxDebugContext::SetStream(ostream
*str
, streambuf
*buf
)
498 m_debugStream
->flush();
499 delete m_debugStream
;
501 m_debugStream
= NULL
;
503 // Not allowed in Watcom (~streambuf is protected).
504 // Is this trying to say something significant to us??
508 streambuf
* oldBuf
= m_streamBuf
;
517 bool wxDebugContext::SetFile(const wxString
& file
)
519 ofstream
*str
= new ofstream((char *) (const char *)file
);
533 bool wxDebugContext::SetStandardError(void)
537 #if !defined(_WINDLL)
538 wxDebugStreamBuf
*buf
= new wxDebugStreamBuf
;
539 ostream
*stream
= new ostream(m_streamBuf
);
540 SetStream(stream
, buf
);
551 Work out the positions of the markers by creating an array of 2 markers
552 and comparing the addresses of the 2 elements. Use this number as the
553 alignment for markers.
555 size_t wxDebugContext::CalcAlignment ()
558 return (char *) &ar
[1] - (char *) &ar
[0];
562 char * wxDebugContext::StructPos (const char * buf
)
567 char * wxDebugContext::MidMarkerPos (const char * buf
)
569 return StructPos (buf
) + PaddedSize (sizeof (wxMemStruct
));
572 char * wxDebugContext::CallerMemPos (const char * buf
)
574 return MidMarkerPos (buf
) + PaddedSize (sizeof(wxMarkerType
));
578 char * wxDebugContext::EndMarkerPos (const char * buf
, const size_t size
)
580 return CallerMemPos (buf
) + PaddedSize (size
);
585 Slightly different as this takes a pointer to the start of the caller
586 requested region and returns a pointer to the start of the buffer.
588 char * wxDebugContext::StartPos (const char * caller
)
590 return ((char *) (caller
- wxDebugContext::PaddedSize (sizeof(wxMarkerType
)) -
591 wxDebugContext::PaddedSize (sizeof (wxMemStruct
))));
595 We may need padding between various parts of the allocated memory.
596 Given a size of memory, this returns the amount of memory which should
597 be allocated in order to allow for alignment of the following object.
599 I don't know how portable this stuff is, but it seems to work for me at
600 the moment. It would be real nice if I knew more about this!
602 size_t wxDebugContext::GetPadding (const size_t size
)
604 size_t pad
= size
% CalcAlignment ();
605 return (pad
) ? sizeof(wxMarkerType
) - pad
: 0;
610 size_t wxDebugContext::PaddedSize (const size_t size
)
612 return size
+ GetPadding (size
);
616 Returns the total amount of memory which we need to get from the system
617 in order to satisfy a caller request. This includes space for the struct
618 plus markers and the caller's memory as well.
620 size_t wxDebugContext::TotSize (const size_t reqSize
)
622 return (PaddedSize (sizeof (wxMemStruct
)) + PaddedSize (reqSize
) +
623 2 * sizeof(wxMarkerType
));
628 Traverse the list of nodes executing the given function on each node.
630 void wxDebugContext::TraverseList (PmSFV func
, wxMemStruct
*from
)
633 from
= wxDebugContext::GetHead ();
635 for (wxMemStruct
* st
= from
; st
!= 0; st
= st
->m_next
)
637 void* data
= st
->GetActualData();
638 // if ((data != (void*)m_debugStream) && (data != (void*) m_streamBuf))
639 if (data
!= (void*) wxLog::GetActiveTarget())
650 bool wxDebugContext::PrintList (void)
656 TraverseList ((PmSFV
)&wxMemStruct::PrintNode
, (checkPoint
? checkPoint
->m_next
: (wxMemStruct
*)NULL
));
664 bool wxDebugContext::Dump(void)
672 char* appName
= "application";
673 wxString
appNameStr("");
676 appNameStr
= wxTheApp
->GetAppName();
677 appName
= (char*) (const char*) appNameStr
;
678 wxLogDebug("----- Memory dump of %s at %s -----", appName
, WXSTRINGCAST
wxNow() );
682 wxLogDebug( "----- Memory dump -----" );
685 TraverseList ((PmSFV
)&wxMemStruct::Dump
, (checkPoint
? checkPoint
->m_next
: (wxMemStruct
*)NULL
));
696 struct wxDebugStatsStruct
701 wxDebugStatsStruct
*next
;
704 static wxDebugStatsStruct
*FindStatsStruct(wxDebugStatsStruct
*st
, char *name
)
708 if (strcmp(st
->instanceClass
, name
) == 0)
715 static wxDebugStatsStruct
*InsertStatsStruct(wxDebugStatsStruct
*head
, wxDebugStatsStruct
*st
)
721 bool wxDebugContext::PrintStatistics(bool detailed
)
729 char* appName
= "application";
730 wxString
appNameStr("");
733 appNameStr
= wxTheApp
->GetAppName();
734 appName
= (char*) (const char*) appNameStr
;
735 wxLogDebug("----- Memory statistics of %s at %s -----", appName
, WXSTRINGCAST
wxNow() );
739 wxLogDebug( "----- Memory statistics -----" );
743 bool currentMode
= GetDebugMode();
746 long noNonObjectNodes
= 0;
747 long noObjectNodes
= 0;
750 wxDebugStatsStruct
*list
= NULL
;
752 wxMemStruct
*from
= (checkPoint
? checkPoint
->m_next
: (wxMemStruct
*)NULL
);
754 from
= wxDebugContext::GetHead ();
757 for (st
= from
; st
!= 0; st
= st
->m_next
)
759 void* data
= st
->GetActualData();
760 // if (detailed && (data != (void*)m_debugStream) && (data != (void*) m_streamBuf))
761 if (detailed
&& (data
!= (void*) wxLog::GetActiveTarget()))
763 char *className
= "nonobject";
764 if (st
->m_isObject
&& st
->GetActualData())
766 wxObject
*obj
= (wxObject
*)st
->GetActualData();
767 if (obj
->GetClassInfo()->GetClassName())
768 className
= obj
->GetClassInfo()->GetClassName();
770 wxDebugStatsStruct
*stats
= FindStatsStruct(list
, className
);
773 stats
= (wxDebugStatsStruct
*)malloc(sizeof(wxDebugStatsStruct
));
774 stats
->instanceClass
= className
;
775 stats
->instanceCount
= 0;
776 stats
->totalSize
= 0;
777 list
= InsertStatsStruct(list
, stats
);
779 stats
->instanceCount
++;
780 stats
->totalSize
+= st
->RequestSize();
783 // if ((data != (void*)m_debugStream) && (data != (void*) m_streamBuf))
784 if (data
!= (void*) wxLog::GetActiveTarget())
786 totalSize
+= st
->RequestSize();
798 wxLogDebug("%ld objects of class %s, total size %ld",
799 list
->instanceCount
, list
->instanceClass
, list
->totalSize
);
800 wxDebugStatsStruct
*old
= list
;
807 SetDebugMode(currentMode
);
809 wxLogDebug("Number of object items: %ld", noObjectNodes
);
810 wxLogDebug("Number of non-object items: %ld", noNonObjectNodes
);
811 wxLogDebug("Total allocated size: %ld", totalSize
);
821 bool wxDebugContext::PrintClasses(void)
828 char* appName
= "application";
829 wxString
appNameStr("");
832 appNameStr
= wxTheApp
->GetAppName();
833 appName
= (char*) (const char*) appNameStr
;
834 wxLogDebug("----- Classes in %s -----", appName
);
842 wxClassInfo::sm_classTable
->BeginFind();
843 node
= wxClassInfo::sm_classTable
->Next();
846 info
= (wxClassInfo
*)node
->Data();
847 if (info
->GetClassName())
849 wxString
msg(info
->GetClassName());
852 if (info
->GetBaseClassName1() && !info
->GetBaseClassName2())
855 msg
+= info
->GetBaseClassName1();
857 else if (info
->GetBaseClassName1() && info
->GetBaseClassName2())
860 msg
+= info
->GetBaseClassName1() ;
862 msg
+= info
->GetBaseClassName2() ;
864 if (info
->GetConstructor())
869 node
= wxClassInfo::sm_classTable
->Next();
873 wxLogDebug("There are %d classes derived from wxObject.", n
);
879 void wxDebugContext::SetCheckpoint(bool all
)
887 // Checks all nodes since checkpoint, or since start.
888 int wxDebugContext::Check(bool checkAll
)
892 wxMemStruct
*from
= (checkPoint
? checkPoint
->m_next
: (wxMemStruct
*)NULL
);
893 if (!from
|| checkAll
)
894 from
= wxDebugContext::GetHead ();
896 for (wxMemStruct
* st
= from
; st
!= 0; st
= st
->m_next
)
899 nFailures
+= st
->CheckBlock ();
907 // Count the number of non-wxDebugContext-related objects
908 // that are outstanding
909 int wxDebugContext::CountObjectsLeft(bool sinceCheckpoint
)
913 wxMemStruct
*from
= NULL
;
914 if (sinceCheckpoint
&& checkPoint
)
915 from
= checkPoint
->m_next
;
917 from
= wxDebugContext::GetHead () ;
919 for (wxMemStruct
* st
= from
; st
!= 0; st
= st
->m_next
)
921 void* data
= st
->GetActualData();
922 // if ((data != (void*)m_debugStream) && (data != (void*) m_streamBuf))
923 if (data
!= (void*) wxLog::GetActiveTarget())
931 The global operator new used for everything apart from getting
932 dynamic storage within this function itself.
935 // We'll only do malloc and free for the moment: leave the interesting
936 // stuff for the wxObject versions.
938 #if defined(__WXDEBUG__) && wxUSE_GLOBAL_MEMORY_OPERATORS
944 // Seems OK all of a sudden. Maybe to do with linking with multithreaded library?
945 #if 0 // def _MSC_VER
946 #define NO_DEBUG_ALLOCATION
949 // Unfortunately ~wxDebugStreamBuf doesn't work (VC++ 5) when we enable the debugging
950 // code. I have no idea why. In BC++ 4.5, we have a similar problem the debug
951 // stream myseriously changing pointer address between being passed from SetFile to SetStream.
952 // See docs/msw/issues.txt.
953 void * operator new (size_t size
, char * fileName
, int lineNum
)
955 #ifdef NO_DEBUG_ALLOCATION
958 return wxDebugAlloc(size
, fileName
, lineNum
, FALSE
, FALSE
);
962 // Added JACS 25/11/98
963 void * operator new (size_t size
)
965 #ifdef NO_DEBUG_ALLOCATION
968 return wxDebugAlloc(size
, NULL
, 0, FALSE
);
972 #if wxUSE_ARRAY_MEMORY_OPERATORS
973 void * operator new[] (size_t size
)
975 #ifdef NO_DEBUG_ALLOCATION
978 return wxDebugAlloc(size
, NULL
, 0, FALSE
, TRUE
);
983 #if wxUSE_ARRAY_MEMORY_OPERATORS
984 void * operator new[] (size_t size
, char * fileName
, int lineNum
)
986 #ifdef NO_DEBUG_ALLOCATION
989 return wxDebugAlloc(size
, fileName
, lineNum
, FALSE
, TRUE
);
994 void operator delete (void * buf
)
996 #ifdef NO_DEBUG_ALLOCATION
1004 #if _MSC_VER >= 1200
1005 void operator delete(void* pData
, char* /* 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
, char * 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("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 char *fmt
...)
1133 static char buffer
[512];
1138 wvsprintf(buffer
,fmt
,ap
) ;
1140 vsprintf(buffer
,fmt
,ap
) ;
1145 if (wxDebugContext::HasStream())
1147 wxDebugContext::GetStream() << buffer
;
1148 wxDebugContext::GetStream().flush();
1152 OutputDebugString((LPCSTR
)buffer
) ;
1154 fprintf(stderr
, buffer
);
1159 void wxTraceLevel(int level
, const char *fmt
...)
1161 if (wxDebugContext::GetLevel() < level
)
1165 static char buffer
[512];
1170 wvsprintf(buffer
,fmt
,ap
) ;
1172 vsprintf(buffer
,fmt
,ap
) ;
1177 if (wxDebugContext::HasStream())
1179 wxDebugContext::GetStream() << buffer
;
1180 wxDebugContext::GetStream().flush();
1184 OutputDebugString((LPCSTR
)buffer
) ;
1186 fprintf(stderr
, buffer
);
1190 #else // wxUSE_MEMORY_TRACING && defined(__WXDEBUG__)
1191 void wxTrace(const char *WXUNUSED(fmt
) ...)
1195 void wxTraceLevel(int WXUNUSED(level
), const char *WXUNUSED(fmt
) ...)