]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/common/memory.cpp
added an error message if a bitmap can't be addedto the image list
[wxWidgets.git] / src / common / memory.cpp
... / ...
CommitLineData
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__) && !defined( __MWERKS__ )
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*/
114void 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*/
125void 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*/
141int 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*/
163int 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*/
175int 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*/
201int 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*/
260int 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*/
288int 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*/
311void wxMemStruct::SetDeleted ()
312{
313 m_id = MemFillChar;
314}
315
316int 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*/
326void 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
366void 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*/
415int 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
464wxMemStruct *wxDebugContext::m_head = NULL;
465wxMemStruct *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
470streambuf *wxDebugContext::m_streamBuf = NULL;
471ostream *wxDebugContext::m_debugStream = NULL;
472
473bool wxDebugContext::m_checkPrevious = FALSE;
474int wxDebugContext::debugLevel = 1;
475bool wxDebugContext::debugOn = TRUE;
476wxMemStruct *wxDebugContext::checkPoint = NULL;
477
478wxDebugContext::wxDebugContext(void)
479{
480// m_streamBuf = new wxDebugStreamBuf;
481// m_debugStream = new ostream(m_streamBuf);
482}
483
484wxDebugContext::~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
494void 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
517bool 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
533bool wxDebugContext::SetStandardError(void)
534{
535 // Obsolete
536#if 0
537#if !defined(_WINDLL)
538 wxDebugStreamBuf *buf = new wxDebugStreamBuf;
539 ostream *stream = new ostream(m_streamBuf);
540 SetStream(stream, buf);
541 return TRUE;
542#else
543 return FALSE;
544#endif
545#endif
546 return FALSE;
547}
548
549
550/*
551 Work out the positions of the markers by creating an array of 2 markers
552 and comparing the addresses of the 2 elements. Use this number as the
553 alignment for markers.
554*/
555size_t wxDebugContext::CalcAlignment ()
556{
557 wxMarkerType ar[2];
558 return (char *) &ar[1] - (char *) &ar[0];
559}
560
561
562char * wxDebugContext::StructPos (const char * buf)
563{
564 return (char *) buf;
565}
566
567char * wxDebugContext::MidMarkerPos (const char * buf)
568{
569 return StructPos (buf) + PaddedSize (sizeof (wxMemStruct));
570}
571
572char * wxDebugContext::CallerMemPos (const char * buf)
573{
574 return MidMarkerPos (buf) + PaddedSize (sizeof(wxMarkerType));
575}
576
577
578char * wxDebugContext::EndMarkerPos (const char * buf, const size_t size)
579{
580 return CallerMemPos (buf) + PaddedSize (size);
581}
582
583
584/*
585 Slightly different as this takes a pointer to the start of the caller
586 requested region and returns a pointer to the start of the buffer.
587 */
588char * wxDebugContext::StartPos (const char * caller)
589{
590 return ((char *) (caller - wxDebugContext::PaddedSize (sizeof(wxMarkerType)) -
591 wxDebugContext::PaddedSize (sizeof (wxMemStruct))));
592}
593
594/*
595 We may need padding between various parts of the allocated memory.
596 Given a size of memory, this returns the amount of memory which should
597 be allocated in order to allow for alignment of the following object.
598
599 I don't know how portable this stuff is, but it seems to work for me at
600 the moment. It would be real nice if I knew more about this!
601*/
602size_t wxDebugContext::GetPadding (const size_t size)
603{
604 size_t pad = size % CalcAlignment ();
605 return (pad) ? sizeof(wxMarkerType) - pad : 0;
606}
607
608
609
610size_t wxDebugContext::PaddedSize (const size_t size)
611{
612 return size + GetPadding (size);
613}
614
615/*
616 Returns the total amount of memory which we need to get from the system
617 in order to satisfy a caller request. This includes space for the struct
618 plus markers and the caller's memory as well.
619*/
620size_t wxDebugContext::TotSize (const size_t reqSize)
621{
622 return (PaddedSize (sizeof (wxMemStruct)) + PaddedSize (reqSize) +
623 2 * sizeof(wxMarkerType));
624}
625
626
627/*
628 Traverse the list of nodes executing the given function on each node.
629*/
630void wxDebugContext::TraverseList (PmSFV func, wxMemStruct *from)
631{
632 if (!from)
633 from = wxDebugContext::GetHead ();
634
635 for (wxMemStruct * st = from; st != 0; st = st->m_next)
636 {
637 void* data = st->GetActualData();
638// if ((data != (void*)m_debugStream) && (data != (void*) m_streamBuf))
639 if (data != (void*) wxLog::GetActiveTarget())
640 {
641 (st->*func) ();
642 }
643 }
644}
645
646
647/*
648 Print out the list.
649 */
650bool wxDebugContext::PrintList (void)
651{
652#ifdef __WXDEBUG__
653// if (!HasStream())
654// return FALSE;
655
656 TraverseList ((PmSFV)&wxMemStruct::PrintNode, (checkPoint ? checkPoint->m_next : (wxMemStruct*)NULL));
657
658 return TRUE;
659#else
660 return FALSE;
661#endif
662}
663
664bool wxDebugContext::Dump(void)
665{
666#ifdef __WXDEBUG__
667// if (!HasStream())
668// return FALSE;
669
670 if (TRUE)
671 {
672 char* appName = "application";
673 wxString appNameStr("");
674 if (wxTheApp)
675 {
676 appNameStr = wxTheApp->GetAppName();
677 appName = (char*) (const char*) appNameStr;
678 wxLogDebug("----- Memory dump of %s at %s -----", appName, WXSTRINGCAST wxNow() );
679 }
680 else
681 {
682 wxLogDebug( "----- Memory dump -----" );
683 }
684 }
685 TraverseList ((PmSFV)&wxMemStruct::Dump, (checkPoint ? checkPoint->m_next : (wxMemStruct*)NULL));
686
687 wxLogDebug( "" );
688 wxLogDebug( "" );
689
690 return TRUE;
691#else
692 return FALSE;
693#endif
694}
695
696struct wxDebugStatsStruct
697{
698 long instanceCount;
699 long totalSize;
700 char *instanceClass;
701 wxDebugStatsStruct *next;
702};
703
704static wxDebugStatsStruct *FindStatsStruct(wxDebugStatsStruct *st, char *name)
705{
706 while (st)
707 {
708 if (strcmp(st->instanceClass, name) == 0)
709 return st;
710 st = st->next;
711 }
712 return NULL;
713}
714
715static wxDebugStatsStruct *InsertStatsStruct(wxDebugStatsStruct *head, wxDebugStatsStruct *st)
716{
717 st->next = head;
718 return st;
719}
720
721bool wxDebugContext::PrintStatistics(bool detailed)
722{
723#ifdef __WXDEBUG__
724// if (!HasStream())
725// return FALSE;
726
727 if (TRUE)
728 {
729 char* appName = "application";
730 wxString appNameStr("");
731 if (wxTheApp)
732 {
733 appNameStr = wxTheApp->GetAppName();
734 appName = (char*) (const char*) appNameStr;
735 wxLogDebug("----- Memory statistics of %s at %s -----", appName, WXSTRINGCAST wxNow() );
736 }
737 else
738 {
739 wxLogDebug( "----- Memory statistics -----" );
740 }
741 }
742
743 bool currentMode = GetDebugMode();
744 SetDebugMode(FALSE);
745
746 long noNonObjectNodes = 0;
747 long noObjectNodes = 0;
748 long totalSize = 0;
749
750 wxDebugStatsStruct *list = NULL;
751
752 wxMemStruct *from = (checkPoint ? checkPoint->m_next : (wxMemStruct*)NULL );
753 if (!from)
754 from = wxDebugContext::GetHead ();
755
756 wxMemStruct *st;
757 for (st = from; st != 0; st = st->m_next)
758 {
759 void* data = st->GetActualData();
760// if (detailed && (data != (void*)m_debugStream) && (data != (void*) m_streamBuf))
761 if (detailed && (data != (void*) wxLog::GetActiveTarget()))
762 {
763 char *className = "nonobject";
764 if (st->m_isObject && st->GetActualData())
765 {
766 wxObject *obj = (wxObject *)st->GetActualData();
767 if (obj->GetClassInfo()->GetClassName())
768 className = obj->GetClassInfo()->GetClassName();
769 }
770 wxDebugStatsStruct *stats = FindStatsStruct(list, className);
771 if (!stats)
772 {
773 stats = (wxDebugStatsStruct *)malloc(sizeof(wxDebugStatsStruct));
774 stats->instanceClass = className;
775 stats->instanceCount = 0;
776 stats->totalSize = 0;
777 list = InsertStatsStruct(list, stats);
778 }
779 stats->instanceCount ++;
780 stats->totalSize += st->RequestSize();
781 }
782
783// if ((data != (void*)m_debugStream) && (data != (void*) m_streamBuf))
784 if (data != (void*) wxLog::GetActiveTarget())
785 {
786 totalSize += st->RequestSize();
787 if (st->m_isObject)
788 noObjectNodes ++;
789 else
790 noNonObjectNodes ++;
791 }
792 }
793
794 if (detailed)
795 {
796 while (list)
797 {
798 wxLogDebug("%ld objects of class %s, total size %ld",
799 list->instanceCount, list->instanceClass, list->totalSize);
800 wxDebugStatsStruct *old = list;
801 list = old->next;
802 free((char *)old);
803 }
804 wxLogDebug("");
805 }
806
807 SetDebugMode(currentMode);
808
809 wxLogDebug("Number of object items: %ld", noObjectNodes);
810 wxLogDebug("Number of non-object items: %ld", noNonObjectNodes);
811 wxLogDebug("Total allocated size: %ld", totalSize);
812 wxLogDebug("");
813 wxLogDebug("");
814
815 return TRUE;
816#else
817 return FALSE;
818#endif
819}
820
821bool wxDebugContext::PrintClasses(void)
822{
823// if (!HasStream())
824// return FALSE;
825
826 if (TRUE)
827 {
828 char* appName = "application";
829 wxString appNameStr("");
830 if (wxTheApp)
831 {
832 appNameStr = wxTheApp->GetAppName();
833 appName = (char*) (const char*) appNameStr;
834 wxLogDebug("----- Classes in %s -----", appName);
835 }
836 }
837
838 int n = 0;
839 wxNode *node;
840 wxClassInfo *info;
841
842 wxClassInfo::sm_classTable->BeginFind();
843 node = wxClassInfo::sm_classTable->Next();
844 while (node)
845 {
846 info = (wxClassInfo *)node->Data();
847 if (info->GetClassName())
848 {
849 wxString msg(info->GetClassName());
850 msg += " ";
851
852 if (info->GetBaseClassName1() && !info->GetBaseClassName2())
853 {
854 msg += "is a ";
855 msg += info->GetBaseClassName1();
856 }
857 else if (info->GetBaseClassName1() && info->GetBaseClassName2())
858 {
859 msg += "is a ";
860 msg += info->GetBaseClassName1() ;
861 msg += ", ";
862 msg += info->GetBaseClassName2() ;
863 }
864 if (info->GetConstructor())
865 msg += ": dynamic";
866
867 wxLogDebug(msg);
868 }
869 node = wxClassInfo::sm_classTable->Next();
870 n ++;
871 }
872 wxLogDebug("");
873 wxLogDebug("There are %d classes derived from wxObject.", n);
874 wxLogDebug("");
875 wxLogDebug("");
876 return TRUE;
877}
878
879void wxDebugContext::SetCheckpoint(bool all)
880{
881 if (all)
882 checkPoint = NULL;
883 else
884 checkPoint = m_tail;
885}
886
887// Checks all nodes since checkpoint, or since start.
888int wxDebugContext::Check(bool checkAll)
889{
890 int nFailures = 0;
891
892 wxMemStruct *from = (checkPoint ? checkPoint->m_next : (wxMemStruct*)NULL );
893 if (!from || checkAll)
894 from = wxDebugContext::GetHead ();
895
896 for (wxMemStruct * st = from; st != 0; st = st->m_next)
897 {
898 if (st->AssertIt ())
899 nFailures += st->CheckBlock ();
900 else
901 return -1;
902 }
903
904 return nFailures;
905}
906
907// Count the number of non-wxDebugContext-related objects
908// that are outstanding
909int wxDebugContext::CountObjectsLeft(bool sinceCheckpoint)
910{
911 int n = 0;
912
913 wxMemStruct *from = NULL;
914 if (sinceCheckpoint && checkPoint)
915 from = checkPoint->m_next;
916 else
917 from = wxDebugContext::GetHead () ;
918
919 for (wxMemStruct * st = from; st != 0; st = st->m_next)
920 {
921 void* data = st->GetActualData();
922// if ((data != (void*)m_debugStream) && (data != (void*) m_streamBuf))
923 if (data != (void*) wxLog::GetActiveTarget())
924 n ++;
925 }
926
927 return n ;
928}
929
930/*
931 The global operator new used for everything apart from getting
932 dynamic storage within this function itself.
933*/
934
935// We'll only do malloc and free for the moment: leave the interesting
936// stuff for the wxObject versions.
937
938#if defined(__WXDEBUG__) && wxUSE_GLOBAL_MEMORY_OPERATORS
939
940#ifdef new
941#undef new
942#endif
943
944// Seems OK all of a sudden. Maybe to do with linking with multithreaded library?
945#if 0 // def _MSC_VER
946#define NO_DEBUG_ALLOCATION
947#endif
948
949// Unfortunately ~wxDebugStreamBuf doesn't work (VC++ 5) when we enable the debugging
950// code. I have no idea why. In BC++ 4.5, we have a similar problem the debug
951// stream myseriously changing pointer address between being passed from SetFile to SetStream.
952// See docs/msw/issues.txt.
953void * operator new (size_t size, char * fileName, int lineNum)
954{
955#ifdef NO_DEBUG_ALLOCATION
956 return malloc(size);
957#else
958 return wxDebugAlloc(size, fileName, lineNum, FALSE, FALSE);
959#endif
960}
961
962// Added JACS 25/11/98
963void * operator new (size_t size)
964{
965#ifdef NO_DEBUG_ALLOCATION
966 return malloc(size);
967#else
968 return wxDebugAlloc(size, NULL, 0, FALSE);
969#endif
970}
971
972#if wxUSE_ARRAY_MEMORY_OPERATORS
973void * operator new[] (size_t size)
974{
975#ifdef NO_DEBUG_ALLOCATION
976 return malloc(size);
977#else
978 return wxDebugAlloc(size, NULL, 0, FALSE, TRUE);
979#endif
980}
981#endif
982
983#if wxUSE_ARRAY_MEMORY_OPERATORS
984void * operator new[] (size_t size, char * fileName, int lineNum)
985{
986#ifdef NO_DEBUG_ALLOCATION
987 return malloc(size);
988#else
989 return wxDebugAlloc(size, fileName, lineNum, FALSE, TRUE);
990#endif
991}
992#endif
993
994void operator delete (void * buf)
995{
996#ifdef NO_DEBUG_ALLOCATION
997 free((char*) buf);
998#else
999 wxDebugFree(buf);
1000#endif
1001}
1002
1003// VC++ 6.0
1004#if _MSC_VER >= 1200
1005void operator delete(void* pData, char* /* fileName */, int /* lineNum */)
1006{
1007// ::operator delete(pData);
1008 // JACS 21/11/1998: surely we need to call wxDebugFree?
1009 wxDebugFree(pData, FALSE);
1010}
1011// New operator 21/11/1998
1012void operator delete[](void* pData, char* /* fileName */, int /* lineNum */)
1013{
1014 wxDebugFree(pData, TRUE);
1015}
1016#endif
1017
1018#if wxUSE_ARRAY_MEMORY_OPERATORS
1019
1020void operator delete[] (void * buf)
1021{
1022#ifdef NO_DEBUG_ALLOCATION
1023 free((char*) buf);
1024#else
1025 wxDebugFree(buf, TRUE);
1026#endif
1027}
1028#endif
1029
1030#endif
1031
1032// TODO: store whether this is a vector or not.
1033void * wxDebugAlloc(size_t size, char * fileName, int lineNum, bool isObject, bool WXUNUSED(isVect) )
1034{
1035 // If not in debugging allocation mode, do the normal thing
1036 // so we don't leave any trace of ourselves in the node list.
1037
1038 if (!wxDebugContext::GetDebugMode())
1039 {
1040 return (void *)malloc(size);
1041 }
1042
1043 int totSize = wxDebugContext::TotSize (size);
1044 char * buf = (char *) malloc(totSize);
1045 if (!buf) {
1046 wxLogDebug("Call to malloc (%ld) failed.", (long)size);
1047 return 0;
1048 }
1049 wxMemStruct * st = (wxMemStruct *)buf;
1050 st->m_firstMarker = MemStartCheck;
1051 st->m_reqSize = size;
1052 st->m_fileName = fileName;
1053 st->m_lineNum = lineNum;
1054 st->m_id = MemStructId;
1055 st->m_prev = 0;
1056 st->m_next = 0;
1057 st->m_isObject = isObject;
1058
1059 // Errors from Append() shouldn't really happen - but just in case!
1060 if (st->Append () == 0) {
1061 st->ErrorMsg ("Trying to append new node");
1062 }
1063
1064 if (wxDebugContext::GetCheckPrevious ()) {
1065 if (st->CheckAllPrevious () < 0) {
1066 st->ErrorMsg ("Checking previous nodes");
1067 }
1068 }
1069
1070 // Set up the extra markers at the middle and end.
1071 char * ptr = wxDebugContext::MidMarkerPos (buf);
1072 * (wxMarkerType *) ptr = MemMidCheck;
1073 ptr = wxDebugContext::EndMarkerPos (buf, size);
1074 * (wxMarkerType *) ptr = MemEndCheck;
1075
1076 // pointer returned points to the start of the caller's
1077 // usable area.
1078 void *m_actualData = (void *) wxDebugContext::CallerMemPos (buf);
1079 st->m_actualData = m_actualData;
1080
1081 return m_actualData;
1082}
1083
1084// TODO: check whether was allocated as a vector
1085void wxDebugFree(void * buf, bool WXUNUSED(isVect) )
1086{
1087 if (!buf)
1088 return;
1089
1090 // If not in debugging allocation mode, do the normal thing
1091 // so we don't leave any trace of ourselves in the node list.
1092 if (!wxDebugContext::GetDebugMode())
1093 {
1094 free((char *)buf);
1095 return;
1096 }
1097
1098 // Points to the start of the entire allocated area.
1099 char * startPointer = wxDebugContext::StartPos ((char *) buf);
1100 // Find the struct and make sure that it's identifiable.
1101 wxMemStruct * st = (wxMemStruct *) wxDebugContext::StructPos (startPointer);
1102
1103 if (! st->ValidateNode ())
1104 return;
1105
1106 // If this is the current checkpoint, we need to
1107 // move the checkpoint back so it points to a valid
1108 // node.
1109 if (st == wxDebugContext::checkPoint)
1110 wxDebugContext::checkPoint = wxDebugContext::checkPoint->m_prev;
1111
1112 if (! st->Unlink ())
1113 {
1114 st->ErrorMsg ("Unlinking deleted node");
1115 }
1116
1117 // Now put in the fill char into the id slot and the caller requested
1118 // memory locations.
1119 st->SetDeleted ();
1120 (void) memset (wxDebugContext::CallerMemPos (startPointer), MemFillChar,
1121 st->RequestSize ());
1122
1123 // Don't allow delayed freeing of memory in this version
1124// if (!wxDebugContext::GetDelayFree())
1125// free((void *)st);
1126 free((char *)st);
1127}
1128
1129// Trace: send output to the current debugging stream
1130void wxTrace(const char *fmt ...)
1131{
1132 va_list ap;
1133 static char buffer[512];
1134
1135 va_start(ap, fmt);
1136
1137#ifdef __WXMSW__
1138 wvsprintf(buffer,fmt,ap) ;
1139#else
1140 vsprintf(buffer,fmt,ap) ;
1141#endif
1142
1143 va_end(ap);
1144
1145 if (wxDebugContext::HasStream())
1146 {
1147 wxDebugContext::GetStream() << buffer;
1148 wxDebugContext::GetStream().flush();
1149 }
1150 else
1151#ifdef __WXMSW__
1152 OutputDebugString((LPCSTR)buffer) ;
1153#else
1154 fprintf(stderr, buffer);
1155#endif
1156}
1157
1158// Trace with level
1159void wxTraceLevel(int level, const char *fmt ...)
1160{
1161 if (wxDebugContext::GetLevel() < level)
1162 return;
1163
1164 va_list ap;
1165 static char buffer[512];
1166
1167 va_start(ap, fmt);
1168
1169#ifdef __WXMSW__
1170 wvsprintf(buffer,fmt,ap) ;
1171#else
1172 vsprintf(buffer,fmt,ap) ;
1173#endif
1174
1175 va_end(ap);
1176
1177 if (wxDebugContext::HasStream())
1178 {
1179 wxDebugContext::GetStream() << buffer;
1180 wxDebugContext::GetStream().flush();
1181 }
1182 else
1183#ifdef __WXMSW__
1184 OutputDebugString((LPCSTR)buffer) ;
1185#else
1186 fprintf(stderr, buffer);
1187#endif
1188}
1189
1190#else // wxUSE_MEMORY_TRACING && defined(__WXDEBUG__)
1191void wxTrace(const char *WXUNUSED(fmt) ...)
1192{
1193}
1194
1195void wxTraceLevel(int WXUNUSED(level), const char *WXUNUSED(fmt) ...)
1196{
1197}
1198#endif
1199