]> git.saurik.com Git - wxWidgets.git/blob - src/common/memory.cpp
set error to GSOCK_TIMEOUT if the socket timed out (modified and extended patch 1303554)
[wxWidgets.git] / src / common / memory.cpp
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 */
110 void 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 */
119 void 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 */
133 int 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 */
155 int 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 */
167 int 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 */
193 int 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 */
252 int 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 */
280 int 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 */
303 void wxMemStruct::SetDeleted ()
304 {
305 m_id = MemFillChar;
306 }
307
308 int 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 */
318 void 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
358 void 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 */
407 int 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
456 wxMemStruct *wxDebugContext::m_head = NULL;
457 wxMemStruct *wxDebugContext::m_tail = NULL;
458
459 bool wxDebugContext::m_checkPrevious = false;
460 int wxDebugContext::debugLevel = 1;
461 bool wxDebugContext::debugOn = true;
462 wxMemStruct *wxDebugContext::checkPoint = NULL;
463
464 // For faster alignment calculation
465 static wxMarkerType markerCalc[2];
466 int wxDebugContext::m_balign = (int)((char *)&markerCalc[1] - (char*)&markerCalc[0]);
467 int wxDebugContext::m_balignmask = (int)((char *)&markerCalc[1] - (char*)&markerCalc[0]) - 1;
468
469 wxDebugContext::wxDebugContext(void)
470 {
471 }
472
473 wxDebugContext::~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 */
482 size_t wxDebugContext::CalcAlignment ()
483 {
484 wxMarkerType ar[2];
485 return (char *) &ar[1] - (char *) &ar[0];
486 }
487
488
489 char * wxDebugContext::StructPos (const char * buf)
490 {
491 return (char *) buf;
492 }
493
494 char * wxDebugContext::MidMarkerPos (const char * buf)
495 {
496 return StructPos (buf) + PaddedSize (sizeof (wxMemStruct));
497 }
498
499 char * wxDebugContext::CallerMemPos (const char * buf)
500 {
501 return MidMarkerPos (buf) + PaddedSize (sizeof(wxMarkerType));
502 }
503
504
505 char * 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 */
515 char * 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 */
532 size_t wxDebugContext::GetPadding (const size_t size)
533 {
534 size_t pad = size % CalcAlignment ();
535 return (pad) ? sizeof(wxMarkerType) - pad : 0;
536 }
537
538 size_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 */
556 size_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 */
566 void 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 */
587 bool 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
598 bool 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__
628 struct wxDebugStatsStruct
629 {
630 long instanceCount;
631 long totalSize;
632 wxChar *instanceClass;
633 wxDebugStatsStruct *next;
634 };
635
636 static 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
647 static wxDebugStatsStruct *InsertStatsStruct(wxDebugStatsStruct *head, wxDebugStatsStruct *st)
648 {
649 st->next = head;
650 return st;
651 }
652 #endif
653
654 bool 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
749 bool 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
803 void 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.
812 int 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
833 int 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
854 void 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
879 static bool memSectionOk = false;
880
881 class MemoryCriticalSection : public wxCriticalSection
882 {
883 public:
884 MemoryCriticalSection() {
885 memSectionOk = true;
886 }
887 ~MemoryCriticalSection() {
888 memSectionOk = false;
889 }
890 };
891
892 class MemoryCriticalSectionLocker
893 {
894 public:
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
899 private:
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
908 static MemoryCriticalSection memLocker;
909
910 #endif
911
912 #if !(defined(__WXMSW__) && (defined(WXUSINGDLL) || defined(WXMAKINGDLL_BASE)))
913 #ifdef __WXDEBUG__
914 #if wxUSE_GLOBAL_MEMORY_OPERATORS
915 void * operator new (size_t size, wxChar * fileName, int lineNum)
916 {
917 return wxDebugAlloc(size, fileName, lineNum, false, false);
918 }
919
920 void * operator new (size_t size)
921 {
922 return wxDebugAlloc(size, NULL, 0, false);
923 }
924
925 void operator delete (void * buf)
926 {
927 wxDebugFree(buf, false);
928 }
929
930 #if wxUSE_ARRAY_MEMORY_OPERATORS
931 void * operator new[] (size_t size)
932 {
933 return wxDebugAlloc(size, NULL, 0, false, true);
934 }
935
936 void * operator new[] (size_t size, wxChar * fileName, int lineNum)
937 {
938 return wxDebugAlloc(size, fileName, lineNum, false, true);
939 }
940
941 void operator delete[] (void * buf)
942 {
943 wxDebugFree(buf, true);
944 }
945 #endif // wxUSE_ARRAY_MEMORY_OPERATORS
946 #endif // !(defined(__WXMSW__) && (defined(WXUSINGDLL) || defined(WXMAKINGDLL_BASE)))
947 #endif // wxUSE_GLOBAL_MEMORY_OPERATORS
948
949 // TODO: store whether this is a vector or not.
950 void * wxDebugAlloc(size_t size, wxChar * fileName, int lineNum, bool isObject, bool WXUNUSED(isVect) )
951 {
952 #if USE_THREADSAFE_MEMORY_ALLOCATION
953 MemoryCriticalSectionLocker lock(memLocker);
954 #endif
955
956 // If not in debugging allocation mode, do the normal thing
957 // so we don't leave any trace of ourselves in the node list.
958
959 #if defined(__VISAGECPP__) && (__IBMCPP__ < 400 || __IBMC__ < 400 )
960 // VA 3.0 still has trouble in here
961 return (void *)malloc(size);
962 #endif
963 if (!wxDebugContext::GetDebugMode())
964 {
965 return (void *)malloc(size);
966 }
967
968 int totSize = wxDebugContext::TotSize (size);
969 char * buf = (char *) malloc(totSize);
970 if (!buf) {
971 wxLogMessage(wxT("Call to malloc (%ld) failed."), (long)size);
972 return 0;
973 }
974 wxMemStruct * st = (wxMemStruct *)buf;
975 st->m_firstMarker = MemStartCheck;
976 st->m_reqSize = size;
977 st->m_fileName = fileName;
978 st->m_lineNum = lineNum;
979 st->m_id = MemStructId;
980 st->m_prev = 0;
981 st->m_next = 0;
982 st->m_isObject = isObject;
983
984 // Errors from Append() shouldn't really happen - but just in case!
985 if (st->Append () == 0) {
986 st->ErrorMsg ("Trying to append new node");
987 }
988
989 if (wxDebugContext::GetCheckPrevious ()) {
990 if (st->CheckAllPrevious () < 0) {
991 st->ErrorMsg ("Checking previous nodes");
992 }
993 }
994
995 // Set up the extra markers at the middle and end.
996 char * ptr = wxDebugContext::MidMarkerPos (buf);
997 * (wxMarkerType *) ptr = MemMidCheck;
998 ptr = wxDebugContext::EndMarkerPos (buf, size);
999 * (wxMarkerType *) ptr = MemEndCheck;
1000
1001 // pointer returned points to the start of the caller's
1002 // usable area.
1003 void *m_actualData = (void *) wxDebugContext::CallerMemPos (buf);
1004 st->m_actualData = m_actualData;
1005
1006 return m_actualData;
1007 }
1008
1009 // TODO: check whether was allocated as a vector
1010 void wxDebugFree(void * buf, bool WXUNUSED(isVect) )
1011 {
1012 #if USE_THREADSAFE_MEMORY_ALLOCATION
1013 MemoryCriticalSectionLocker lock(memLocker);
1014 #endif
1015
1016 if (!buf)
1017 return;
1018
1019 #if defined(__VISAGECPP__) && (__IBMCPP__ < 400 || __IBMC__ < 400 )
1020 // VA 3.0 still has trouble in here
1021 free((char *)buf);
1022 #endif
1023 // If not in debugging allocation mode, do the normal thing
1024 // so we don't leave any trace of ourselves in the node list.
1025 if (!wxDebugContext::GetDebugMode())
1026 {
1027 free((char *)buf);
1028 return;
1029 }
1030
1031 // Points to the start of the entire allocated area.
1032 char * startPointer = wxDebugContext::StartPos ((char *) buf);
1033 // Find the struct and make sure that it's identifiable.
1034 wxMemStruct * st = (wxMemStruct *) wxDebugContext::StructPos (startPointer);
1035
1036 if (! st->ValidateNode ())
1037 return;
1038
1039 // If this is the current checkpoint, we need to
1040 // move the checkpoint back so it points to a valid
1041 // node.
1042 if (st == wxDebugContext::checkPoint)
1043 wxDebugContext::checkPoint = wxDebugContext::checkPoint->m_prev;
1044
1045 if (! st->Unlink ())
1046 {
1047 st->ErrorMsg ("Unlinking deleted node");
1048 }
1049
1050 // Now put in the fill char into the id slot and the caller requested
1051 // memory locations.
1052 st->SetDeleted ();
1053 (void) memset (wxDebugContext::CallerMemPos (startPointer), MemFillChar,
1054 st->RequestSize ());
1055
1056 free((char *)st);
1057 }
1058
1059 #endif // __WXDEBUG__
1060
1061 // Trace: send output to the current debugging stream
1062 void wxTrace(const wxChar * ...)
1063 {
1064 #if 1
1065 wxFAIL_MSG(wxT("wxTrace is now obsolete. Please use wxDebugXXX instead."));
1066 #else
1067 va_list ap;
1068 static wxChar buffer[512];
1069
1070 va_start(ap, fmt);
1071
1072 #ifdef __WXMSW__
1073 wvsprintf(buffer,fmt,ap) ;
1074 #else
1075 vsprintf(buffer,fmt,ap) ;
1076 #endif
1077
1078 va_end(ap);
1079
1080 if (wxDebugContext::HasStream())
1081 {
1082 wxDebugContext::GetStream() << buffer;
1083 wxDebugContext::GetStream().flush();
1084 }
1085 else
1086 #ifdef __WXMSW__
1087 #ifdef __WIN32__
1088 OutputDebugString((LPCTSTR)buffer) ;
1089 #else
1090 OutputDebugString((const char*) buffer) ;
1091 #endif
1092 #else
1093 fprintf(stderr, buffer);
1094 #endif
1095 #endif
1096 }
1097
1098 // Trace with level
1099 void wxTraceLevel(int, const wxChar * ...)
1100 {
1101 #if 1
1102 wxFAIL_MSG(wxT("wxTrace is now obsolete. Please use wxDebugXXX instead."));
1103 #else
1104 if (wxDebugContext::GetLevel() < level)
1105 return;
1106
1107 va_list ap;
1108 static wxChar buffer[512];
1109
1110 va_start(ap, fmt);
1111
1112 #ifdef __WXMSW__
1113 wxWvsprintf(buffer,fmt,ap) ;
1114 #else
1115 vsprintf(buffer,fmt,ap) ;
1116 #endif
1117
1118 va_end(ap);
1119
1120 if (wxDebugContext::HasStream())
1121 {
1122 wxDebugContext::GetStream() << buffer;
1123 wxDebugContext::GetStream().flush();
1124 }
1125 else
1126 #ifdef __WXMSW__
1127 #ifdef __WIN32__
1128 OutputDebugString((LPCTSTR)buffer) ;
1129 #else
1130 OutputDebugString((const char*) buffer) ;
1131 #endif
1132 #else
1133 fprintf(stderr, buffer);
1134 #endif
1135 #endif
1136 }
1137
1138 //----------------------------------------------------------------------------
1139 // Final cleanup after all global objects in all files have been destroyed
1140 //----------------------------------------------------------------------------
1141
1142 // Don't set it to 0 by dynamic initialization
1143 // Some compilers will really do the assignment later
1144 // All global variables are initialized to 0 at the very beginning, and this is just fine.
1145 int wxDebugContextDumpDelayCounter::sm_count;
1146
1147 void wxDebugContextDumpDelayCounter::DoDump()
1148 {
1149 if (wxDebugContext::CountObjectsLeft(true) > 0)
1150 {
1151 wxDebugContext::OutputDumpLine(wxT("There were memory leaks.\n"));
1152 wxDebugContext::Dump();
1153 wxDebugContext::PrintStatistics();
1154 }
1155 }
1156
1157 // Even if there is nothing else, make sure that there is at
1158 // least one cleanup counter object
1159 static wxDebugContextDumpDelayCounter wxDebugContextDumpDelayCounter_One;
1160
1161 #endif // (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
1162