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