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