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