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