/[pcsx2_0.9.7]/trunk/3rdparty/wxWidgets/src/common/memory.cpp
ViewVC logotype

Annotation of /trunk/3rdparty/wxWidgets/src/common/memory.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 31 - (hide annotations) (download)
Tue Sep 7 03:24:11 2010 UTC (10 years, 4 months ago) by william
File size: 29779 byte(s)
committing r3113 initial commit again...
1 william 31 /////////////////////////////////////////////////////////////////////////////
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
289     void wxMemStruct::SetDeleted ()
290     {
291     m_id = MemFillChar;
292     }
293    
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     */
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    
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     */
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    
455     wxDebugContext::wxDebugContext(void)
456     {
457     }
458    
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     */
468     size_t wxDebugContext::CalcAlignment ()
469     {
470     wxMarkerType ar[2];
471     return (char *) &ar[1] - (char *) &ar[0];
472     }
473    
474    
475     char * wxDebugContext::StructPos (const char * buf)
476     {
477     return (char *) buf;
478     }
479    
480     char * wxDebugContext::MidMarkerPos (const char * buf)
481     {
482     return StructPos (buf) + PaddedSize (sizeof (wxMemStruct));
483     }
484    
485     char * wxDebugContext::CallerMemPos (const char * buf)
486     {
487     return MidMarkerPos (buf) + PaddedSize (sizeof(wxMarkerType));
488     }
489    
490    
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     */
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     */
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    
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     */
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     */
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     */
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    
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    
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    
633     static wxDebugStatsStruct *InsertStatsStruct(wxDebugStatsStruct *head, wxDebugStatsStruct *st)
634     {
635     st->next = head;
636     return st;
637     }
638     #endif
639    
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    
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    
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.
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
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
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:
870     MemoryCriticalSection() {
871     memSectionOk = true;
872     }
873     ~MemoryCriticalSection() {
874     memSectionOk = false;
875     }
876     };
877    
878     class MemoryCriticalSectionLocker
879     {
880     public:
881     inline MemoryCriticalSectionLocker(wxCriticalSection& critsect)
882     : m_critsect(critsect), m_locked(memSectionOk) { if(m_locked) m_critsect.Enter(); }
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
902     void * operator new (size_t size, wxChar * fileName, int lineNum)
903     {
904     return wxDebugAlloc(size, fileName, lineNum, false, false);
905     }
906    
907     void * operator new (size_t size)
908     {
909     return wxDebugAlloc(size, NULL, 0, false);
910     }
911    
912     void operator delete (void * buf)
913     {
914     wxDebugFree(buf, false);
915     }
916    
917     #if wxUSE_ARRAY_MEMORY_OPERATORS
918     void * operator new[] (size_t size)
919     {
920     return wxDebugAlloc(size, NULL, 0, false, true);
921     }
922    
923     void * operator new[] (size_t size, wxChar * fileName, int lineNum)
924     {
925     return wxDebugAlloc(size, fileName, lineNum, false, true);
926     }
927    
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.
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
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
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
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    
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

  ViewVC Help
Powered by ViewVC 1.1.22