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