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