]> git.saurik.com Git - wxWidgets.git/blob - src/common/memory.cpp
don't crash in UnselectAll() if the tree has no root
[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 #include "wx/log.h"
39 #include <stdlib.h>
40
41 #include "wx/ioswrap.h"
42
43 // Obsolete
44 #if 0
45 #if wxUSE_IOSTREAMH
46 #include <fstream.h>
47 #else
48 #include <fstream>
49 #endif
50 #endif
51
52 #if !defined(__WATCOMC__) && !(defined(__VMS__) && ( __VMS_VER < 70000000 ) )\
53 && !defined( __MWERKS__ ) && !defined(__SALFORDC__)
54 #include <memory.h>
55 #endif
56
57 #include <stdarg.h>
58 #include <string.h>
59
60 #ifdef __WXMSW__
61 #include <windows.h>
62
63 #ifdef GetClassInfo
64 #undef GetClassInfo
65 #endif
66
67 #ifdef GetClassName
68 #undef GetClassName
69 #endif
70
71 #endif
72
73 #include "wx/memory.h"
74
75 #ifdef new
76 #undef new
77 #endif
78
79 // wxDebugContext wxTheDebugContext;
80 /*
81 Redefine new and delete so that we can pick up situations where:
82 - we overwrite or underwrite areas of malloc'd memory.
83 - we use uninitialise variables
84 Only do this in debug mode.
85
86 We change new to get enough memory to allocate a struct, followed
87 by the caller's requested memory, followed by a tag. The struct
88 is used to create a doubly linked list of these areas and also
89 contains another tag. The tags are used to determine when the area
90 has been over/under written.
91 */
92
93
94 /*
95 Values which are used to set the markers which will be tested for
96 under/over write. There are 3 of these, one in the struct, one
97 immediately after the struct but before the caller requested memory and
98 one immediately after the requested memory.
99 */
100 #define MemStartCheck 0x23A8
101 #define MemMidCheck 0xA328
102 #define MemEndCheck 0x8A32
103 #define MemFillChar 0xAF
104 #define MemStructId 0x666D
105
106 /*
107 External interface for the wxMemStruct class. Others are
108 defined inline within the class def. Here we only need to be able
109 to add and delete nodes from the list and handle errors in some way.
110 */
111
112 /*
113 Used for internal "this shouldn't happen" type of errors.
114 */
115 void wxMemStruct::ErrorMsg (const char * mesg)
116 {
117 wxLogMessage(wxT("wxWindows memory checking error: %s"), mesg);
118 PrintNode ();
119
120 // << m_fileName << ' ' << m_lineNum << endl;
121 }
122
123 /*
124 Used when we find an overwrite or an underwrite error.
125 */
126 void wxMemStruct::ErrorMsg ()
127 {
128 wxLogMessage(wxT("wxWindows over/underwrite memory error:"));
129 PrintNode ();
130
131 // cerr << m_fileName << ' ' << m_lineNum << endl;
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 // wxSTD ostream *wxDebugContext::m_debugStream = NULL;
468 // wxSTD streambuf *wxDebugContext::m_streamBuf = NULL;
469
470 // Must initialise these in wxEntry, and then delete them just before wxEntry exits
471 // Obsolete
472 #if 0
473 wxSTD streambuf *wxDebugContext::m_streamBuf = NULL;
474 wxSTD ostream *wxDebugContext::m_debugStream = NULL;
475 #endif
476
477 bool wxDebugContext::m_checkPrevious = FALSE;
478 int wxDebugContext::debugLevel = 1;
479 bool wxDebugContext::debugOn = TRUE;
480 wxMemStruct *wxDebugContext::checkPoint = NULL;
481
482 // For faster alignment calculation
483 static wxMarkerType markerCalc[2];
484 int wxDebugContext::m_balign = (int)((char *)&markerCalc[1] - (char*)&markerCalc[0]);
485 int wxDebugContext::m_balignmask = (int)((char *)&markerCalc[1] - (char*)&markerCalc[0]) - 1;
486
487 wxDebugContext::wxDebugContext(void)
488 {
489 // m_streamBuf = new wxDebugStreamBuf;
490 // m_debugStream = new wxSTD ostream(m_streamBuf);
491 }
492
493 wxDebugContext::~wxDebugContext(void)
494 {
495 // SetStream(NULL, NULL);
496 }
497
498 /*
499 * It's bizarre, but with BC++ 4.5, the value of str changes
500 * between SetFile and SetStream.
501 */
502
503 // Obsolete
504 #if 0
505 void wxDebugContext::SetStream(wxSTD ostream *str, wxSTD streambuf *buf)
506 {
507 if (m_debugStream)
508 {
509 m_debugStream->flush();
510 delete m_debugStream;
511 }
512 m_debugStream = NULL;
513
514 // Not allowed in Watcom (~streambuf is protected).
515 // Is this trying to say something significant to us??
516 #ifndef __WATCOMC__
517 if (m_streamBuf)
518 {
519 wxSTD streambuf* oldBuf = m_streamBuf;
520 m_streamBuf = NULL;
521 delete oldBuf;
522 }
523 #endif
524 m_streamBuf = buf;
525 m_debugStream = str;
526 }
527
528 bool wxDebugContext::SetFile(const wxString& file)
529 {
530 wxSTD ofstream *str = new wxSTD ofstream(file.mb_str());
531
532 if (str->bad())
533 {
534 delete str;
535 return FALSE;
536 }
537 else
538 {
539 SetStream(str);
540 return TRUE;
541 }
542 }
543
544 bool wxDebugContext::SetStandardError(void)
545 {
546 // Obsolete
547 #if 0
548 #if !defined(_WINDLL)
549 wxDebugStreamBuf *buf = new wxDebugStreamBuf;
550 wxSTD ostream *stream = new wxSTD ostream(m_streamBuf);
551 SetStream(stream, buf);
552 return TRUE;
553 #else
554 return FALSE;
555 #endif
556 #endif
557 return FALSE;
558 }
559 #endif
560 // 0
561
562 /*
563 Work out the positions of the markers by creating an array of 2 markers
564 and comparing the addresses of the 2 elements. Use this number as the
565 alignment for markers.
566 */
567 size_t wxDebugContext::CalcAlignment ()
568 {
569 wxMarkerType ar[2];
570 return (char *) &ar[1] - (char *) &ar[0];
571 }
572
573
574 char * wxDebugContext::StructPos (const char * buf)
575 {
576 return (char *) buf;
577 }
578
579 char * wxDebugContext::MidMarkerPos (const char * buf)
580 {
581 return StructPos (buf) + PaddedSize (sizeof (wxMemStruct));
582 }
583
584 char * wxDebugContext::CallerMemPos (const char * buf)
585 {
586 return MidMarkerPos (buf) + PaddedSize (sizeof(wxMarkerType));
587 }
588
589
590 char * wxDebugContext::EndMarkerPos (const char * buf, const size_t size)
591 {
592 return CallerMemPos (buf) + PaddedSize (size);
593 }
594
595
596 /*
597 Slightly different as this takes a pointer to the start of the caller
598 requested region and returns a pointer to the start of the buffer.
599 */
600 char * wxDebugContext::StartPos (const char * caller)
601 {
602 return ((char *) (caller - wxDebugContext::PaddedSize (sizeof(wxMarkerType)) -
603 wxDebugContext::PaddedSize (sizeof (wxMemStruct))));
604 }
605
606 /*
607 We may need padding between various parts of the allocated memory.
608 Given a size of memory, this returns the amount of memory which should
609 be allocated in order to allow for alignment of the following object.
610
611 I don't know how portable this stuff is, but it seems to work for me at
612 the moment. It would be real nice if I knew more about this!
613
614 // Note: this function is now obsolete (along with CalcAlignment)
615 // because the calculations are done statically, for greater speed.
616 */
617 size_t wxDebugContext::GetPadding (const size_t size)
618 {
619 size_t pad = size % CalcAlignment ();
620 return (pad) ? sizeof(wxMarkerType) - pad : 0;
621 }
622
623 size_t wxDebugContext::PaddedSize (const size_t size)
624 {
625 // Added by Terry Farnham <TJRT@pacbell.net> to replace
626 // slow GetPadding call.
627 int padb;
628
629 padb = size & m_balignmask;
630 if(padb)
631 return(size + m_balign - padb);
632 else
633 return(size);
634
635 // Old (slow) code
636 #if 0
637 return size + GetPadding (size);
638 #endif
639 }
640
641 /*
642 Returns the total amount of memory which we need to get from the system
643 in order to satisfy a caller request. This includes space for the struct
644 plus markers and the caller's memory as well.
645 */
646 size_t wxDebugContext::TotSize (const size_t reqSize)
647 {
648 return (PaddedSize (sizeof (wxMemStruct)) + PaddedSize (reqSize) +
649 2 * sizeof(wxMarkerType));
650 }
651
652
653 /*
654 Traverse the list of nodes executing the given function on each node.
655 */
656 void wxDebugContext::TraverseList (PmSFV func, wxMemStruct *from)
657 {
658 if (!from)
659 from = wxDebugContext::GetHead ();
660
661 wxMemStruct * st = NULL;
662 for (st = from; st != 0; st = st->m_next)
663 {
664 void* data = st->GetActualData();
665 // if ((data != (void*)m_debugStream) && (data != (void*) m_streamBuf))
666 if (data != (void*) wxLog::GetActiveTarget())
667 {
668 (st->*func) ();
669 }
670 }
671 }
672
673
674 /*
675 Print out the list.
676 */
677 bool wxDebugContext::PrintList (void)
678 {
679 #ifdef __WXDEBUG__
680 // if (!HasStream())
681 // return FALSE;
682
683 TraverseList ((PmSFV)&wxMemStruct::PrintNode, (checkPoint ? checkPoint->m_next : (wxMemStruct*)NULL));
684
685 return TRUE;
686 #else
687 return FALSE;
688 #endif
689 }
690
691 bool wxDebugContext::Dump(void)
692 {
693 #ifdef __WXDEBUG__
694 // if (!HasStream())
695 // return FALSE;
696
697 // if (TRUE)
698 {
699 wxChar* appName = wxT("application");
700 wxString appNameStr("");
701 if (wxTheApp)
702 {
703 appNameStr = wxTheApp->GetAppName();
704 appName = WXSTRINGCAST appNameStr;
705 wxLogMessage(wxT("----- Memory dump of %s at %s -----"), appName, WXSTRINGCAST wxNow() );
706 }
707 else
708 {
709 wxLogMessage( wxT("----- Memory dump -----") );
710 }
711 }
712 TraverseList ((PmSFV)&wxMemStruct::Dump, (checkPoint ? checkPoint->m_next : (wxMemStruct*)NULL));
713
714 wxLogMessage( wxT("") );
715 wxLogMessage( wxT("") );
716
717 return TRUE;
718 #else
719 return FALSE;
720 #endif
721 }
722
723 #ifdef __WXDEBUG__
724 struct wxDebugStatsStruct
725 {
726 long instanceCount;
727 long totalSize;
728 wxChar *instanceClass;
729 wxDebugStatsStruct *next;
730 };
731
732 static wxDebugStatsStruct *FindStatsStruct(wxDebugStatsStruct *st, wxChar *name)
733 {
734 while (st)
735 {
736 if (wxStrcmp(st->instanceClass, name) == 0)
737 return st;
738 st = st->next;
739 }
740 return NULL;
741 }
742
743 static wxDebugStatsStruct *InsertStatsStruct(wxDebugStatsStruct *head, wxDebugStatsStruct *st)
744 {
745 st->next = head;
746 return st;
747 }
748 #endif
749
750 bool wxDebugContext::PrintStatistics(bool detailed)
751 {
752 #ifdef __WXDEBUG__
753 // if (!HasStream())
754 // return FALSE;
755
756 // if (TRUE)
757 {
758 wxChar* appName = wxT("application");
759 wxString appNameStr(wxT(""));
760 if (wxTheApp)
761 {
762 appNameStr = wxTheApp->GetAppName();
763 appName = WXSTRINGCAST appNameStr;
764 wxLogMessage(wxT("----- Memory statistics of %s at %s -----"), appName, WXSTRINGCAST wxNow() );
765 }
766 else
767 {
768 wxLogMessage( wxT("----- Memory statistics -----") );
769 }
770 }
771
772 bool currentMode = GetDebugMode();
773 SetDebugMode(FALSE);
774
775 long noNonObjectNodes = 0;
776 long noObjectNodes = 0;
777 long totalSize = 0;
778
779 wxDebugStatsStruct *list = NULL;
780
781 wxMemStruct *from = (checkPoint ? checkPoint->m_next : (wxMemStruct*)NULL );
782 if (!from)
783 from = wxDebugContext::GetHead ();
784
785 wxMemStruct *st;
786 for (st = from; st != 0; st = st->m_next)
787 {
788 void* data = st->GetActualData();
789 // if (detailed && (data != (void*)m_debugStream) && (data != (void*) m_streamBuf))
790 if (detailed && (data != (void*) wxLog::GetActiveTarget()))
791 {
792 wxChar *className = wxT("nonobject");
793 if (st->m_isObject && st->GetActualData())
794 {
795 wxObject *obj = (wxObject *)st->GetActualData();
796 if (obj->GetClassInfo()->GetClassName())
797 className = (wxChar*)obj->GetClassInfo()->GetClassName();
798 }
799 wxDebugStatsStruct *stats = FindStatsStruct(list, className);
800 if (!stats)
801 {
802 stats = (wxDebugStatsStruct *)malloc(sizeof(wxDebugStatsStruct));
803 stats->instanceClass = className;
804 stats->instanceCount = 0;
805 stats->totalSize = 0;
806 list = InsertStatsStruct(list, stats);
807 }
808 stats->instanceCount ++;
809 stats->totalSize += st->RequestSize();
810 }
811
812 // if ((data != (void*)m_debugStream) && (data != (void*) m_streamBuf))
813 if (data != (void*) wxLog::GetActiveTarget())
814 {
815 totalSize += st->RequestSize();
816 if (st->m_isObject)
817 noObjectNodes ++;
818 else
819 noNonObjectNodes ++;
820 }
821 }
822
823 if (detailed)
824 {
825 while (list)
826 {
827 wxLogMessage(wxT("%ld objects of class %s, total size %ld"),
828 list->instanceCount, list->instanceClass, list->totalSize);
829 wxDebugStatsStruct *old = list;
830 list = old->next;
831 free((char *)old);
832 }
833 wxLogMessage(wxT(""));
834 }
835
836 SetDebugMode(currentMode);
837
838 wxLogMessage(wxT("Number of object items: %ld"), noObjectNodes);
839 wxLogMessage(wxT("Number of non-object items: %ld"), noNonObjectNodes);
840 wxLogMessage(wxT("Total allocated size: %ld"), totalSize);
841 wxLogMessage(wxT(""));
842 wxLogMessage(wxT(""));
843
844 return TRUE;
845 #else
846 (void)detailed;
847 return FALSE;
848 #endif
849 }
850
851 bool wxDebugContext::PrintClasses(void)
852 {
853 // if (!HasStream())
854 // return FALSE;
855
856 // if (TRUE)
857 {
858 wxChar* appName = wxT("application");
859 wxString appNameStr(wxT(""));
860 if (wxTheApp)
861 {
862 appNameStr = wxTheApp->GetAppName();
863 appName = WXSTRINGCAST appNameStr;
864 wxLogMessage(wxT("----- Classes in %s -----"), appName);
865 }
866 }
867
868 int n = 0;
869 wxNode *node;
870 wxClassInfo *info;
871
872 wxClassInfo::sm_classTable->BeginFind();
873 node = wxClassInfo::sm_classTable->Next();
874 while (node)
875 {
876 info = (wxClassInfo *)node->Data();
877 if (info->GetClassName())
878 {
879 wxString msg(info->GetClassName());
880 msg += wxT(" ");
881
882 if (info->GetBaseClassName1() && !info->GetBaseClassName2())
883 {
884 msg += wxT("is a ");
885 msg += info->GetBaseClassName1();
886 }
887 else if (info->GetBaseClassName1() && info->GetBaseClassName2())
888 {
889 msg += wxT("is a ");
890 msg += info->GetBaseClassName1() ;
891 msg += wxT(", ");
892 msg += info->GetBaseClassName2() ;
893 }
894 if (info->GetConstructor())
895 msg += wxT(": dynamic");
896
897 wxLogMessage(msg);
898 }
899 node = wxClassInfo::sm_classTable->Next();
900 n ++;
901 }
902 wxLogMessage(wxT(""));
903 wxLogMessage(wxT("There are %d classes derived from wxObject."), n);
904 wxLogMessage(wxT(""));
905 wxLogMessage(wxT(""));
906 return TRUE;
907 }
908
909 void wxDebugContext::SetCheckpoint(bool all)
910 {
911 if (all)
912 checkPoint = NULL;
913 else
914 checkPoint = m_tail;
915 }
916
917 // Checks all nodes since checkpoint, or since start.
918 int wxDebugContext::Check(bool checkAll)
919 {
920 int nFailures = 0;
921
922 wxMemStruct *from = (checkPoint ? checkPoint->m_next : (wxMemStruct*)NULL );
923 if (!from || checkAll)
924 from = wxDebugContext::GetHead ();
925
926 for (wxMemStruct * st = from; st != 0; st = st->m_next)
927 {
928 if (st->AssertIt ())
929 nFailures += st->CheckBlock ();
930 else
931 return -1;
932 }
933
934 return nFailures;
935 }
936
937 // Count the number of non-wxDebugContext-related objects
938 // that are outstanding
939 int wxDebugContext::CountObjectsLeft(bool sinceCheckpoint)
940 {
941 int n = 0;
942
943 wxMemStruct *from = NULL;
944 if (sinceCheckpoint && checkPoint)
945 from = checkPoint->m_next;
946 else
947 from = wxDebugContext::GetHead () ;
948
949 for (wxMemStruct * st = from; st != 0; st = st->m_next)
950 {
951 void* data = st->GetActualData();
952 // if ((data != (void*)m_debugStream) && (data != (void*) m_streamBuf))
953 if (data != (void*) wxLog::GetActiveTarget())
954 n ++;
955 }
956
957 return n ;
958 }
959
960 // TODO: store whether this is a vector or not.
961 void * wxDebugAlloc(size_t size, wxChar * fileName, int lineNum, bool isObject, bool WXUNUSED(isVect) )
962 {
963 // If not in debugging allocation mode, do the normal thing
964 // so we don't leave any trace of ourselves in the node list.
965
966 #if defined(__VISAGECPP__) && (__IBMCPP__ < 400 || __IBMC__ < 400 )
967 // VA 3.0 still has trouble in here
968 return (void *)malloc(size);
969 #endif
970 if (!wxDebugContext::GetDebugMode())
971 {
972 return (void *)malloc(size);
973 }
974
975 int totSize = wxDebugContext::TotSize (size);
976 char * buf = (char *) malloc(totSize);
977 if (!buf) {
978 wxLogMessage(wxT("Call to malloc (%ld) failed."), (long)size);
979 return 0;
980 }
981 wxMemStruct * st = (wxMemStruct *)buf;
982 st->m_firstMarker = MemStartCheck;
983 st->m_reqSize = size;
984 st->m_fileName = fileName;
985 st->m_lineNum = lineNum;
986 st->m_id = MemStructId;
987 st->m_prev = 0;
988 st->m_next = 0;
989 st->m_isObject = isObject;
990
991 // Errors from Append() shouldn't really happen - but just in case!
992 if (st->Append () == 0) {
993 st->ErrorMsg ("Trying to append new node");
994 }
995
996 if (wxDebugContext::GetCheckPrevious ()) {
997 if (st->CheckAllPrevious () < 0) {
998 st->ErrorMsg ("Checking previous nodes");
999 }
1000 }
1001
1002 // Set up the extra markers at the middle and end.
1003 char * ptr = wxDebugContext::MidMarkerPos (buf);
1004 * (wxMarkerType *) ptr = MemMidCheck;
1005 ptr = wxDebugContext::EndMarkerPos (buf, size);
1006 * (wxMarkerType *) ptr = MemEndCheck;
1007
1008 // pointer returned points to the start of the caller's
1009 // usable area.
1010 void *m_actualData = (void *) wxDebugContext::CallerMemPos (buf);
1011 st->m_actualData = m_actualData;
1012
1013 return m_actualData;
1014 }
1015
1016 // TODO: check whether was allocated as a vector
1017 void wxDebugFree(void * buf, bool WXUNUSED(isVect) )
1018 {
1019 if (!buf)
1020 return;
1021
1022 #if defined(__VISAGECPP__) && (__IBMCPP__ < 400 || __IBMC__ < 400 )
1023 // VA 3.0 still has trouble in here
1024 free((char *)buf);
1025 #endif
1026 // If not in debugging allocation mode, do the normal thing
1027 // so we don't leave any trace of ourselves in the node list.
1028 if (!wxDebugContext::GetDebugMode())
1029 {
1030 free((char *)buf);
1031 return;
1032 }
1033
1034 // Points to the start of the entire allocated area.
1035 char * startPointer = wxDebugContext::StartPos ((char *) buf);
1036 // Find the struct and make sure that it's identifiable.
1037 wxMemStruct * st = (wxMemStruct *) wxDebugContext::StructPos (startPointer);
1038
1039 if (! st->ValidateNode ())
1040 return;
1041
1042 // If this is the current checkpoint, we need to
1043 // move the checkpoint back so it points to a valid
1044 // node.
1045 if (st == wxDebugContext::checkPoint)
1046 wxDebugContext::checkPoint = wxDebugContext::checkPoint->m_prev;
1047
1048 if (! st->Unlink ())
1049 {
1050 st->ErrorMsg ("Unlinking deleted node");
1051 }
1052
1053 // Now put in the fill char into the id slot and the caller requested
1054 // memory locations.
1055 st->SetDeleted ();
1056 (void) memset (wxDebugContext::CallerMemPos (startPointer), MemFillChar,
1057 st->RequestSize ());
1058
1059 // Don't allow delayed freeing of memory in this version
1060 // if (!wxDebugContext::GetDelayFree())
1061 // free((void *)st);
1062 free((char *)st);
1063 }
1064
1065 // Trace: send output to the current debugging stream
1066 void wxTrace(const wxChar * ...)
1067 {
1068 #if 1
1069 wxFAIL_MSG(wxT("wxTrace is now obsolete. Please use wxDebugXXX instead."));
1070 #else
1071 va_list ap;
1072 static wxChar buffer[512];
1073
1074 va_start(ap, fmt);
1075
1076 #ifdef __WXMSW__
1077 wvsprintf(buffer,fmt,ap) ;
1078 #else
1079 vsprintf(buffer,fmt,ap) ;
1080 #endif
1081
1082 va_end(ap);
1083
1084 if (wxDebugContext::HasStream())
1085 {
1086 wxDebugContext::GetStream() << buffer;
1087 wxDebugContext::GetStream().flush();
1088 }
1089 else
1090 #ifdef __WXMSW__
1091 #ifdef __WIN32__
1092 OutputDebugString((LPCTSTR)buffer) ;
1093 #else
1094 OutputDebugString((const char*) buffer) ;
1095 #endif
1096 #else
1097 fprintf(stderr, buffer);
1098 #endif
1099 #endif
1100 }
1101
1102 // Trace with level
1103 void wxTraceLevel(int, const wxChar * ...)
1104 {
1105 #if 1
1106 wxFAIL_MSG(wxT("wxTrace is now obsolete. Please use wxDebugXXX instead."));
1107 #else
1108 if (wxDebugContext::GetLevel() < level)
1109 return;
1110
1111 va_list ap;
1112 static wxChar buffer[512];
1113
1114 va_start(ap, fmt);
1115
1116 #ifdef __WXMSW__
1117 wxWvsprintf(buffer,fmt,ap) ;
1118 #else
1119 vsprintf(buffer,fmt,ap) ;
1120 #endif
1121
1122 va_end(ap);
1123
1124 if (wxDebugContext::HasStream())
1125 {
1126 wxDebugContext::GetStream() << buffer;
1127 wxDebugContext::GetStream().flush();
1128 }
1129 else
1130 #ifdef __WXMSW__
1131 #ifdef __WIN32__
1132 OutputDebugString((LPCTSTR)buffer) ;
1133 #else
1134 OutputDebugString((const char*) buffer) ;
1135 #endif
1136 #else
1137 fprintf(stderr, buffer);
1138 #endif
1139 #endif
1140 }
1141
1142 #else // wxUSE_MEMORY_TRACING && defined(__WXDEBUG__)
1143 void wxTrace(const char *WXUNUSED(fmt) ...)
1144 {
1145 }
1146
1147 void wxTraceLevel(int WXUNUSED(level), const char *WXUNUSED(fmt) ...)
1148 {
1149 }
1150 #endif
1151