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