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