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