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