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