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