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