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