]> git.saurik.com Git - wxWidgets.git/blob - src/common/memory.cpp
wxChoice/wxComboBox background colour change (to get back to where we were);
[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 wxLogDebug(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 wxLogDebug(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 wxLogDebug(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 wxLogDebug(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 wxLogDebug(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 wxLogDebug(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 wxLogDebug(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 wxDebugContext::wxDebugContext(void)
477 {
478 // m_streamBuf = new wxDebugStreamBuf;
479 // m_debugStream = new ostream(m_streamBuf);
480 }
481
482 wxDebugContext::~wxDebugContext(void)
483 {
484 SetStream(NULL, NULL);
485 }
486
487 /*
488 * It's bizarre, but with BC++ 4.5, the value of str changes
489 * between SetFile and SetStream.
490 */
491
492 void wxDebugContext::SetStream(ostream *str, streambuf *buf)
493 {
494 if (m_debugStream)
495 {
496 m_debugStream->flush();
497 delete m_debugStream;
498 }
499 m_debugStream = NULL;
500
501 // Not allowed in Watcom (~streambuf is protected).
502 // Is this trying to say something significant to us??
503 #ifndef __WATCOMC__
504 if (m_streamBuf)
505 {
506 streambuf* oldBuf = m_streamBuf;
507 m_streamBuf = NULL;
508 delete oldBuf;
509 }
510 #endif
511 m_streamBuf = buf;
512 m_debugStream = str;
513 }
514
515 bool wxDebugContext::SetFile(const wxString& file)
516 {
517 ofstream *str = new ofstream(file.fn_str());
518
519 if (str->bad())
520 {
521 delete str;
522 return FALSE;
523 }
524 else
525 {
526 SetStream(str);
527 return TRUE;
528 }
529 }
530
531 bool wxDebugContext::SetStandardError(void)
532 {
533 // Obsolete
534 #if 0
535 #if !defined(_WINDLL)
536 wxDebugStreamBuf *buf = new wxDebugStreamBuf;
537 ostream *stream = new ostream(m_streamBuf);
538 SetStream(stream, buf);
539 return TRUE;
540 #else
541 return FALSE;
542 #endif
543 #endif
544 return FALSE;
545 }
546
547
548 /*
549 Work out the positions of the markers by creating an array of 2 markers
550 and comparing the addresses of the 2 elements. Use this number as the
551 alignment for markers.
552 */
553 size_t wxDebugContext::CalcAlignment ()
554 {
555 wxMarkerType ar[2];
556 return (char *) &ar[1] - (char *) &ar[0];
557 }
558
559
560 char * wxDebugContext::StructPos (const char * buf)
561 {
562 return (char *) buf;
563 }
564
565 char * wxDebugContext::MidMarkerPos (const char * buf)
566 {
567 return StructPos (buf) + PaddedSize (sizeof (wxMemStruct));
568 }
569
570 char * wxDebugContext::CallerMemPos (const char * buf)
571 {
572 return MidMarkerPos (buf) + PaddedSize (sizeof(wxMarkerType));
573 }
574
575
576 char * wxDebugContext::EndMarkerPos (const char * buf, const size_t size)
577 {
578 return CallerMemPos (buf) + PaddedSize (size);
579 }
580
581
582 /*
583 Slightly different as this takes a pointer to the start of the caller
584 requested region and returns a pointer to the start of the buffer.
585 */
586 char * wxDebugContext::StartPos (const char * caller)
587 {
588 return ((char *) (caller - wxDebugContext::PaddedSize (sizeof(wxMarkerType)) -
589 wxDebugContext::PaddedSize (sizeof (wxMemStruct))));
590 }
591
592 /*
593 We may need padding between various parts of the allocated memory.
594 Given a size of memory, this returns the amount of memory which should
595 be allocated in order to allow for alignment of the following object.
596
597 I don't know how portable this stuff is, but it seems to work for me at
598 the moment. It would be real nice if I knew more about this!
599 */
600 size_t wxDebugContext::GetPadding (const size_t size)
601 {
602 size_t pad = size % CalcAlignment ();
603 return (pad) ? sizeof(wxMarkerType) - pad : 0;
604 }
605
606
607
608 size_t wxDebugContext::PaddedSize (const size_t size)
609 {
610 return size + GetPadding (size);
611 }
612
613 /*
614 Returns the total amount of memory which we need to get from the system
615 in order to satisfy a caller request. This includes space for the struct
616 plus markers and the caller's memory as well.
617 */
618 size_t wxDebugContext::TotSize (const size_t reqSize)
619 {
620 return (PaddedSize (sizeof (wxMemStruct)) + PaddedSize (reqSize) +
621 2 * sizeof(wxMarkerType));
622 }
623
624
625 /*
626 Traverse the list of nodes executing the given function on each node.
627 */
628 void wxDebugContext::TraverseList (PmSFV func, wxMemStruct *from)
629 {
630 if (!from)
631 from = wxDebugContext::GetHead ();
632
633 for (wxMemStruct * st = from; st != 0; st = st->m_next)
634 {
635 void* data = st->GetActualData();
636 // if ((data != (void*)m_debugStream) && (data != (void*) m_streamBuf))
637 if (data != (void*) wxLog::GetActiveTarget())
638 {
639 (st->*func) ();
640 }
641 }
642 }
643
644
645 /*
646 Print out the list.
647 */
648 bool wxDebugContext::PrintList (void)
649 {
650 #ifdef __WXDEBUG__
651 // if (!HasStream())
652 // return FALSE;
653
654 TraverseList ((PmSFV)&wxMemStruct::PrintNode, (checkPoint ? checkPoint->m_next : (wxMemStruct*)NULL));
655
656 return TRUE;
657 #else
658 return FALSE;
659 #endif
660 }
661
662 bool wxDebugContext::Dump(void)
663 {
664 #ifdef __WXDEBUG__
665 // if (!HasStream())
666 // return FALSE;
667
668 // if (TRUE)
669 {
670 wxChar* appName = wxT("application");
671 wxString appNameStr("");
672 if (wxTheApp)
673 {
674 appNameStr = wxTheApp->GetAppName();
675 appName = WXSTRINGCAST appNameStr;
676 wxLogDebug(wxT("----- Memory dump of %s at %s -----"), appName, WXSTRINGCAST wxNow() );
677 }
678 else
679 {
680 wxLogDebug( wxT("----- Memory dump -----") );
681 }
682 }
683 TraverseList ((PmSFV)&wxMemStruct::Dump, (checkPoint ? checkPoint->m_next : (wxMemStruct*)NULL));
684
685 wxLogDebug( wxT("") );
686 wxLogDebug( wxT("") );
687
688 return TRUE;
689 #else
690 return FALSE;
691 #endif
692 }
693
694 struct wxDebugStatsStruct
695 {
696 long instanceCount;
697 long totalSize;
698 wxChar *instanceClass;
699 wxDebugStatsStruct *next;
700 };
701
702 static wxDebugStatsStruct *FindStatsStruct(wxDebugStatsStruct *st, wxChar *name)
703 {
704 while (st)
705 {
706 if (wxStrcmp(st->instanceClass, name) == 0)
707 return st;
708 st = st->next;
709 }
710 return NULL;
711 }
712
713 static wxDebugStatsStruct *InsertStatsStruct(wxDebugStatsStruct *head, wxDebugStatsStruct *st)
714 {
715 st->next = head;
716 return st;
717 }
718
719 bool wxDebugContext::PrintStatistics(bool detailed)
720 {
721 #ifdef __WXDEBUG__
722 // if (!HasStream())
723 // return FALSE;
724
725 // if (TRUE)
726 {
727 wxChar* appName = wxT("application");
728 wxString appNameStr(wxT(""));
729 if (wxTheApp)
730 {
731 appNameStr = wxTheApp->GetAppName();
732 appName = WXSTRINGCAST appNameStr;
733 wxLogDebug(wxT("----- Memory statistics of %s at %s -----"), appName, WXSTRINGCAST wxNow() );
734 }
735 else
736 {
737 wxLogDebug( wxT("----- Memory statistics -----") );
738 }
739 }
740
741 bool currentMode = GetDebugMode();
742 SetDebugMode(FALSE);
743
744 long noNonObjectNodes = 0;
745 long noObjectNodes = 0;
746 long totalSize = 0;
747
748 wxDebugStatsStruct *list = NULL;
749
750 wxMemStruct *from = (checkPoint ? checkPoint->m_next : (wxMemStruct*)NULL );
751 if (!from)
752 from = wxDebugContext::GetHead ();
753
754 wxMemStruct *st;
755 for (st = from; st != 0; st = st->m_next)
756 {
757 void* data = st->GetActualData();
758 // if (detailed && (data != (void*)m_debugStream) && (data != (void*) m_streamBuf))
759 if (detailed && (data != (void*) wxLog::GetActiveTarget()))
760 {
761 wxChar *className = wxT("nonobject");
762 if (st->m_isObject && st->GetActualData())
763 {
764 wxObject *obj = (wxObject *)st->GetActualData();
765 if (obj->GetClassInfo()->GetClassName())
766 className = obj->GetClassInfo()->GetClassName();
767 }
768 wxDebugStatsStruct *stats = FindStatsStruct(list, className);
769 if (!stats)
770 {
771 stats = (wxDebugStatsStruct *)malloc(sizeof(wxDebugStatsStruct));
772 stats->instanceClass = className;
773 stats->instanceCount = 0;
774 stats->totalSize = 0;
775 list = InsertStatsStruct(list, stats);
776 }
777 stats->instanceCount ++;
778 stats->totalSize += st->RequestSize();
779 }
780
781 // if ((data != (void*)m_debugStream) && (data != (void*) m_streamBuf))
782 if (data != (void*) wxLog::GetActiveTarget())
783 {
784 totalSize += st->RequestSize();
785 if (st->m_isObject)
786 noObjectNodes ++;
787 else
788 noNonObjectNodes ++;
789 }
790 }
791
792 if (detailed)
793 {
794 while (list)
795 {
796 wxLogDebug(wxT("%ld objects of class %s, total size %ld"),
797 list->instanceCount, list->instanceClass, list->totalSize);
798 wxDebugStatsStruct *old = list;
799 list = old->next;
800 free((char *)old);
801 }
802 wxLogDebug(wxT(""));
803 }
804
805 SetDebugMode(currentMode);
806
807 wxLogDebug(wxT("Number of object items: %ld"), noObjectNodes);
808 wxLogDebug(wxT("Number of non-object items: %ld"), noNonObjectNodes);
809 wxLogDebug(wxT("Total allocated size: %ld"), totalSize);
810 wxLogDebug(wxT(""));
811 wxLogDebug(wxT(""));
812
813 return TRUE;
814 #else
815 return FALSE;
816 #endif
817 }
818
819 bool wxDebugContext::PrintClasses(void)
820 {
821 // if (!HasStream())
822 // return FALSE;
823
824 // if (TRUE)
825 {
826 wxChar* appName = wxT("application");
827 wxString appNameStr(wxT(""));
828 if (wxTheApp)
829 {
830 appNameStr = wxTheApp->GetAppName();
831 appName = WXSTRINGCAST appNameStr;
832 wxLogDebug(wxT("----- Classes in %s -----"), appName);
833 }
834 }
835
836 int n = 0;
837 wxNode *node;
838 wxClassInfo *info;
839
840 wxClassInfo::sm_classTable->BeginFind();
841 node = wxClassInfo::sm_classTable->Next();
842 while (node)
843 {
844 info = (wxClassInfo *)node->Data();
845 if (info->GetClassName())
846 {
847 wxString msg(info->GetClassName());
848 msg += wxT(" ");
849
850 if (info->GetBaseClassName1() && !info->GetBaseClassName2())
851 {
852 msg += wxT("is a ");
853 msg += info->GetBaseClassName1();
854 }
855 else if (info->GetBaseClassName1() && info->GetBaseClassName2())
856 {
857 msg += wxT("is a ");
858 msg += info->GetBaseClassName1() ;
859 msg += wxT(", ");
860 msg += info->GetBaseClassName2() ;
861 }
862 if (info->GetConstructor())
863 msg += wxT(": dynamic");
864
865 wxLogDebug(msg);
866 }
867 node = wxClassInfo::sm_classTable->Next();
868 n ++;
869 }
870 wxLogDebug(wxT(""));
871 wxLogDebug(wxT("There are %d classes derived from wxObject."), n);
872 wxLogDebug(wxT(""));
873 wxLogDebug(wxT(""));
874 return TRUE;
875 }
876
877 void wxDebugContext::SetCheckpoint(bool all)
878 {
879 if (all)
880 checkPoint = NULL;
881 else
882 checkPoint = m_tail;
883 }
884
885 // Checks all nodes since checkpoint, or since start.
886 int wxDebugContext::Check(bool checkAll)
887 {
888 int nFailures = 0;
889
890 wxMemStruct *from = (checkPoint ? checkPoint->m_next : (wxMemStruct*)NULL );
891 if (!from || checkAll)
892 from = wxDebugContext::GetHead ();
893
894 for (wxMemStruct * st = from; st != 0; st = st->m_next)
895 {
896 if (st->AssertIt ())
897 nFailures += st->CheckBlock ();
898 else
899 return -1;
900 }
901
902 return nFailures;
903 }
904
905 // Count the number of non-wxDebugContext-related objects
906 // that are outstanding
907 int wxDebugContext::CountObjectsLeft(bool sinceCheckpoint)
908 {
909 int n = 0;
910
911 wxMemStruct *from = NULL;
912 if (sinceCheckpoint && checkPoint)
913 from = checkPoint->m_next;
914 else
915 from = wxDebugContext::GetHead () ;
916
917 for (wxMemStruct * st = from; st != 0; st = st->m_next)
918 {
919 void* data = st->GetActualData();
920 // if ((data != (void*)m_debugStream) && (data != (void*) m_streamBuf))
921 if (data != (void*) wxLog::GetActiveTarget())
922 n ++;
923 }
924
925 return n ;
926 }
927
928 /*
929 The global operator new used for everything apart from getting
930 dynamic storage within this function itself.
931 */
932
933 // We'll only do malloc and free for the moment: leave the interesting
934 // stuff for the wxObject versions.
935
936 #if defined(__WXDEBUG__) && wxUSE_GLOBAL_MEMORY_OPERATORS
937
938 #ifdef new
939 #undef new
940 #endif
941
942 // Seems OK all of a sudden. Maybe to do with linking with multithreaded library?
943 #if 0 // def __VISUALC__
944 #define NO_DEBUG_ALLOCATION
945 #endif
946
947 // Unfortunately ~wxDebugStreamBuf doesn't work (VC++ 5) when we enable the debugging
948 // code. I have no idea why. In BC++ 4.5, we have a similar problem the debug
949 // stream myseriously changing pointer address between being passed from SetFile to SetStream.
950 // See docs/msw/issues.txt.
951 void * operator new (size_t size, wxChar * fileName, int lineNum)
952 {
953 #ifdef NO_DEBUG_ALLOCATION
954 return malloc(size);
955 #else
956 return wxDebugAlloc(size, fileName, lineNum, FALSE, FALSE);
957 #endif
958 }
959
960 // Added JACS 25/11/98
961 void * operator new (size_t size)
962 {
963 #ifdef NO_DEBUG_ALLOCATION
964 return malloc(size);
965 #else
966 return wxDebugAlloc(size, NULL, 0, FALSE);
967 #endif
968 }
969
970 #if wxUSE_ARRAY_MEMORY_OPERATORS
971 void * operator new[] (size_t size)
972 {
973 #ifdef NO_DEBUG_ALLOCATION
974 return malloc(size);
975 #else
976 return wxDebugAlloc(size, NULL, 0, FALSE, TRUE);
977 #endif
978 }
979 #endif
980
981 #if wxUSE_ARRAY_MEMORY_OPERATORS
982 void * operator new[] (size_t size, wxChar * fileName, int lineNum)
983 {
984 #ifdef NO_DEBUG_ALLOCATION
985 return malloc(size);
986 #else
987 return wxDebugAlloc(size, fileName, lineNum, FALSE, TRUE);
988 #endif
989 }
990 #endif
991
992 #if !defined(__VISAGECPP__) // already defines this by default
993 void operator delete (void * buf)
994 {
995 #ifdef NO_DEBUG_ALLOCATION
996 free((char*) buf);
997 #else
998 wxDebugFree(buf);
999 #endif
1000 }
1001 #endif
1002
1003 // VC++ 6.0
1004 #if defined(__VISUALC__) && (__VISUALC__ >= 1200)
1005 void operator delete(void* pData, wxChar* /* 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
1012 void operator delete[](void* pData, char* /* fileName */, int /* lineNum */)
1013 {
1014 wxDebugFree(pData, TRUE);
1015 }
1016 #endif
1017
1018 #if wxUSE_ARRAY_MEMORY_OPERATORS
1019
1020 void 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.
1033 void * wxDebugAlloc(size_t size, wxChar * 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(wxT("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
1085 void 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
1130 void wxTrace(const wxChar *fmt ...)
1131 {
1132 va_list ap;
1133 static wxChar 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 #ifdef __WIN32__
1153 OutputDebugString((LPCTSTR)buffer) ;
1154 #else
1155 OutputDebugString((const char*) buffer) ;
1156 #endif
1157 #else
1158 fprintf(stderr, buffer);
1159 #endif
1160 }
1161
1162 // Trace with level
1163 void wxTraceLevel(int level, const wxChar *fmt ...)
1164 {
1165 if (wxDebugContext::GetLevel() < level)
1166 return;
1167
1168 va_list ap;
1169 static wxChar buffer[512];
1170
1171 va_start(ap, fmt);
1172
1173 #ifdef __WXMSW__
1174 wvsprintf(buffer,fmt,ap) ;
1175 #else
1176 vsprintf(buffer,fmt,ap) ;
1177 #endif
1178
1179 va_end(ap);
1180
1181 if (wxDebugContext::HasStream())
1182 {
1183 wxDebugContext::GetStream() << buffer;
1184 wxDebugContext::GetStream().flush();
1185 }
1186 else
1187 #ifdef __WXMSW__
1188 #ifdef __WIN32__
1189 OutputDebugString((LPCTSTR)buffer) ;
1190 #else
1191 OutputDebugString((const char*) buffer) ;
1192 #endif
1193 #else
1194 fprintf(stderr, buffer);
1195 #endif
1196 }
1197
1198 #else // wxUSE_MEMORY_TRACING && defined(__WXDEBUG__)
1199 void wxTrace(const char *WXUNUSED(fmt) ...)
1200 {
1201 }
1202
1203 void wxTraceLevel(int WXUNUSED(level), const char *WXUNUSED(fmt) ...)
1204 {
1205 }
1206 #endif
1207