]> git.saurik.com Git - wxWidgets.git/blame - src/common/memory.cpp
Added ODBC database classes and sample from RemStar (sample needs work for wxWin 2)
[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
69/*
70#ifdef new
71#undef new
72#endif
73*/
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*/
111void wxMemStruct::ErrorMsg (const char * mesg)
112{
113 wxTrace("wxWindows memory checking error: %s\n", 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*/
122void wxMemStruct::ErrorMsg ()
123{
124 wxTrace("wxWindows over/underwrite memory error: \n");
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*/
138int 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*/
160int 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*/
172int 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*/
198int 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*/
257int 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*/
285int 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*/
308void wxMemStruct::SetDeleted ()
309{
310 m_id = MemFillChar;
311}
312
313int 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*/
323void wxMemStruct::PrintNode ()
324{
325 if (m_isObject)
326 {
327 wxObject *obj = (wxObject *)m_actualData;
328 wxClassInfo *info = obj->GetClassInfo();
329
330 if (info && info->GetClassName())
331 wxTrace("%s", info->GetClassName());
332 else
333 wxTrace("Object");
334
335 if (m_fileName)
336 wxTrace(" (%s %d)", m_fileName, (int)m_lineNum);
337
338 wxTrace(" at $%lX, size %d\n", (long)GetActualData(), (int)RequestSize());
339 }
340 else
341 {
342 wxTrace("Non-object data");
343 if (m_fileName)
344 wxTrace(" (%s %d)", m_fileName, (int)m_lineNum);
345 wxTrace(" at $%lX, size %d\n", (long)GetActualData(), (int)RequestSize());
346 }
347}
348
349void wxMemStruct::Dump ()
350{
351 if (!ValidateNode()) return;
352
353 if (m_isObject)
354 {
355 wxObject *obj = (wxObject *)m_actualData;
356// wxClassInfo *info = obj->GetClassInfo();
357
358 if (m_fileName)
359 wxTrace("Item (%s %d)", m_fileName, (int)m_lineNum);
360 else
361 wxTrace("Item");
362
363 wxTrace(" at $%lX, size %d: ", (long)GetActualData(), (int)RequestSize());
364// wxTrace(info->GetClassName());
365 obj->Dump(wxDebugContext::GetStream());
366 wxTrace("\n");
367 }
368 else
369 {
370 wxTrace("Non-object data");
371 if (m_fileName)
372 wxTrace(" (%s %d)", m_fileName, (int)m_lineNum);
373 wxTrace(" at $%lX, size %d\n", (long)GetActualData(), (int)RequestSize());
374 }
375}
376
377
378/*
379 Validate a node. Check to see that the node is "clean" in the sense
380 that nothing has over/underwritten it etc.
381*/
382int wxMemStruct::ValidateNode ()
383{
384 char * startPointer = (char *) this;
385 if (!AssertIt ()) {
386 if (IsDeleted ())
387 ErrorMsg ("Object already deleted");
388 else {
389 // Can't use the error routines as we have no recognisable object.
bd7d06f2
RR
390#ifndef __WXGTK__
391 wxTrace("Can't verify memory struct - all bets are off!\n");
392#endif
c801d85f
KB
393 }
394 return 0;
395 }
396
397/*
398 int i;
399 for (i = 0; i < wxDebugContext::TotSize (requestSize ()); i++)
400 cout << startPointer [i];
401 cout << endl;
402*/
403 if (Marker () != MemStartCheck)
404 ErrorMsg ();
405 if (* (wxMarkerType *) wxDebugContext::MidMarkerPos (startPointer) != MemMidCheck)
406 ErrorMsg ();
407 if (* (wxMarkerType *) wxDebugContext::EndMarkerPos (startPointer,
408 RequestSize ()) !=
409 MemEndCheck)
410 ErrorMsg ();
411
412 // Back to before the extra buffer and check that
413 // we can still read what we originally wrote.
414 if (Marker () != MemStartCheck ||
415 * (wxMarkerType *) wxDebugContext::MidMarkerPos (startPointer)
416 != MemMidCheck ||
417 * (wxMarkerType *) wxDebugContext::EndMarkerPos (startPointer,
418 RequestSize ()) != MemEndCheck)
419 {
420 ErrorMsg ();
421 return 0;
422 }
423
424 return 1;
425}
426
427/*
428 The wxDebugContext class.
429*/
430
431wxMemStruct *wxDebugContext::m_head = NULL;
432wxMemStruct *wxDebugContext::m_tail = NULL;
433// ostream *wxDebugContext::m_debugStream = NULL;
434// streambuf *wxDebugContext::m_streamBuf = NULL;
435
436// Must initialise these in wxEntry, and then delete them just before wxEntry exits
437streambuf *wxDebugContext::m_streamBuf = NULL;
438ostream *wxDebugContext::m_debugStream = NULL;
439
440bool wxDebugContext::m_checkPrevious = FALSE;
441int wxDebugContext::debugLevel = 1;
442bool wxDebugContext::debugOn = TRUE;
443wxMemStruct *wxDebugContext::checkPoint = NULL;
444
445wxDebugContext::wxDebugContext(void)
446{
447// m_streamBuf = new wxDebugStreamBuf;
448// m_debugStream = new ostream(m_streamBuf);
449}
450
451wxDebugContext::~wxDebugContext(void)
452{
453 SetStream(NULL, NULL);
454}
455
456/*
457 * It's bizarre, but with BC++ 4.5, the value of str changes
458 * between SetFile and SetStream.
459 */
460
461void wxDebugContext::SetStream(ostream *str, streambuf *buf)
462{
463/*
464 if (str)
465 {
466 char buff[128];
467 sprintf(buff, "SetStream (1): str is %ld", (long) str);
468 MessageBox(NULL, buff, "Memory", MB_OK);
469 }
470*/
471
472 if (m_debugStream)
473 {
474 m_debugStream->flush();
475 delete m_debugStream;
476 }
477 m_debugStream = NULL;
478
479 // Not allowed in Watcom (~streambuf is protected).
480 // Is this trying to say something significant to us??
481#ifndef __WATCOMC__
482 if (m_streamBuf)
483 {
484 streambuf* oldBuf = m_streamBuf;
485 m_streamBuf = NULL;
486 delete oldBuf;
487 }
488#endif
489 m_streamBuf = buf;
490 m_debugStream = str;
491}
492
493bool wxDebugContext::SetFile(const wxString& file)
494{
495 ofstream *str = new ofstream((char *) (const char *)file);
496
497 if (str->bad())
498 {
499 delete str;
500 return FALSE;
501 }
502 else
503 {
504/*
505 char buf[40];
506 sprintf(buf, "SetFile: str is %ld", (long) str);
507 MessageBox(NULL, buf, "Memory", MB_OK);
508*/
509 SetStream(str);
510 return TRUE;
511 }
512}
513
514bool wxDebugContext::SetStandardError(void)
515{
516#if !defined(_WINDLL)
517 wxDebugStreamBuf *buf = new wxDebugStreamBuf;
518 ostream *stream = new ostream(m_streamBuf);
519 SetStream(stream, buf);
520 return TRUE;
521#else
522 return FALSE;
523#endif
524}
525
526
527/*
528 Work out the positions of the markers by creating an array of 2 markers
529 and comparing the addresses of the 2 elements. Use this number as the
530 alignment for markers.
531*/
532size_t wxDebugContext::CalcAlignment ()
533{
534 wxMarkerType ar[2];
535 return (char *) &ar[1] - (char *) &ar[0];
536}
537
538
539char * wxDebugContext::StructPos (const char * buf)
540{
541 return (char *) buf;
542}
543
544char * wxDebugContext::MidMarkerPos (const char * buf)
545{
546 return StructPos (buf) + PaddedSize (sizeof (wxMemStruct));
547}
548
549char * wxDebugContext::CallerMemPos (const char * buf)
550{
551 return MidMarkerPos (buf) + PaddedSize (sizeof(wxMarkerType));
552}
553
554
555char * wxDebugContext::EndMarkerPos (const char * buf, const size_t size)
556{
557 return CallerMemPos (buf) + PaddedSize (size);
558}
559
560
561/*
562 Slightly different as this takes a pointer to the start of the caller
563 requested region and returns a pointer to the start of the buffer.
564 */
565char * wxDebugContext::StartPos (const char * caller)
566{
567 return ((char *) (caller - wxDebugContext::PaddedSize (sizeof(wxMarkerType)) -
568 wxDebugContext::PaddedSize (sizeof (wxMemStruct))));
569}
570
571/*
572 We may need padding between various parts of the allocated memory.
573 Given a size of memory, this returns the amount of memory which should
574 be allocated in order to allow for alignment of the following object.
575
576 I don't know how portable this stuff is, but it seems to work for me at
577 the moment. It would be real nice if I knew more about this!
578*/
579size_t wxDebugContext::GetPadding (const size_t size)
580{
581 size_t pad = size % CalcAlignment ();
582 return (pad) ? sizeof(wxMarkerType) - pad : 0;
583}
584
585
586
587size_t wxDebugContext::PaddedSize (const size_t size)
588{
589 return size + GetPadding (size);
590}
591
592/*
593 Returns the total amount of memory which we need to get from the system
594 in order to satisfy a caller request. This includes space for the struct
595 plus markers and the caller's memory as well.
596*/
597size_t wxDebugContext::TotSize (const size_t reqSize)
598{
599 return (PaddedSize (sizeof (wxMemStruct)) + PaddedSize (reqSize) +
600 2 * sizeof(wxMarkerType));
601}
602
603
604/*
605 Traverse the list of nodes executing the given function on each node.
606*/
607void wxDebugContext::TraverseList (PmSFV func, wxMemStruct *from)
608{
609 if (!from)
610 from = wxDebugContext::GetHead ();
611
612 for (wxMemStruct * st = from; st != 0; st = st->m_next)
613 {
614 void* data = st->GetActualData();
615 if ((data != (void*)m_debugStream) && (data != (void*) m_streamBuf))
616 {
617 (st->*func) ();
618 }
619 }
620}
621
622
623/*
624 Print out the list.
625 */
626bool wxDebugContext::PrintList (void)
627{
b2aef89b 628#if WXDEBUG
c801d85f
KB
629 if (!HasStream())
630 return FALSE;
631
bd7d06f2 632 TraverseList ((PmSFV)&wxMemStruct::PrintNode, (checkPoint ? checkPoint->m_next : (wxMemStruct*)NULL));
c801d85f
KB
633
634 return TRUE;
635#else
636 return FALSE;
637#endif
638}
639
640bool wxDebugContext::Dump(void)
641{
b2aef89b 642#if WXDEBUG
c801d85f
KB
643 if (!HasStream())
644 return FALSE;
645
646 if (TRUE)
647 {
648 char* appName = "application";
649 wxString appNameStr("");
650 if (wxTheApp)
651 {
652 appNameStr = wxTheApp->GetAppName();
653 appName = (char*) (const char*) appNameStr;
bd7d06f2 654 wxTrace("Memory dump of %s at %s:\n", appName, WXSTRINGCAST wxNow() );
c801d85f
KB
655 }
656 }
bd7d06f2 657 TraverseList ((PmSFV)&wxMemStruct::Dump, (checkPoint ? checkPoint->m_next : (wxMemStruct*)NULL));
c801d85f
KB
658
659 return TRUE;
660#else
661 return FALSE;
662#endif
663}
664
665struct wxDebugStatsStruct
666{
667 long instanceCount;
668 long totalSize;
669 char *instanceClass;
670 wxDebugStatsStruct *next;
671};
672
673static wxDebugStatsStruct *FindStatsStruct(wxDebugStatsStruct *st, char *name)
674{
675 while (st)
676 {
677 if (strcmp(st->instanceClass, name) == 0)
678 return st;
679 st = st->next;
680 }
681 return NULL;
682}
683
684static wxDebugStatsStruct *InsertStatsStruct(wxDebugStatsStruct *head, wxDebugStatsStruct *st)
685{
686 st->next = head;
687 return st;
688}
689
690bool wxDebugContext::PrintStatistics(bool detailed)
691{
b2aef89b 692#if WXDEBUG
c801d85f
KB
693 if (!HasStream())
694 return FALSE;
695
696 bool currentMode = GetDebugMode();
697 SetDebugMode(FALSE);
698
699 long noNonObjectNodes = 0;
700 long noObjectNodes = 0;
701 long totalSize = 0;
702
703 wxDebugStatsStruct *list = NULL;
704
bd7d06f2 705 wxMemStruct *from = (checkPoint ? checkPoint->m_next : (wxMemStruct*)NULL );
c801d85f
KB
706 if (!from)
707 from = wxDebugContext::GetHead ();
708
709 wxMemStruct *st;
710 for (st = from; st != 0; st = st->m_next)
711 {
712 void* data = st->GetActualData();
713 if (detailed && (data != (void*)m_debugStream) && (data != (void*) m_streamBuf))
714 {
715 char *className = "nonobject";
716 if (st->m_isObject && st->GetActualData())
717 {
718 wxObject *obj = (wxObject *)st->GetActualData();
719 if (obj->GetClassInfo()->GetClassName())
720 className = obj->GetClassInfo()->GetClassName();
721 }
722 wxDebugStatsStruct *stats = FindStatsStruct(list, className);
723 if (!stats)
724 {
725 stats = (wxDebugStatsStruct *)malloc(sizeof(wxDebugStatsStruct));
726 stats->instanceClass = className;
727 stats->instanceCount = 0;
728 stats->totalSize = 0;
729 list = InsertStatsStruct(list, stats);
730 }
731 stats->instanceCount ++;
732 stats->totalSize += st->RequestSize();
733 }
734
735 if ((data != (void*)m_debugStream) && (data != (void*) m_streamBuf))
736 {
737 totalSize += st->RequestSize();
738 if (st->m_isObject)
739 noObjectNodes ++;
740 else
741 noNonObjectNodes ++;
742 }
743 }
744
745 if (detailed)
746 {
747 while (list)
748 {
749 wxTrace("%ld objects of class %s, total size %ld\n",
750 list->instanceCount, list->instanceClass, list->totalSize);
751 wxDebugStatsStruct *old = list;
752 list = old->next;
753 free((char *)old);
754 }
755 wxTrace("\n");
756 }
757
758 SetDebugMode(currentMode);
759
760 wxTrace("Number of object items: %ld\n", noObjectNodes);
761 wxTrace("Number of non-object items: %ld\n", noNonObjectNodes);
762 wxTrace("Total allocated size: %ld\n", totalSize);
763
764 return TRUE;
765#else
766 return FALSE;
767#endif
768}
769
770bool wxDebugContext::PrintClasses(void)
771{
772 if (!HasStream())
773 return FALSE;
774
775 if (TRUE)
776 {
777 char* appName = "application";
778 wxString appNameStr("");
779 if (wxTheApp)
780 {
781 appNameStr = wxTheApp->GetAppName();
782 appName = (char*) (const char*) appNameStr;
783 wxTrace("Classes in %s:\n\n", appName);
784 }
785 }
786
787 int n = 0;
788 wxClassInfo *info = wxClassInfo::first;
789 while (info)
790 {
791 if (info->GetClassName())
792 {
793 wxTrace("%s ", info->GetClassName());
794
795 if (info->GetBaseClassName1() && !info->GetBaseClassName2())
796 wxTrace("is a %s", info->GetBaseClassName1());
797 else if (info->GetBaseClassName1() && info->GetBaseClassName2())
798 wxTrace("is a %s, %s", info->GetBaseClassName1(), info->GetBaseClassName2());
799 if (info->objectConstructor)
800 wxTrace(": dynamic\n");
801 else
802 wxTrace("\n");
803 }
804 info = info->next;
805 n ++;
806 }
807 wxTrace("\nThere are %d classes derived from wxObject.\n", n);
808 return TRUE;
809}
810
811void wxDebugContext::SetCheckpoint(bool all)
812{
813 if (all)
814 checkPoint = NULL;
815 else
816 checkPoint = m_tail;
817}
818
819// Checks all nodes since checkpoint, or since start.
820int wxDebugContext::Check(bool checkAll)
821{
822 int nFailures = 0;
823
bd7d06f2 824 wxMemStruct *from = (checkPoint ? checkPoint->m_next : (wxMemStruct*)NULL );
c801d85f
KB
825 if (!from || checkAll)
826 from = wxDebugContext::GetHead ();
827
828 for (wxMemStruct * st = from; st != 0; st = st->m_next)
829 {
830 if (st->AssertIt ())
831 nFailures += st->CheckBlock ();
832 else
833 return -1;
834 }
835
836 return nFailures;
837}
838
839// Count the number of non-wxDebugContext-related objects
840// that are outstanding
841int wxDebugContext::CountObjectsLeft(void)
842{
843 int n = 0;
844
845 wxMemStruct *from = wxDebugContext::GetHead ();
846
847 for (wxMemStruct * st = from; st != 0; st = st->m_next)
848 {
849 void* data = st->GetActualData();
850 if ((data != (void*)m_debugStream) && (data != (void*) m_streamBuf))
851 n ++;
852 }
853
854 return n ;
855}
856
857/*
858 The global operator new used for everything apart from getting
859 dynamic storage within this function itself.
860*/
861
862// We'll only do malloc and free for the moment: leave the interesting
863// stuff for the wxObject versions.
864
b2aef89b 865#if WXDEBUG && USE_GLOBAL_MEMORY_OPERATORS
c801d85f
KB
866
867#ifdef new
868#undef new
869#endif
870
871// Seems OK all of a sudden. Maybe to do with linking with multithreaded library?
872#if 0 // def _MSC_VER
873#define NO_DEBUG_ALLOCATION
874#endif
875
876// Unfortunately ~wxDebugStreamBuf doesn't work (VC++ 5) when we enable the debugging
877// code. I have no idea why. In BC++ 4.5, we have a similar problem the debug
878// stream myseriously changing pointer address between being passed from SetFile to SetStream.
879// See docs/msw/issues.txt.
880void * operator new (size_t size, char * fileName, int lineNum)
881{
882#ifdef NO_DEBUG_ALLOCATION
883 return malloc(size);
884#else
885 return wxDebugAlloc(size, fileName, lineNum, FALSE, FALSE);
886#endif
887}
888
bb6290e3 889#if !( defined (_MSC_VER) && (_MSC_VER <= 1000) )
c801d85f
KB
890void * operator new[] (size_t size, char * fileName, int lineNum)
891{
892#ifdef NO_DEBUG_ALLOCATION
893 return malloc(size);
894#else
895 return wxDebugAlloc(size, fileName, lineNum, FALSE, TRUE);
896#endif
897}
5260b1c5 898#endif
c801d85f
KB
899
900void operator delete (void * buf)
901{
902#ifdef NO_DEBUG_ALLOCATION
903 free((char*) buf);
904#else
905 wxDebugFree(buf);
906#endif
907}
908
bb6290e3 909#if !( defined (_MSC_VER) && (_MSC_VER <= 1000) )
c801d85f
KB
910void operator delete[] (void * buf)
911{
912#ifdef NO_DEBUG_ALLOCATION
913 free((char*) buf);
914#else
915 wxDebugFree(buf, TRUE);
916#endif
917}
5260b1c5 918#endif
c801d85f
KB
919
920#endif
921
922// TODO: store whether this is a vector or not.
bd7d06f2 923void * wxDebugAlloc(size_t size, char * fileName, int lineNum, bool isObject, bool WXUNUSED(isVect) )
c801d85f
KB
924{
925 // If not in debugging allocation mode, do the normal thing
926 // so we don't leave any trace of ourselves in the node list.
927
928 if (!wxDebugContext::GetDebugMode())
929 {
930 return (void *)malloc(size);
931 }
932
933 char * buf = (char *) malloc(wxDebugContext::TotSize (size));
934 if (!buf) {
935 wxTrace("Call to malloc (%ld) failed.\n", (long)size);
936 return 0;
937 }
938 wxMemStruct * st = (wxMemStruct *)buf;
939 st->m_firstMarker = MemStartCheck;
940 st->m_reqSize = size;
941 st->m_fileName = fileName;
942 st->m_lineNum = lineNum;
943 st->m_id = MemStructId;
944 st->m_prev = 0;
945 st->m_next = 0;
946 st->m_isObject = isObject;
947
948 // Errors from Append() shouldn't really happen - but just in case!
949 if (st->Append () == 0) {
950 st->ErrorMsg ("Trying to append new node");
951 }
952
953 if (wxDebugContext::GetCheckPrevious ()) {
954 if (st->CheckAllPrevious () < 0) {
955 st->ErrorMsg ("Checking previous nodes");
956 }
957 }
958
959 // Set up the extra markers at the middle and end.
960 char * ptr = wxDebugContext::MidMarkerPos (buf);
961 * (wxMarkerType *) ptr = MemMidCheck;
962 ptr = wxDebugContext::EndMarkerPos (buf, size);
963 * (wxMarkerType *) ptr = MemEndCheck;
964
965 // pointer returned points to the start of the caller's
966 // usable area.
967 void *m_actualData = (void *) wxDebugContext::CallerMemPos (buf);
968 st->m_actualData = m_actualData;
969
970 return m_actualData;
971}
972
973// TODO: check whether was allocated as a vector
bd7d06f2 974void wxDebugFree(void * buf, bool WXUNUSED(isVect) )
c801d85f
KB
975{
976 if (!buf)
977 return;
978
979 // If not in debugging allocation mode, do the normal thing
980 // so we don't leave any trace of ourselves in the node list.
981 if (!wxDebugContext::GetDebugMode())
982 {
983 free((char *)buf);
984 return;
985 }
986
987 // Points to the start of the entire allocated area.
988 char * startPointer = wxDebugContext::StartPos ((char *) buf);
989 // Find the struct and make sure that it's identifiable.
990 wxMemStruct * st = (wxMemStruct *) wxDebugContext::StructPos (startPointer);
991
992 if (! st->ValidateNode ())
993 return;
994
995 // If this is the current checkpoint, we need to
996 // move the checkpoint back so it points to a valid
997 // node.
998 if (st == wxDebugContext::checkPoint)
999 wxDebugContext::checkPoint = wxDebugContext::checkPoint->m_prev;
1000
1001 if (! st->Unlink ())
1002 {
1003 st->ErrorMsg ("Unlinking deleted node");
1004 }
1005
1006 // Now put in the fill char into the id slot and the caller requested
1007 // memory locations.
1008 st->SetDeleted ();
1009 (void) memset (wxDebugContext::CallerMemPos (startPointer), MemFillChar,
1010 st->RequestSize ());
1011
1012 // Don't allow delayed freeing of memory in this version
1013// if (!wxDebugContext::GetDelayFree())
1014// free((void *)st);
1015 free((char *)st);
1016}
1017
1018// Trace: send output to the current debugging stream
1019void wxTrace(const char *fmt ...)
1020{
1021 va_list ap;
1022 static char buffer[512];
1023
1024 va_start(ap, fmt);
1025
2049ba38 1026#ifdef __WXMSW__
c801d85f
KB
1027 wvsprintf(buffer,fmt,ap) ;
1028#else
1029 vsprintf(buffer,fmt,ap) ;
1030#endif
1031
1032 va_end(ap);
1033
1034 if (wxDebugContext::HasStream())
1035 {
1036 wxDebugContext::GetStream() << buffer;
1037 wxDebugContext::GetStream().flush();
1038 }
1039 else
2049ba38 1040#ifdef __WXMSW__
c801d85f
KB
1041 OutputDebugString((LPCSTR)buffer) ;
1042#else
1043 fprintf(stderr, buffer);
1044#endif
1045}
1046
1047// Trace with level
1048void wxTraceLevel(int level, const char *fmt ...)
1049{
1050 if (wxDebugContext::GetLevel() < level)
1051 return;
1052
1053 va_list ap;
1054 static char buffer[512];
1055
1056 va_start(ap, fmt);
1057
2049ba38 1058#ifdef __WXMSW__
c801d85f
KB
1059 wvsprintf(buffer,fmt,ap) ;
1060#else
1061 vsprintf(buffer,fmt,ap) ;
1062#endif
1063
1064 va_end(ap);
1065
1066 if (wxDebugContext::HasStream())
1067 {
1068 wxDebugContext::GetStream() << buffer;
1069 wxDebugContext::GetStream().flush();
1070 }
1071 else
2049ba38 1072#ifdef __WXMSW__
c801d85f
KB
1073 OutputDebugString((LPCSTR)buffer) ;
1074#else
1075 fprintf(stderr, buffer);
1076#endif
1077}
1078
b2aef89b 1079#else // USE_MEMORY_TRACING && WXDEBUG
c801d85f
KB
1080void wxTrace(const char *WXUNUSED(fmt) ...)
1081{
1082}
1083
1084void wxTraceLevel(int WXUNUSED(level), const char *WXUNUSED(fmt) ...)
1085{
1086}
1087#endif
1088