1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        src/common/memory.cpp
3 // Purpose:     Memory checking implementation
4 // Author:      Arthur Seaton, Julian Smart
5 // Modified by:
6 // Created:     04/01/98
7 // RCS-ID:      $Id: memory.cpp 41054 2006-09-07 19:01:45Z ABX $
8 // Copyright:   (c) Julian Smart
9 // Licence:     wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11 
12 // For compilers that support precompilation, includes "wx.h".
13 #include "wx/wxprec.h"
14 
15 #ifdef __BORLANDC__
16     #pragma hdrstop
17 #endif
18 
19 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
20 
21 #include "wx/memory.h"
22 
23 #ifndef WX_PRECOMP
24     #ifdef __WXMSW__
25         #include "wx/msw/wrapwin.h"
26     #endif
27     #include "wx/utils.h"
28     #include "wx/app.h"
29     #include "wx/hash.h"
30     #include "wx/log.h"
31 #endif
32 
33 #if wxUSE_THREADS
34     #include "wx/thread.h"
35 #endif
36 
37 #include <stdlib.h>
38 
39 #include "wx/ioswrap.h"
40 
41 #if !defined(__WATCOMC__) && !(defined(__VMS__) && ( __VMS_VER < 70000000 ) )\
42      && !defined( __MWERKS__ ) && !defined(__SALFORDC__)
43 #include <memory.h>
44 #endif
45 
46 #include <stdarg.h>
47 #include <string.h>
48 
49 #if wxUSE_THREADS && defined(__WXDEBUG__)
50 #define USE_THREADSAFE_MEMORY_ALLOCATION 1
51 #else
52 #define USE_THREADSAFE_MEMORY_ALLOCATION 0
53 #endif
54 
55 
56 #ifdef new
57 #undef new
58 #endif
59 
60 // wxDebugContext wxTheDebugContext;
61 /*
62   Redefine new and delete so that we can pick up situations where:
63         - we overwrite or underwrite areas of malloc'd memory.
64         - we use uninitialise variables
65   Only do this in debug mode.
66 
67   We change new to get enough memory to allocate a struct, followed
68   by the caller's requested memory, followed by a tag. The struct
69   is used to create a doubly linked list of these areas and also
70   contains another tag. The tags are used to determine when the area
71   has been over/under written.
72 */
73 
74 
75 /*
76   Values which are used to set the markers which will be tested for
77   under/over write. There are 3 of these, one in the struct, one
78   immediately after the struct but before the caller requested memory and
79   one immediately after the requested memory.
80 */
81 #define MemStartCheck  0x23A8
82 #define MemMidCheck  0xA328
83 #define MemEndCheck 0x8A32
84 #define MemFillChar 0xAF
85 #define MemStructId  0x666D
86 
87 /*
88   External interface for the wxMemStruct class. Others are
89   defined inline within the class def. Here we only need to be able
90   to add and delete nodes from the list and handle errors in some way.
91 */
92 
93 /*
94   Used for internal "this shouldn't happen" type of errors.
95 */
ErrorMsg(const char * mesg)96 void wxMemStruct::ErrorMsg (const char * mesg)
97 {
98   wxLogMessage(wxT("wxWidgets memory checking error: %s"), mesg);
99   PrintNode ();
100 }
101 
102 /*
103   Used when we find an overwrite or an underwrite error.
104 */
ErrorMsg()105 void wxMemStruct::ErrorMsg ()
106 {
107   wxLogMessage(wxT("wxWidgets over/underwrite memory error:"));
108   PrintNode ();
109 }
110 
111 
112 /*
113   We want to find out if pointers have been overwritten as soon as is
114   possible, so test everything before we dereference it. Of course it's still
115   quite possible that, if things have been overwritten, this function will
116   fall over, but the only way of dealing with that would cost too much in terms
117   of time.
118 */
AssertList()119 int wxMemStruct::AssertList ()
120 {
121     if (wxDebugContext::GetHead () != 0 && ! (wxDebugContext::GetHead ())->AssertIt () ||
122         wxDebugContext::GetTail () != 0 && ! wxDebugContext::GetTail ()->AssertIt ()) {
123         ErrorMsg ("Head or tail pointers trashed");
124         return 0;
125     }
126     return 1;
127 }
128 
129 
130 /*
131   Check that the thing we're pointing to has the correct id for a wxMemStruct
132   object and also that it's previous and next pointers are pointing at objects
133   which have valid ids.
134   This is definitely not perfect since we could fall over just trying to access
135   any of the slots which we use here, but I think it's about the best that I
136   can do without doing something like taking all new wxMemStruct pointers and
137   comparing them against all known pointer within the list and then only
138   doing this sort of check _after_ you've found the pointer in the list. That
139   would be safer, but also much more time consuming.
140 */
AssertIt()141 int wxMemStruct::AssertIt ()
142 {
143     return (m_id == MemStructId &&
144             (m_prev == 0 || m_prev->m_id == MemStructId) &&
145             (m_next == 0 || m_next->m_id == MemStructId));
146 }
147 
148 
149 /*
150   Additions are always at the tail of the list.
151   Returns 0 on error, non-zero on success.
152 */
Append()153 int wxMemStruct::Append ()
154 {
155     if (! AssertList ())
156         return 0;
157 
158     if (wxDebugContext::GetHead () == 0) {
159         if (wxDebugContext::GetTail () != 0) {
160             ErrorMsg ("Null list should have a null tail pointer");
161             return 0;
162         }
163         (void) wxDebugContext::SetHead (this);
164         (void) wxDebugContext::SetTail (this);
165     } else {
166         wxDebugContext::GetTail ()->m_next = this;
167         this->m_prev = wxDebugContext::GetTail ();
168         (void) wxDebugContext::SetTail (this);
169     }
170     return 1;
171 }
172 
173 
174 /*
175   Don't actually free up anything here as the space which is used
176   by the node will be free'd up when the whole block is free'd.
177   Returns 0 on error, non-zero on success.
178 */
Unlink()179 int wxMemStruct::Unlink ()
180 {
181     if (! AssertList ())
182         return 0;
183 
184     if (wxDebugContext::GetHead () == 0 || wxDebugContext::GetTail () == 0) {
185         ErrorMsg ("Trying to remove node from empty list");
186         return 0;
187     }
188 
189     // Handle the part of the list before this node.
190     if (m_prev == 0) {
191         if (this != wxDebugContext::GetHead ()) {
192             ErrorMsg ("No previous node for non-head node");
193             return 0;
194         }
195         (void) wxDebugContext::SetHead (m_next);
196     } else {
197         if (! m_prev->AssertIt ()) {
198             ErrorMsg ("Trashed previous pointer");
199             return 0;
200         }
201 
202         if (m_prev->m_next != this) {
203             ErrorMsg ("List is inconsistent");
204             return 0;
205         }
206         m_prev->m_next = m_next;
207     }
208 
209     // Handle the part of the list after this node.
210     if (m_next == 0) {
211         if (this != wxDebugContext::GetTail ()) {
212             ErrorMsg ("No next node for non-tail node");
213             return 0;
214         }
215         (void) wxDebugContext::SetTail (m_prev);
216     } else {
217         if (! m_next->AssertIt ()) {
218             ErrorMsg ("Trashed next pointer");
219             return 0;
220         }
221 
222         if (m_next->m_prev != this) {
223             ErrorMsg ("List is inconsistent");
224             return 0;
225         }
226         m_next->m_prev = m_prev;
227     }
228 
229     return 1;
230 }
231 
232 
233 
234 /*
235   Checks a node and block of memory to see that the markers are still
236   intact.
237 */
CheckBlock()238 int wxMemStruct::CheckBlock ()
239 {
240     int nFailures = 0;
241 
242     if (m_firstMarker != MemStartCheck) {
243         nFailures++;
244         ErrorMsg ();
245     }
246 
247     char * pointer = wxDebugContext::MidMarkerPos ((char *) this);
248     if (* (wxMarkerType *) pointer != MemMidCheck) {
249         nFailures++;
250         ErrorMsg ();
251     }
252 
253     pointer = wxDebugContext::EndMarkerPos ((char *) this, RequestSize ());
254     if (* (wxMarkerType *) pointer != MemEndCheck) {
255         nFailures++;
256         ErrorMsg ();
257     }
258 
259     return nFailures;
260 }
261 
262 
263 /*
264   Check the list of nodes to see if they are all ok.
265 */
CheckAllPrevious()266 int wxMemStruct::CheckAllPrevious ()
267 {
268     int nFailures = 0;
269 
270     for (wxMemStruct * st = this->m_prev; st != 0; st = st->m_prev) {
271         if (st->AssertIt ())
272             nFailures += st->CheckBlock ();
273         else
274             return -1;
275     }
276 
277     return nFailures;
278 }
279 
280 
281 /*
282   When we delete a node we set the id slot to a specific value and then test
283   against this to see if a nodes have been deleted previously. I don't
284   just set the entire memory to the fillChar because then I'd be overwriting
285   useful stuff like the vtbl which may be needed to output the error message
286   including the file name and line numbers. Without this info the whole point
287   of this class is lost!
288 */
SetDeleted()289 void wxMemStruct::SetDeleted ()
290 {
291     m_id = MemFillChar;
292 }
293 
IsDeleted()294 int wxMemStruct::IsDeleted ()
295 {
296     return (m_id == MemFillChar);
297 }
298 
299 
300 /*
301   Print out a single node. There are many far better ways of doing this
302   but this will suffice for now.
303 */
PrintNode()304 void wxMemStruct::PrintNode ()
305 {
306   if (m_isObject)
307   {
308     wxObject *obj = (wxObject *)m_actualData;
309     wxClassInfo *info = obj->GetClassInfo();
310 
311     // Let's put this in standard form so IDEs can load the file at the appropriate
312     // line
313     wxString msg;
314 
315     if (m_fileName)
316       msg.Printf(wxT("%s(%d): "), m_fileName, (int)m_lineNum);
317 
318     if (info && info->GetClassName())
319       msg += info->GetClassName();
320     else
321       msg += wxT("object");
322 
323     wxString msg2;
324     msg2.Printf(wxT(" at 0x%lX, size %d"), (long)GetActualData(), (int)RequestSize());
325     msg += msg2;
326 
327     wxLogMessage(msg);
328   }
329   else
330   {
331     wxString msg;
332 
333     if (m_fileName)
334       msg.Printf(wxT("%s(%d): "), m_fileName, (int)m_lineNum);
335     msg += wxT("non-object data");
336     wxString msg2;
337     msg2.Printf(wxT(" at 0x%lX, size %d\n"), (long)GetActualData(), (int)RequestSize());
338     msg += msg2;
339 
340     wxLogMessage(msg);
341   }
342 }
343 
Dump()344 void wxMemStruct::Dump ()
345 {
346   if (!ValidateNode()) return;
347 
348   if (m_isObject)
349   {
350     wxObject *obj = (wxObject *)m_actualData;
351 
352     wxString msg;
353     if (m_fileName)
354       msg.Printf(wxT("%s(%d): "), m_fileName, (int)m_lineNum);
355 
356 
357     /* TODO: We no longer have a stream (using wxLogDebug) so we can't dump it.
358      * Instead, do what wxObject::Dump does.
359      * What should we do long-term, eliminate Dumping? Or specify
360      * that MyClass::Dump should use wxLogDebug? Ugh.
361     obj->Dump(wxDebugContext::GetStream());
362      */
363 
364     if (obj->GetClassInfo() && obj->GetClassInfo()->GetClassName())
365       msg += obj->GetClassInfo()->GetClassName();
366     else
367       msg += wxT("unknown object class");
368 
369     wxString msg2;
370     msg2.Printf(wxT(" at 0x%lX, size %d"), (long)GetActualData(), (int)RequestSize());
371     msg += msg2;
372 
373     wxDebugContext::OutputDumpLine(msg);
374   }
375   else
376   {
377     wxString msg;
378     if (m_fileName)
379       msg.Printf(wxT("%s(%d): "), m_fileName, (int)m_lineNum);
380 
381     wxString msg2;
382     msg2.Printf(wxT("non-object data at 0x%lX, size %d"), (long)GetActualData(), (int)RequestSize() );
383     msg += msg2;
384     wxDebugContext::OutputDumpLine(msg);
385   }
386 }
387 
388 
389 /*
390   Validate a node. Check to see that the node is "clean" in the sense
391   that nothing has over/underwritten it etc.
392 */
ValidateNode()393 int wxMemStruct::ValidateNode ()
394 {
395     char * startPointer = (char *) this;
396     if (!AssertIt ()) {
397         if (IsDeleted ())
398             ErrorMsg ("Object already deleted");
399         else {
400             // Can't use the error routines as we have no recognisable object.
401 #ifndef __WXGTK__
402              wxLogMessage(wxT("Can't verify memory struct - all bets are off!"));
403 #endif
404         }
405         return 0;
406     }
407 
408 /*
409     int i;
410     for (i = 0; i < wxDebugContext::TotSize (requestSize ()); i++)
411       cout << startPointer [i];
412     cout << endl;
413 */
414     if (Marker () != MemStartCheck)
415       ErrorMsg ();
416     if (* (wxMarkerType *) wxDebugContext::MidMarkerPos (startPointer) != MemMidCheck)
417       ErrorMsg ();
418     if (* (wxMarkerType *) wxDebugContext::EndMarkerPos (startPointer,
419                                               RequestSize ()) !=
420         MemEndCheck)
421       ErrorMsg ();
422 
423     // Back to before the extra buffer and check that
424     // we can still read what we originally wrote.
425     if (Marker () != MemStartCheck ||
426         * (wxMarkerType *) wxDebugContext::MidMarkerPos (startPointer)
427                          != MemMidCheck ||
428         * (wxMarkerType *) wxDebugContext::EndMarkerPos (startPointer,
429                                               RequestSize ()) != MemEndCheck)
430     {
431         ErrorMsg ();
432         return 0;
433     }
434 
435     return 1;
436 }
437 
438 /*
439   The wxDebugContext class.
440 */
441 
442 wxMemStruct *wxDebugContext::m_head = NULL;
443 wxMemStruct *wxDebugContext::m_tail = NULL;
444 
445 bool wxDebugContext::m_checkPrevious = false;
446 int wxDebugContext::debugLevel = 1;
447 bool wxDebugContext::debugOn = true;
448 wxMemStruct *wxDebugContext::checkPoint = NULL;
449 
450 // For faster alignment calculation
451 static wxMarkerType markerCalc[2];
452 int wxDebugContext::m_balign = (int)((char *)&markerCalc[1] - (char*)&markerCalc[0]);
453 int wxDebugContext::m_balignmask = (int)((char *)&markerCalc[1] - (char*)&markerCalc[0]) - 1;
454 
wxDebugContext(void)455 wxDebugContext::wxDebugContext(void)
456 {
457 }
458 
~wxDebugContext(void)459 wxDebugContext::~wxDebugContext(void)
460 {
461 }
462 
463 /*
464   Work out the positions of the markers by creating an array of 2 markers
465   and comparing the addresses of the 2 elements. Use this number as the
466   alignment for markers.
467 */
CalcAlignment()468 size_t wxDebugContext::CalcAlignment ()
469 {
470     wxMarkerType ar[2];
471     return (char *) &ar[1] - (char *) &ar[0];
472 }
473 
474 
StructPos(const char * buf)475 char * wxDebugContext::StructPos (const char * buf)
476 {
477     return (char *) buf;
478 }
479 
MidMarkerPos(const char * buf)480 char * wxDebugContext::MidMarkerPos (const char * buf)
481 {
482     return StructPos (buf) + PaddedSize (sizeof (wxMemStruct));
483 }
484 
CallerMemPos(const char * buf)485 char * wxDebugContext::CallerMemPos (const char * buf)
486 {
487     return MidMarkerPos (buf) + PaddedSize (sizeof(wxMarkerType));
488 }
489 
490 
EndMarkerPos(const char * buf,const size_t size)491 char * wxDebugContext::EndMarkerPos (const char * buf, const size_t size)
492 {
493     return CallerMemPos (buf) + PaddedSize (size);
494 }
495 
496 
497 /*
498   Slightly different as this takes a pointer to the start of the caller
499   requested region and returns a pointer to the start of the buffer.
500   */
StartPos(const char * caller)501 char * wxDebugContext::StartPos (const char * caller)
502 {
503     return ((char *) (caller - wxDebugContext::PaddedSize (sizeof(wxMarkerType)) -
504             wxDebugContext::PaddedSize (sizeof (wxMemStruct))));
505 }
506 
507 /*
508   We may need padding between various parts of the allocated memory.
509   Given a size of memory, this returns the amount of memory which should
510   be allocated in order to allow for alignment of the following object.
511 
512   I don't know how portable this stuff is, but it seems to work for me at
513   the moment. It would be real nice if I knew more about this!
514 
515   // Note: this function is now obsolete (along with CalcAlignment)
516   // because the calculations are done statically, for greater speed.
517 */
GetPadding(const size_t size)518 size_t wxDebugContext::GetPadding (const size_t size)
519 {
520     size_t pad = size % CalcAlignment ();
521     return (pad) ? sizeof(wxMarkerType) - pad : 0;
522 }
523 
PaddedSize(const size_t size)524 size_t wxDebugContext::PaddedSize (const size_t size)
525 {
526     // Added by Terry Farnham <TJRT@pacbell.net> to replace
527     // slow GetPadding call.
528     int padb;
529 
530     padb = size & m_balignmask;
531     if(padb)
532         return(size + m_balign - padb);
533     else
534         return(size);
535 }
536 
537 /*
538   Returns the total amount of memory which we need to get from the system
539   in order to satisfy a caller request. This includes space for the struct
540   plus markers and the caller's memory as well.
541 */
TotSize(const size_t reqSize)542 size_t wxDebugContext::TotSize (const size_t reqSize)
543 {
544     return (PaddedSize (sizeof (wxMemStruct)) + PaddedSize (reqSize) +
545             2 * sizeof(wxMarkerType));
546 }
547 
548 
549 /*
550   Traverse the list of nodes executing the given function on each node.
551 */
TraverseList(PmSFV func,wxMemStruct * from)552 void wxDebugContext::TraverseList (PmSFV func, wxMemStruct *from)
553 {
554   if (!from)
555     from = wxDebugContext::GetHead ();
556 
557   wxMemStruct * st = NULL;
558   for (st = from; st != 0; st = st->m_next)
559   {
560       void* data = st->GetActualData();
561 //      if ((data != (void*)m_debugStream) && (data != (void*) m_streamBuf))
562       if (data != (void*) wxLog::GetActiveTarget())
563       {
564         (st->*func) ();
565       }
566   }
567 }
568 
569 
570 /*
571   Print out the list.
572   */
PrintList(void)573 bool wxDebugContext::PrintList (void)
574 {
575 #ifdef __WXDEBUG__
576   TraverseList ((PmSFV)&wxMemStruct::PrintNode, (checkPoint ? checkPoint->m_next : (wxMemStruct*)NULL));
577 
578   return true;
579 #else
580   return false;
581 #endif
582 }
583 
Dump(void)584 bool wxDebugContext::Dump(void)
585 {
586 #ifdef __WXDEBUG__
587   {
588     wxChar* appName = (wxChar*) wxT("application");
589     wxString appNameStr;
590     if (wxTheApp)
591     {
592         appNameStr = wxTheApp->GetAppName();
593         appName = WXSTRINGCAST appNameStr;
594         OutputDumpLine(wxT("----- Memory dump of %s at %s -----"), appName, WXSTRINGCAST wxNow() );
595     }
596     else
597     {
598       OutputDumpLine( wxT("----- Memory dump -----") );
599     }
600   }
601 
602   TraverseList ((PmSFV)&wxMemStruct::Dump, (checkPoint ? checkPoint->m_next : (wxMemStruct*)NULL));
603 
604   OutputDumpLine(wxEmptyString);
605   OutputDumpLine(wxEmptyString);
606 
607   return true;
608 #else
609   return false;
610 #endif
611 }
612 
613 #ifdef __WXDEBUG__
614 struct wxDebugStatsStruct
615 {
616   long instanceCount;
617   long totalSize;
618   wxChar *instanceClass;
619   wxDebugStatsStruct *next;
620 };
621 
FindStatsStruct(wxDebugStatsStruct * st,wxChar * name)622 static wxDebugStatsStruct *FindStatsStruct(wxDebugStatsStruct *st, wxChar *name)
623 {
624   while (st)
625   {
626     if (wxStrcmp(st->instanceClass, name) == 0)
627       return st;
628     st = st->next;
629   }
630   return NULL;
631 }
632 
InsertStatsStruct(wxDebugStatsStruct * head,wxDebugStatsStruct * st)633 static wxDebugStatsStruct *InsertStatsStruct(wxDebugStatsStruct *head, wxDebugStatsStruct *st)
634 {
635   st->next = head;
636   return st;
637 }
638 #endif
639 
PrintStatistics(bool detailed)640 bool wxDebugContext::PrintStatistics(bool detailed)
641 {
642 #ifdef __WXDEBUG__
643   {
644     wxChar* appName = (wxChar*) wxT("application");
645     wxString appNameStr;
646     if (wxTheApp)
647     {
648         appNameStr = wxTheApp->GetAppName();
649         appName = WXSTRINGCAST appNameStr;
650         OutputDumpLine(wxT("----- Memory statistics of %s at %s -----"), appName, WXSTRINGCAST wxNow() );
651     }
652     else
653     {
654       OutputDumpLine( wxT("----- Memory statistics -----") );
655     }
656   }
657 
658   bool currentMode = GetDebugMode();
659   SetDebugMode(false);
660 
661   long noNonObjectNodes = 0;
662   long noObjectNodes = 0;
663   long totalSize = 0;
664 
665   wxDebugStatsStruct *list = NULL;
666 
667   wxMemStruct *from = (checkPoint ? checkPoint->m_next : (wxMemStruct*)NULL );
668   if (!from)
669     from = wxDebugContext::GetHead ();
670 
671   wxMemStruct *st;
672   for (st = from; st != 0; st = st->m_next)
673   {
674     void* data = st->GetActualData();
675     if (detailed && (data != (void*) wxLog::GetActiveTarget()))
676     {
677       wxChar *className = (wxChar*) wxT("nonobject");
678       if (st->m_isObject && st->GetActualData())
679       {
680         wxObject *obj = (wxObject *)st->GetActualData();
681         if (obj->GetClassInfo()->GetClassName())
682           className = (wxChar*)obj->GetClassInfo()->GetClassName();
683       }
684       wxDebugStatsStruct *stats = FindStatsStruct(list, className);
685       if (!stats)
686       {
687         stats = (wxDebugStatsStruct *)malloc(sizeof(wxDebugStatsStruct));
688         stats->instanceClass = className;
689         stats->instanceCount = 0;
690         stats->totalSize = 0;
691         list = InsertStatsStruct(list, stats);
692       }
693       stats->instanceCount ++;
694       stats->totalSize += st->RequestSize();
695     }
696 
697     if (data != (void*) wxLog::GetActiveTarget())
698     {
699         totalSize += st->RequestSize();
700         if (st->m_isObject)
701             noObjectNodes ++;
702         else
703             noNonObjectNodes ++;
704     }
705   }
706 
707   if (detailed)
708   {
709     while (list)
710     {
711       OutputDumpLine(wxT("%ld objects of class %s, total size %ld"),
712           list->instanceCount, list->instanceClass, list->totalSize);
713       wxDebugStatsStruct *old = list;
714       list = old->next;
715       free((char *)old);
716     }
717     OutputDumpLine(wxEmptyString);
718   }
719 
720   SetDebugMode(currentMode);
721 
722   OutputDumpLine(wxT("Number of object items: %ld"), noObjectNodes);
723   OutputDumpLine(wxT("Number of non-object items: %ld"), noNonObjectNodes);
724   OutputDumpLine(wxT("Total allocated size: %ld"), totalSize);
725   OutputDumpLine(wxEmptyString);
726   OutputDumpLine(wxEmptyString);
727 
728   return true;
729 #else
730   (void)detailed;
731   return false;
732 #endif
733 }
734 
PrintClasses(void)735 bool wxDebugContext::PrintClasses(void)
736 {
737   {
738     wxChar* appName = (wxChar*) wxT("application");
739     wxString appNameStr;
740     if (wxTheApp)
741     {
742         appNameStr = wxTheApp->GetAppName();
743         appName = WXSTRINGCAST appNameStr;
744         wxLogMessage(wxT("----- Classes in %s -----"), appName);
745     }
746   }
747 
748   int n = 0;
749   wxHashTable::compatibility_iterator node;
750   wxClassInfo *info;
751 
752   wxClassInfo::sm_classTable->BeginFind();
753   node = wxClassInfo::sm_classTable->Next();
754   while (node)
755   {
756     info = (wxClassInfo *)node->GetData();
757     if (info->GetClassName())
758     {
759         wxString msg(info->GetClassName());
760         msg += wxT(" ");
761 
762         if (info->GetBaseClassName1() && !info->GetBaseClassName2())
763         {
764             msg += wxT("is a ");
765             msg += info->GetBaseClassName1();
766         }
767         else if (info->GetBaseClassName1() && info->GetBaseClassName2())
768         {
769             msg += wxT("is a ");
770             msg += info->GetBaseClassName1() ;
771             msg += wxT(", ");
772             msg += info->GetBaseClassName2() ;
773         }
774         if (info->GetConstructor())
775             msg += wxT(": dynamic");
776 
777         wxLogMessage(msg);
778     }
779     node = wxClassInfo::sm_classTable->Next();
780     n ++;
781   }
782   wxLogMessage(wxEmptyString);
783   wxLogMessage(wxT("There are %d classes derived from wxObject."), n);
784   wxLogMessage(wxEmptyString);
785   wxLogMessage(wxEmptyString);
786   return true;
787 }
788 
SetCheckpoint(bool all)789 void wxDebugContext::SetCheckpoint(bool all)
790 {
791   if (all)
792     checkPoint = NULL;
793   else
794     checkPoint = m_tail;
795 }
796 
797 // Checks all nodes since checkpoint, or since start.
Check(bool checkAll)798 int wxDebugContext::Check(bool checkAll)
799 {
800   int nFailures = 0;
801 
802   wxMemStruct *from = (checkPoint ? checkPoint->m_next : (wxMemStruct*)NULL );
803   if (!from || checkAll)
804     from = wxDebugContext::GetHead ();
805 
806   for (wxMemStruct * st = from; st != 0; st = st->m_next)
807   {
808     if (st->AssertIt ())
809       nFailures += st->CheckBlock ();
810     else
811       return -1;
812   }
813 
814   return nFailures;
815 }
816 
817 // Count the number of non-wxDebugContext-related objects
818 // that are outstanding
CountObjectsLeft(bool sinceCheckpoint)819 int wxDebugContext::CountObjectsLeft(bool sinceCheckpoint)
820 {
821   int n = 0;
822 
823   wxMemStruct *from = NULL;
824   if (sinceCheckpoint && checkPoint)
825     from = checkPoint->m_next;
826   else
827     from = wxDebugContext::GetHead () ;
828 
829   for (wxMemStruct * st = from; st != 0; st = st->m_next)
830   {
831       void* data = st->GetActualData();
832       if (data != (void*) wxLog::GetActiveTarget())
833           n ++;
834   }
835 
836   return n ;
837 }
838 
839 // This function is used to output the dump
OutputDumpLine(const wxChar * szFormat,...)840 void wxDebugContext::OutputDumpLine(const wxChar *szFormat, ...)
841 {
842     // a buffer of 2048 bytes should be long enough for a file name
843     // and a class name
844     wxChar buf[2048];
845     int count;
846     va_list argptr;
847     va_start(argptr, szFormat);
848     buf[sizeof(buf)/sizeof(wxChar)-1] = _T('\0');
849 
850     // keep 3 bytes for a \r\n\0
851     count = wxVsnprintf(buf, sizeof(buf)/sizeof(wxChar)-3, szFormat, argptr);
852 
853     if ( count < 0 )
854         count = sizeof(buf)/sizeof(wxChar)-3;
855     buf[count]=_T('\r');
856     buf[count+1]=_T('\n');
857     buf[count+2]=_T('\0');
858 
859     wxMessageOutputDebug dbgout;
860     dbgout.Printf(buf);
861 }
862 
863 
864 #if USE_THREADSAFE_MEMORY_ALLOCATION
865 static bool memSectionOk = false;
866 
867 class MemoryCriticalSection : public wxCriticalSection
868 {
869 public:
MemoryCriticalSection()870     MemoryCriticalSection() {
871         memSectionOk = true;
872     }
~MemoryCriticalSection()873     ~MemoryCriticalSection() {
874         memSectionOk = false;
875     }
876 };
877 
878 class MemoryCriticalSectionLocker
879 {
880 public:
MemoryCriticalSectionLocker(wxCriticalSection & critsect)881     inline MemoryCriticalSectionLocker(wxCriticalSection& critsect)
882     : m_critsect(critsect), m_locked(memSectionOk) { if(m_locked) m_critsect.Enter(); }
~MemoryCriticalSectionLocker()883     inline ~MemoryCriticalSectionLocker() { if(m_locked) m_critsect.Leave(); }
884 
885 private:
886     // no assignment operator nor copy ctor
887     MemoryCriticalSectionLocker(const MemoryCriticalSectionLocker&);
888     MemoryCriticalSectionLocker& operator=(const MemoryCriticalSectionLocker&);
889 
890     wxCriticalSection& m_critsect;
891     bool m_locked;
892 };
893 
894 static MemoryCriticalSection memLocker;
895 
896 #endif // USE_THREADSAFE_MEMORY_ALLOCATION
897 
898 
899 #ifdef __WXDEBUG__
900 #if !(defined(__WXMSW__) && (defined(WXUSINGDLL) || defined(WXMAKINGDLL_BASE)))
901 #if wxUSE_GLOBAL_MEMORY_OPERATORS
operator new(size_t size,wxChar * fileName,int lineNum)902 void * operator new (size_t size, wxChar * fileName, int lineNum)
903 {
904     return wxDebugAlloc(size, fileName, lineNum, false, false);
905 }
906 
operator new(size_t size)907 void * operator new (size_t size)
908 {
909     return wxDebugAlloc(size, NULL, 0, false);
910 }
911 
operator delete(void * buf)912 void operator delete (void * buf)
913 {
914     wxDebugFree(buf, false);
915 }
916 
917 #if wxUSE_ARRAY_MEMORY_OPERATORS
operator new[](size_t size)918 void * operator new[] (size_t size)
919 {
920     return wxDebugAlloc(size, NULL, 0, false, true);
921 }
922 
operator new[](size_t size,wxChar * fileName,int lineNum)923 void * operator new[] (size_t size, wxChar * fileName, int lineNum)
924 {
925     return wxDebugAlloc(size, fileName, lineNum, false, true);
926 }
927 
operator delete[](void * buf)928 void operator delete[] (void * buf)
929 {
930   wxDebugFree(buf, true);
931 }
932 #endif // wxUSE_ARRAY_MEMORY_OPERATORS
933 #endif // wxUSE_GLOBAL_MEMORY_OPERATORS
934 #endif // !(defined(__WXMSW__) && (defined(WXUSINGDLL) || defined(WXMAKINGDLL_BASE)))
935 
936 // TODO: store whether this is a vector or not.
wxDebugAlloc(size_t size,wxChar * fileName,int lineNum,bool isObject,bool WXUNUSED (isVect))937 void * wxDebugAlloc(size_t size, wxChar * fileName, int lineNum, bool isObject, bool WXUNUSED(isVect) )
938 {
939 #if USE_THREADSAFE_MEMORY_ALLOCATION
940   MemoryCriticalSectionLocker lock(memLocker);
941 #endif
942 
943   // If not in debugging allocation mode, do the normal thing
944   // so we don't leave any trace of ourselves in the node list.
945 
946 #if defined(__VISAGECPP__) && (__IBMCPP__ < 400 || __IBMC__ < 400 )
947 // VA 3.0 still has trouble in here
948   return (void *)malloc(size);
949 #endif
950   if (!wxDebugContext::GetDebugMode())
951   {
952     return (void *)malloc(size);
953   }
954 
955     int totSize = wxDebugContext::TotSize (size);
956     char * buf = (char *) malloc(totSize);
957     if (!buf) {
958         wxLogMessage(wxT("Call to malloc (%ld) failed."), (long)size);
959         return 0;
960     }
961     wxMemStruct * st = (wxMemStruct *)buf;
962     st->m_firstMarker = MemStartCheck;
963     st->m_reqSize = size;
964     st->m_fileName = fileName;
965     st->m_lineNum = lineNum;
966     st->m_id = MemStructId;
967     st->m_prev = 0;
968     st->m_next = 0;
969     st->m_isObject = isObject;
970 
971     // Errors from Append() shouldn't really happen - but just in case!
972     if (st->Append () == 0) {
973         st->ErrorMsg ("Trying to append new node");
974     }
975 
976     if (wxDebugContext::GetCheckPrevious ()) {
977         if (st->CheckAllPrevious () < 0) {
978             st->ErrorMsg ("Checking previous nodes");
979         }
980     }
981 
982     // Set up the extra markers at the middle and end.
983     char * ptr = wxDebugContext::MidMarkerPos (buf);
984     * (wxMarkerType *) ptr = MemMidCheck;
985     ptr = wxDebugContext::EndMarkerPos (buf, size);
986     * (wxMarkerType *) ptr = MemEndCheck;
987 
988     // pointer returned points to the start of the caller's
989     // usable area.
990     void *m_actualData = (void *) wxDebugContext::CallerMemPos (buf);
991     st->m_actualData = m_actualData;
992 
993     return m_actualData;
994 }
995 
996 // TODO: check whether was allocated as a vector
wxDebugFree(void * buf,bool WXUNUSED (isVect))997 void wxDebugFree(void * buf, bool WXUNUSED(isVect) )
998 {
999 #if USE_THREADSAFE_MEMORY_ALLOCATION
1000   MemoryCriticalSectionLocker lock(memLocker);
1001 #endif
1002 
1003   if (!buf)
1004     return;
1005 
1006 #if defined(__VISAGECPP__) && (__IBMCPP__ < 400 || __IBMC__ < 400 )
1007 // VA 3.0 still has trouble in here
1008   free((char *)buf);
1009 #endif
1010   // If not in debugging allocation mode, do the normal thing
1011   // so we don't leave any trace of ourselves in the node list.
1012   if (!wxDebugContext::GetDebugMode())
1013   {
1014     free((char *)buf);
1015     return;
1016   }
1017 
1018     // Points to the start of the entire allocated area.
1019     char * startPointer = wxDebugContext::StartPos ((char *) buf);
1020     // Find the struct and make sure that it's identifiable.
1021     wxMemStruct * st = (wxMemStruct *) wxDebugContext::StructPos (startPointer);
1022 
1023     if (! st->ValidateNode ())
1024         return;
1025 
1026     // If this is the current checkpoint, we need to
1027     // move the checkpoint back so it points to a valid
1028     // node.
1029     if (st == wxDebugContext::checkPoint)
1030       wxDebugContext::checkPoint = wxDebugContext::checkPoint->m_prev;
1031 
1032     if (! st->Unlink ())
1033     {
1034       st->ErrorMsg ("Unlinking deleted node");
1035     }
1036 
1037     // Now put in the fill char into the id slot and the caller requested
1038     // memory locations.
1039     st->SetDeleted ();
1040     (void) memset (wxDebugContext::CallerMemPos (startPointer), MemFillChar,
1041                    st->RequestSize ());
1042 
1043     free((char *)st);
1044 }
1045 
1046 #endif // __WXDEBUG__
1047 
1048 // Trace: send output to the current debugging stream
wxTrace(const wxChar * ...)1049 void wxTrace(const wxChar * ...)
1050 {
1051 #if 1
1052     wxFAIL_MSG(wxT("wxTrace is now obsolete. Please use wxDebugXXX instead."));
1053 #else
1054     va_list ap;
1055   static wxChar buffer[512];
1056 
1057   va_start(ap, fmt);
1058 
1059 #ifdef __WXMSW__
1060   wvsprintf(buffer,fmt,ap) ;
1061 #else
1062   vsprintf(buffer,fmt,ap) ;
1063 #endif
1064 
1065   va_end(ap);
1066 
1067   if (wxDebugContext::HasStream())
1068   {
1069     wxDebugContext::GetStream() << buffer;
1070     wxDebugContext::GetStream().flush();
1071   }
1072   else
1073 #ifdef __WXMSW__
1074 #ifdef __WIN32__
1075     OutputDebugString((LPCTSTR)buffer) ;
1076 #else
1077     OutputDebugString((const char*) buffer) ;
1078 #endif
1079 #else
1080     fprintf(stderr, buffer);
1081 #endif
1082 #endif
1083 }
1084 
1085 // Trace with level
wxTraceLevel(int,const wxChar * ...)1086 void wxTraceLevel(int, const wxChar * ...)
1087 {
1088 #if 1
1089     wxFAIL_MSG(wxT("wxTrace is now obsolete. Please use wxDebugXXX instead."));
1090 #else
1091   if (wxDebugContext::GetLevel() < level)
1092     return;
1093 
1094   va_list ap;
1095   static wxChar buffer[512];
1096 
1097   va_start(ap, fmt);
1098 
1099 #ifdef __WXMSW__
1100   wxWvsprintf(buffer,fmt,ap) ;
1101 #else
1102   vsprintf(buffer,fmt,ap) ;
1103 #endif
1104 
1105   va_end(ap);
1106 
1107   if (wxDebugContext::HasStream())
1108   {
1109     wxDebugContext::GetStream() << buffer;
1110     wxDebugContext::GetStream().flush();
1111   }
1112   else
1113 #ifdef __WXMSW__
1114 #ifdef __WIN32__
1115     OutputDebugString((LPCTSTR)buffer) ;
1116 #else
1117     OutputDebugString((const char*) buffer) ;
1118 #endif
1119 #else
1120     fprintf(stderr, buffer);
1121 #endif
1122 #endif
1123 }
1124 
1125 //----------------------------------------------------------------------------
1126 // Final cleanup after all global objects in all files have been destroyed
1127 //----------------------------------------------------------------------------
1128 
1129 // Don't set it to 0 by dynamic initialization
1130 // Some compilers will really do the assignment later
1131 // All global variables are initialized to 0 at the very beginning, and this is just fine.
1132 int wxDebugContextDumpDelayCounter::sm_count;
1133 
DoDump()1134 void wxDebugContextDumpDelayCounter::DoDump()
1135 {
1136     if (wxDebugContext::CountObjectsLeft(true) > 0)
1137     {
1138         wxDebugContext::OutputDumpLine(wxT("There were memory leaks.\n"));
1139         wxDebugContext::Dump();
1140         wxDebugContext::PrintStatistics();
1141     }
1142 }
1143 
1144 // Even if there is nothing else, make sure that there is at
1145 // least one cleanup counter object
1146 static wxDebugContextDumpDelayCounter wxDebugContextDumpDelayCounter_One;
1147 
1148 #endif // (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
1149