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