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