]>
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 (DEBUG && USE_MEMORY_TRACING) || USE_DEBUG_CONTEXT
30 // #pragma implementation
47 #if !defined(__WATCOMC__) && !defined(__VMS__)
67 #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 wxTrace("wxWindows memory checking error: %s\n", mesg
);
116 // << m_fileName << ' ' << m_lineNum << endl;
120 Used when we find an overwrite or an underwrite error.
122 void wxMemStruct::ErrorMsg ()
124 wxTrace("wxWindows over/underwrite memory error: \n");
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 if (info
&& info
->GetClassName())
331 wxTrace("%s", info
->GetClassName());
336 wxTrace(" (%s %d)", m_fileName
, (int)m_lineNum
);
338 wxTrace(" at $%lX, size %d\n", (long)GetActualData(), (int)RequestSize());
342 wxTrace("Non-object data");
344 wxTrace(" (%s %d)", m_fileName
, (int)m_lineNum
);
345 wxTrace(" at $%lX, size %d\n", (long)GetActualData(), (int)RequestSize());
349 void wxMemStruct::Dump ()
351 if (!ValidateNode()) return;
355 wxObject
*obj
= (wxObject
*)m_actualData
;
356 // wxClassInfo *info = obj->GetClassInfo();
359 wxTrace("Item (%s %d)", m_fileName
, (int)m_lineNum
);
363 wxTrace(" at $%lX, size %d: ", (long)GetActualData(), (int)RequestSize());
364 // wxTrace(info->GetClassName());
365 obj
->Dump(wxDebugContext::GetStream());
370 wxTrace("Non-object data");
372 wxTrace(" (%s %d)", m_fileName
, (int)m_lineNum
);
373 wxTrace(" at $%lX, size %d\n", (long)GetActualData(), (int)RequestSize());
379 Validate a node. Check to see that the node is "clean" in the sense
380 that nothing has over/underwritten it etc.
382 int wxMemStruct::ValidateNode ()
384 char * startPointer
= (char *) this;
387 ErrorMsg ("Object already deleted");
389 // Can't use the error routines as we have no recognisable object.
390 wxTrace("Can't verify memory struct - all bets are off!\n");
397 for (i = 0; i < wxDebugContext::TotSize (requestSize ()); i++)
398 cout << startPointer [i];
401 if (Marker () != MemStartCheck
)
403 if (* (wxMarkerType
*) wxDebugContext::MidMarkerPos (startPointer
) != MemMidCheck
)
405 if (* (wxMarkerType
*) wxDebugContext::EndMarkerPos (startPointer
,
410 // Back to before the extra buffer and check that
411 // we can still read what we originally wrote.
412 if (Marker () != MemStartCheck
||
413 * (wxMarkerType
*) wxDebugContext::MidMarkerPos (startPointer
)
415 * (wxMarkerType
*) wxDebugContext::EndMarkerPos (startPointer
,
416 RequestSize ()) != MemEndCheck
)
426 The wxDebugContext class.
429 wxMemStruct
*wxDebugContext::m_head
= NULL
;
430 wxMemStruct
*wxDebugContext::m_tail
= NULL
;
431 // ostream *wxDebugContext::m_debugStream = NULL;
432 // streambuf *wxDebugContext::m_streamBuf = NULL;
434 // Must initialise these in wxEntry, and then delete them just before wxEntry exits
435 streambuf
*wxDebugContext::m_streamBuf
= NULL
;
436 ostream
*wxDebugContext::m_debugStream
= NULL
;
438 bool wxDebugContext::m_checkPrevious
= FALSE
;
439 int wxDebugContext::debugLevel
= 1;
440 bool wxDebugContext::debugOn
= TRUE
;
441 wxMemStruct
*wxDebugContext::checkPoint
= NULL
;
443 wxDebugContext::wxDebugContext(void)
445 // m_streamBuf = new wxDebugStreamBuf;
446 // m_debugStream = new ostream(m_streamBuf);
449 wxDebugContext::~wxDebugContext(void)
451 SetStream(NULL
, NULL
);
455 * It's bizarre, but with BC++ 4.5, the value of str changes
456 * between SetFile and SetStream.
459 void wxDebugContext::SetStream(ostream
*str
, streambuf
*buf
)
465 sprintf(buff, "SetStream (1): str is %ld", (long) str);
466 MessageBox(NULL, buff, "Memory", MB_OK);
472 m_debugStream
->flush();
473 delete m_debugStream
;
475 m_debugStream
= NULL
;
477 // Not allowed in Watcom (~streambuf is protected).
478 // Is this trying to say something significant to us??
482 streambuf
* oldBuf
= m_streamBuf
;
491 bool wxDebugContext::SetFile(const wxString
& file
)
493 ofstream
*str
= new ofstream((char *) (const char *)file
);
504 sprintf(buf, "SetFile: str is %ld", (long) str);
505 MessageBox(NULL, buf, "Memory", MB_OK);
512 bool wxDebugContext::SetStandardError(void)
514 #if !defined(_WINDLL)
515 wxDebugStreamBuf
*buf
= new wxDebugStreamBuf
;
516 ostream
*stream
= new ostream(m_streamBuf
);
517 SetStream(stream
, buf
);
526 Work out the positions of the markers by creating an array of 2 markers
527 and comparing the addresses of the 2 elements. Use this number as the
528 alignment for markers.
530 size_t wxDebugContext::CalcAlignment ()
533 return (char *) &ar
[1] - (char *) &ar
[0];
537 char * wxDebugContext::StructPos (const char * buf
)
542 char * wxDebugContext::MidMarkerPos (const char * buf
)
544 return StructPos (buf
) + PaddedSize (sizeof (wxMemStruct
));
547 char * wxDebugContext::CallerMemPos (const char * buf
)
549 return MidMarkerPos (buf
) + PaddedSize (sizeof(wxMarkerType
));
553 char * wxDebugContext::EndMarkerPos (const char * buf
, const size_t size
)
555 return CallerMemPos (buf
) + PaddedSize (size
);
560 Slightly different as this takes a pointer to the start of the caller
561 requested region and returns a pointer to the start of the buffer.
563 char * wxDebugContext::StartPos (const char * caller
)
565 return ((char *) (caller
- wxDebugContext::PaddedSize (sizeof(wxMarkerType
)) -
566 wxDebugContext::PaddedSize (sizeof (wxMemStruct
))));
570 We may need padding between various parts of the allocated memory.
571 Given a size of memory, this returns the amount of memory which should
572 be allocated in order to allow for alignment of the following object.
574 I don't know how portable this stuff is, but it seems to work for me at
575 the moment. It would be real nice if I knew more about this!
577 size_t wxDebugContext::GetPadding (const size_t size
)
579 size_t pad
= size
% CalcAlignment ();
580 return (pad
) ? sizeof(wxMarkerType
) - pad
: 0;
585 size_t wxDebugContext::PaddedSize (const size_t size
)
587 return size
+ GetPadding (size
);
591 Returns the total amount of memory which we need to get from the system
592 in order to satisfy a caller request. This includes space for the struct
593 plus markers and the caller's memory as well.
595 size_t wxDebugContext::TotSize (const size_t reqSize
)
597 return (PaddedSize (sizeof (wxMemStruct
)) + PaddedSize (reqSize
) +
598 2 * sizeof(wxMarkerType
));
603 Traverse the list of nodes executing the given function on each node.
605 void wxDebugContext::TraverseList (PmSFV func
, wxMemStruct
*from
)
608 from
= wxDebugContext::GetHead ();
610 for (wxMemStruct
* st
= from
; st
!= 0; st
= st
->m_next
)
612 void* data
= st
->GetActualData();
613 if ((data
!= (void*)m_debugStream
) && (data
!= (void*) m_streamBuf
))
624 bool wxDebugContext::PrintList (void)
630 TraverseList ((PmSFV
)&wxMemStruct::PrintNode
, (checkPoint
? checkPoint
->m_next
: NULL
));
638 bool wxDebugContext::Dump(void)
646 char* appName
= "application";
647 wxString
appNameStr("");
650 appNameStr
= wxTheApp
->GetAppName();
651 appName
= (char*) (const char*) appNameStr
;
652 wxTrace("Memory dump of %s at %s:\n", appName
, wxNow());
655 TraverseList ((PmSFV
)&wxMemStruct::Dump
, (checkPoint
? checkPoint
->m_next
: NULL
));
663 struct wxDebugStatsStruct
668 wxDebugStatsStruct
*next
;
671 static wxDebugStatsStruct
*FindStatsStruct(wxDebugStatsStruct
*st
, char *name
)
675 if (strcmp(st
->instanceClass
, name
) == 0)
682 static wxDebugStatsStruct
*InsertStatsStruct(wxDebugStatsStruct
*head
, wxDebugStatsStruct
*st
)
688 bool wxDebugContext::PrintStatistics(bool detailed
)
694 bool currentMode
= GetDebugMode();
697 long noNonObjectNodes
= 0;
698 long noObjectNodes
= 0;
701 wxDebugStatsStruct
*list
= NULL
;
703 wxMemStruct
*from
= (checkPoint
? checkPoint
->m_next
: NULL
);
705 from
= wxDebugContext::GetHead ();
708 for (st
= from
; st
!= 0; st
= st
->m_next
)
710 void* data
= st
->GetActualData();
711 if (detailed
&& (data
!= (void*)m_debugStream
) && (data
!= (void*) m_streamBuf
))
713 char *className
= "nonobject";
714 if (st
->m_isObject
&& st
->GetActualData())
716 wxObject
*obj
= (wxObject
*)st
->GetActualData();
717 if (obj
->GetClassInfo()->GetClassName())
718 className
= obj
->GetClassInfo()->GetClassName();
720 wxDebugStatsStruct
*stats
= FindStatsStruct(list
, className
);
723 stats
= (wxDebugStatsStruct
*)malloc(sizeof(wxDebugStatsStruct
));
724 stats
->instanceClass
= className
;
725 stats
->instanceCount
= 0;
726 stats
->totalSize
= 0;
727 list
= InsertStatsStruct(list
, stats
);
729 stats
->instanceCount
++;
730 stats
->totalSize
+= st
->RequestSize();
733 if ((data
!= (void*)m_debugStream
) && (data
!= (void*) m_streamBuf
))
735 totalSize
+= st
->RequestSize();
747 wxTrace("%ld objects of class %s, total size %ld\n",
748 list
->instanceCount
, list
->instanceClass
, list
->totalSize
);
749 wxDebugStatsStruct
*old
= list
;
756 SetDebugMode(currentMode
);
758 wxTrace("Number of object items: %ld\n", noObjectNodes
);
759 wxTrace("Number of non-object items: %ld\n", noNonObjectNodes
);
760 wxTrace("Total allocated size: %ld\n", totalSize
);
768 bool wxDebugContext::PrintClasses(void)
775 char* appName
= "application";
776 wxString
appNameStr("");
779 appNameStr
= wxTheApp
->GetAppName();
780 appName
= (char*) (const char*) appNameStr
;
781 wxTrace("Classes in %s:\n\n", appName
);
786 wxClassInfo
*info
= wxClassInfo::first
;
789 if (info
->GetClassName())
791 wxTrace("%s ", info
->GetClassName());
793 if (info
->GetBaseClassName1() && !info
->GetBaseClassName2())
794 wxTrace("is a %s", info
->GetBaseClassName1());
795 else if (info
->GetBaseClassName1() && info
->GetBaseClassName2())
796 wxTrace("is a %s, %s", info
->GetBaseClassName1(), info
->GetBaseClassName2());
797 if (info
->objectConstructor
)
798 wxTrace(": dynamic\n");
805 wxTrace("\nThere are %d classes derived from wxObject.\n", n
);
809 void wxDebugContext::SetCheckpoint(bool all
)
817 // Checks all nodes since checkpoint, or since start.
818 int wxDebugContext::Check(bool checkAll
)
822 wxMemStruct
*from
= (checkPoint
? checkPoint
->m_next
: NULL
);
823 if (!from
|| checkAll
)
824 from
= wxDebugContext::GetHead ();
826 for (wxMemStruct
* st
= from
; st
!= 0; st
= st
->m_next
)
829 nFailures
+= st
->CheckBlock ();
837 // Count the number of non-wxDebugContext-related objects
838 // that are outstanding
839 int wxDebugContext::CountObjectsLeft(void)
843 wxMemStruct
*from
= wxDebugContext::GetHead ();
845 for (wxMemStruct
* st
= from
; st
!= 0; st
= st
->m_next
)
847 void* data
= st
->GetActualData();
848 if ((data
!= (void*)m_debugStream
) && (data
!= (void*) m_streamBuf
))
856 The global operator new used for everything apart from getting
857 dynamic storage within this function itself.
860 // We'll only do malloc and free for the moment: leave the interesting
861 // stuff for the wxObject versions.
863 #if DEBUG && USE_GLOBAL_MEMORY_OPERATORS
869 // Seems OK all of a sudden. Maybe to do with linking with multithreaded library?
870 #if 0 // def _MSC_VER
871 #define NO_DEBUG_ALLOCATION
874 // Unfortunately ~wxDebugStreamBuf doesn't work (VC++ 5) when we enable the debugging
875 // code. I have no idea why. In BC++ 4.5, we have a similar problem the debug
876 // stream myseriously changing pointer address between being passed from SetFile to SetStream.
877 // See docs/msw/issues.txt.
878 void * operator new (size_t size
, char * fileName
, int lineNum
)
880 #ifdef NO_DEBUG_ALLOCATION
883 return wxDebugAlloc(size
, fileName
, lineNum
, FALSE
, FALSE
);
887 void * operator new[] (size_t size
, char * fileName
, int lineNum
)
889 #ifdef NO_DEBUG_ALLOCATION
892 return wxDebugAlloc(size
, fileName
, lineNum
, FALSE
, TRUE
);
896 void operator delete (void * buf
)
898 #ifdef NO_DEBUG_ALLOCATION
905 void operator delete[] (void * buf
)
907 #ifdef NO_DEBUG_ALLOCATION
910 wxDebugFree(buf
, TRUE
);
916 // TODO: store whether this is a vector or not.
917 void * wxDebugAlloc(size_t size
, char * fileName
, int lineNum
, bool isObject
, bool isVect
)
919 // If not in debugging allocation mode, do the normal thing
920 // so we don't leave any trace of ourselves in the node list.
922 if (!wxDebugContext::GetDebugMode())
924 return (void *)malloc(size
);
927 char * buf
= (char *) malloc(wxDebugContext::TotSize (size
));
929 wxTrace("Call to malloc (%ld) failed.\n", (long)size
);
932 wxMemStruct
* st
= (wxMemStruct
*)buf
;
933 st
->m_firstMarker
= MemStartCheck
;
934 st
->m_reqSize
= size
;
935 st
->m_fileName
= fileName
;
936 st
->m_lineNum
= lineNum
;
937 st
->m_id
= MemStructId
;
940 st
->m_isObject
= isObject
;
942 // Errors from Append() shouldn't really happen - but just in case!
943 if (st
->Append () == 0) {
944 st
->ErrorMsg ("Trying to append new node");
947 if (wxDebugContext::GetCheckPrevious ()) {
948 if (st
->CheckAllPrevious () < 0) {
949 st
->ErrorMsg ("Checking previous nodes");
953 // Set up the extra markers at the middle and end.
954 char * ptr
= wxDebugContext::MidMarkerPos (buf
);
955 * (wxMarkerType
*) ptr
= MemMidCheck
;
956 ptr
= wxDebugContext::EndMarkerPos (buf
, size
);
957 * (wxMarkerType
*) ptr
= MemEndCheck
;
959 // pointer returned points to the start of the caller's
961 void *m_actualData
= (void *) wxDebugContext::CallerMemPos (buf
);
962 st
->m_actualData
= m_actualData
;
967 // TODO: check whether was allocated as a vector
968 void wxDebugFree(void * buf
, bool isVect
)
973 // If not in debugging allocation mode, do the normal thing
974 // so we don't leave any trace of ourselves in the node list.
975 if (!wxDebugContext::GetDebugMode())
981 // Points to the start of the entire allocated area.
982 char * startPointer
= wxDebugContext::StartPos ((char *) buf
);
983 // Find the struct and make sure that it's identifiable.
984 wxMemStruct
* st
= (wxMemStruct
*) wxDebugContext::StructPos (startPointer
);
986 if (! st
->ValidateNode ())
989 // If this is the current checkpoint, we need to
990 // move the checkpoint back so it points to a valid
992 if (st
== wxDebugContext::checkPoint
)
993 wxDebugContext::checkPoint
= wxDebugContext::checkPoint
->m_prev
;
997 st
->ErrorMsg ("Unlinking deleted node");
1000 // Now put in the fill char into the id slot and the caller requested
1001 // memory locations.
1003 (void) memset (wxDebugContext::CallerMemPos (startPointer
), MemFillChar
,
1004 st
->RequestSize ());
1006 // Don't allow delayed freeing of memory in this version
1007 // if (!wxDebugContext::GetDelayFree())
1008 // free((void *)st);
1012 // Trace: send output to the current debugging stream
1013 void wxTrace(const char *fmt
...)
1016 static char buffer
[512];
1021 wvsprintf(buffer
,fmt
,ap
) ;
1023 vsprintf(buffer
,fmt
,ap
) ;
1028 if (wxDebugContext::HasStream())
1030 wxDebugContext::GetStream() << buffer
;
1031 wxDebugContext::GetStream().flush();
1035 OutputDebugString((LPCSTR
)buffer
) ;
1037 fprintf(stderr
, buffer
);
1042 void wxTraceLevel(int level
, const char *fmt
...)
1044 if (wxDebugContext::GetLevel() < level
)
1048 static char buffer
[512];
1053 wvsprintf(buffer
,fmt
,ap
) ;
1055 vsprintf(buffer
,fmt
,ap
) ;
1060 if (wxDebugContext::HasStream())
1062 wxDebugContext::GetStream() << buffer
;
1063 wxDebugContext::GetStream().flush();
1067 OutputDebugString((LPCSTR
)buffer
) ;
1069 fprintf(stderr
, buffer
);
1073 #else // USE_MEMORY_TRACING && DEBUG
1074 void wxTrace(const char *WXUNUSED(fmt
) ...)
1078 void wxTraceLevel(int WXUNUSED(level
), const char *WXUNUSED(fmt
) ...)