]> git.saurik.com Git - wxWidgets.git/blame - src/common/memory.cpp
New wxEventType for event type enum, and corresponding alterations.
[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
27#if (DEBUG && USE_MEMORY_TRACING) || USE_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 <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
54#ifdef __WINDOWS__
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.
390 wxTrace("Can't verify memory struct - all bets are off!\n");
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{
626#if DEBUG
627 if (!HasStream())
628 return FALSE;
629
630 TraverseList ((PmSFV)&wxMemStruct::PrintNode, (checkPoint ? checkPoint->m_next : NULL));
631
632 return TRUE;
633#else
634 return FALSE;
635#endif
636}
637
638bool wxDebugContext::Dump(void)
639{
640#if DEBUG
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;
652 wxTrace("Memory dump of %s at %s:\n", appName, wxNow());
653 }
654 }
655 TraverseList ((PmSFV)&wxMemStruct::Dump, (checkPoint ? checkPoint->m_next : NULL));
656
657 return TRUE;
658#else
659 return FALSE;
660#endif
661}
662
663struct wxDebugStatsStruct
664{
665 long instanceCount;
666 long totalSize;
667 char *instanceClass;
668 wxDebugStatsStruct *next;
669};
670
671static wxDebugStatsStruct *FindStatsStruct(wxDebugStatsStruct *st, char *name)
672{
673 while (st)
674 {
675 if (strcmp(st->instanceClass, name) == 0)
676 return st;
677 st = st->next;
678 }
679 return NULL;
680}
681
682static wxDebugStatsStruct *InsertStatsStruct(wxDebugStatsStruct *head, wxDebugStatsStruct *st)
683{
684 st->next = head;
685 return st;
686}
687
688bool wxDebugContext::PrintStatistics(bool detailed)
689{
690#if DEBUG
691 if (!HasStream())
692 return FALSE;
693
694 bool currentMode = GetDebugMode();
695 SetDebugMode(FALSE);
696
697 long noNonObjectNodes = 0;
698 long noObjectNodes = 0;
699 long totalSize = 0;
700
701 wxDebugStatsStruct *list = NULL;
702
703 wxMemStruct *from = (checkPoint ? checkPoint->m_next : NULL);
704 if (!from)
705 from = wxDebugContext::GetHead ();
706
707 wxMemStruct *st;
708 for (st = from; st != 0; st = st->m_next)
709 {
710 void* data = st->GetActualData();
711 if (detailed && (data != (void*)m_debugStream) && (data != (void*) m_streamBuf))
712 {
713 char *className = "nonobject";
714 if (st->m_isObject && st->GetActualData())
715 {
716 wxObject *obj = (wxObject *)st->GetActualData();
717 if (obj->GetClassInfo()->GetClassName())
718 className = obj->GetClassInfo()->GetClassName();
719 }
720 wxDebugStatsStruct *stats = FindStatsStruct(list, className);
721 if (!stats)
722 {
723 stats = (wxDebugStatsStruct *)malloc(sizeof(wxDebugStatsStruct));
724 stats->instanceClass = className;
725 stats->instanceCount = 0;
726 stats->totalSize = 0;
727 list = InsertStatsStruct(list, stats);
728 }
729 stats->instanceCount ++;
730 stats->totalSize += st->RequestSize();
731 }
732
733 if ((data != (void*)m_debugStream) && (data != (void*) m_streamBuf))
734 {
735 totalSize += st->RequestSize();
736 if (st->m_isObject)
737 noObjectNodes ++;
738 else
739 noNonObjectNodes ++;
740 }
741 }
742
743 if (detailed)
744 {
745 while (list)
746 {
747 wxTrace("%ld objects of class %s, total size %ld\n",
748 list->instanceCount, list->instanceClass, list->totalSize);
749 wxDebugStatsStruct *old = list;
750 list = old->next;
751 free((char *)old);
752 }
753 wxTrace("\n");
754 }
755
756 SetDebugMode(currentMode);
757
758 wxTrace("Number of object items: %ld\n", noObjectNodes);
759 wxTrace("Number of non-object items: %ld\n", noNonObjectNodes);
760 wxTrace("Total allocated size: %ld\n", totalSize);
761
762 return TRUE;
763#else
764 return FALSE;
765#endif
766}
767
768bool wxDebugContext::PrintClasses(void)
769{
770 if (!HasStream())
771 return FALSE;
772
773 if (TRUE)
774 {
775 char* appName = "application";
776 wxString appNameStr("");
777 if (wxTheApp)
778 {
779 appNameStr = wxTheApp->GetAppName();
780 appName = (char*) (const char*) appNameStr;
781 wxTrace("Classes in %s:\n\n", appName);
782 }
783 }
784
785 int n = 0;
786 wxClassInfo *info = wxClassInfo::first;
787 while (info)
788 {
789 if (info->GetClassName())
790 {
791 wxTrace("%s ", info->GetClassName());
792
793 if (info->GetBaseClassName1() && !info->GetBaseClassName2())
794 wxTrace("is a %s", info->GetBaseClassName1());
795 else if (info->GetBaseClassName1() && info->GetBaseClassName2())
796 wxTrace("is a %s, %s", info->GetBaseClassName1(), info->GetBaseClassName2());
797 if (info->objectConstructor)
798 wxTrace(": dynamic\n");
799 else
800 wxTrace("\n");
801 }
802 info = info->next;
803 n ++;
804 }
805 wxTrace("\nThere are %d classes derived from wxObject.\n", n);
806 return TRUE;
807}
808
809void wxDebugContext::SetCheckpoint(bool all)
810{
811 if (all)
812 checkPoint = NULL;
813 else
814 checkPoint = m_tail;
815}
816
817// Checks all nodes since checkpoint, or since start.
818int wxDebugContext::Check(bool checkAll)
819{
820 int nFailures = 0;
821
822 wxMemStruct *from = (checkPoint ? checkPoint->m_next : NULL);
823 if (!from || checkAll)
824 from = wxDebugContext::GetHead ();
825
826 for (wxMemStruct * st = from; st != 0; st = st->m_next)
827 {
828 if (st->AssertIt ())
829 nFailures += st->CheckBlock ();
830 else
831 return -1;
832 }
833
834 return nFailures;
835}
836
837// Count the number of non-wxDebugContext-related objects
838// that are outstanding
839int wxDebugContext::CountObjectsLeft(void)
840{
841 int n = 0;
842
843 wxMemStruct *from = wxDebugContext::GetHead ();
844
845 for (wxMemStruct * st = from; st != 0; st = st->m_next)
846 {
847 void* data = st->GetActualData();
848 if ((data != (void*)m_debugStream) && (data != (void*) m_streamBuf))
849 n ++;
850 }
851
852 return n ;
853}
854
855/*
856 The global operator new used for everything apart from getting
857 dynamic storage within this function itself.
858*/
859
860// We'll only do malloc and free for the moment: leave the interesting
861// stuff for the wxObject versions.
862
863#if DEBUG && USE_GLOBAL_MEMORY_OPERATORS
864
865#ifdef new
866#undef new
867#endif
868
869// Seems OK all of a sudden. Maybe to do with linking with multithreaded library?
870#if 0 // def _MSC_VER
871#define NO_DEBUG_ALLOCATION
872#endif
873
874// Unfortunately ~wxDebugStreamBuf doesn't work (VC++ 5) when we enable the debugging
875// code. I have no idea why. In BC++ 4.5, we have a similar problem the debug
876// stream myseriously changing pointer address between being passed from SetFile to SetStream.
877// See docs/msw/issues.txt.
878void * operator new (size_t size, char * fileName, int lineNum)
879{
880#ifdef NO_DEBUG_ALLOCATION
881 return malloc(size);
882#else
883 return wxDebugAlloc(size, fileName, lineNum, FALSE, FALSE);
884#endif
885}
886
887void * operator new[] (size_t size, char * fileName, int lineNum)
888{
889#ifdef NO_DEBUG_ALLOCATION
890 return malloc(size);
891#else
892 return wxDebugAlloc(size, fileName, lineNum, FALSE, TRUE);
893#endif
894}
895
896void operator delete (void * buf)
897{
898#ifdef NO_DEBUG_ALLOCATION
899 free((char*) buf);
900#else
901 wxDebugFree(buf);
902#endif
903}
904
905void operator delete[] (void * buf)
906{
907#ifdef NO_DEBUG_ALLOCATION
908 free((char*) buf);
909#else
910 wxDebugFree(buf, TRUE);
911#endif
912}
913
914#endif
915
916// TODO: store whether this is a vector or not.
917void * wxDebugAlloc(size_t size, char * fileName, int lineNum, bool isObject, bool isVect)
918{
919 // If not in debugging allocation mode, do the normal thing
920 // so we don't leave any trace of ourselves in the node list.
921
922 if (!wxDebugContext::GetDebugMode())
923 {
924 return (void *)malloc(size);
925 }
926
927 char * buf = (char *) malloc(wxDebugContext::TotSize (size));
928 if (!buf) {
929 wxTrace("Call to malloc (%ld) failed.\n", (long)size);
930 return 0;
931 }
932 wxMemStruct * st = (wxMemStruct *)buf;
933 st->m_firstMarker = MemStartCheck;
934 st->m_reqSize = size;
935 st->m_fileName = fileName;
936 st->m_lineNum = lineNum;
937 st->m_id = MemStructId;
938 st->m_prev = 0;
939 st->m_next = 0;
940 st->m_isObject = isObject;
941
942 // Errors from Append() shouldn't really happen - but just in case!
943 if (st->Append () == 0) {
944 st->ErrorMsg ("Trying to append new node");
945 }
946
947 if (wxDebugContext::GetCheckPrevious ()) {
948 if (st->CheckAllPrevious () < 0) {
949 st->ErrorMsg ("Checking previous nodes");
950 }
951 }
952
953 // Set up the extra markers at the middle and end.
954 char * ptr = wxDebugContext::MidMarkerPos (buf);
955 * (wxMarkerType *) ptr = MemMidCheck;
956 ptr = wxDebugContext::EndMarkerPos (buf, size);
957 * (wxMarkerType *) ptr = MemEndCheck;
958
959 // pointer returned points to the start of the caller's
960 // usable area.
961 void *m_actualData = (void *) wxDebugContext::CallerMemPos (buf);
962 st->m_actualData = m_actualData;
963
964 return m_actualData;
965}
966
967// TODO: check whether was allocated as a vector
968void wxDebugFree(void * buf, bool isVect)
969{
970 if (!buf)
971 return;
972
973 // If not in debugging allocation mode, do the normal thing
974 // so we don't leave any trace of ourselves in the node list.
975 if (!wxDebugContext::GetDebugMode())
976 {
977 free((char *)buf);
978 return;
979 }
980
981 // Points to the start of the entire allocated area.
982 char * startPointer = wxDebugContext::StartPos ((char *) buf);
983 // Find the struct and make sure that it's identifiable.
984 wxMemStruct * st = (wxMemStruct *) wxDebugContext::StructPos (startPointer);
985
986 if (! st->ValidateNode ())
987 return;
988
989 // If this is the current checkpoint, we need to
990 // move the checkpoint back so it points to a valid
991 // node.
992 if (st == wxDebugContext::checkPoint)
993 wxDebugContext::checkPoint = wxDebugContext::checkPoint->m_prev;
994
995 if (! st->Unlink ())
996 {
997 st->ErrorMsg ("Unlinking deleted node");
998 }
999
1000 // Now put in the fill char into the id slot and the caller requested
1001 // memory locations.
1002 st->SetDeleted ();
1003 (void) memset (wxDebugContext::CallerMemPos (startPointer), MemFillChar,
1004 st->RequestSize ());
1005
1006 // Don't allow delayed freeing of memory in this version
1007// if (!wxDebugContext::GetDelayFree())
1008// free((void *)st);
1009 free((char *)st);
1010}
1011
1012// Trace: send output to the current debugging stream
1013void wxTrace(const char *fmt ...)
1014{
1015 va_list ap;
1016 static char buffer[512];
1017
1018 va_start(ap, fmt);
1019
1020#ifdef __WINDOWS__
1021 wvsprintf(buffer,fmt,ap) ;
1022#else
1023 vsprintf(buffer,fmt,ap) ;
1024#endif
1025
1026 va_end(ap);
1027
1028 if (wxDebugContext::HasStream())
1029 {
1030 wxDebugContext::GetStream() << buffer;
1031 wxDebugContext::GetStream().flush();
1032 }
1033 else
1034#ifdef __WINDOWS__
1035 OutputDebugString((LPCSTR)buffer) ;
1036#else
1037 fprintf(stderr, buffer);
1038#endif
1039}
1040
1041// Trace with level
1042void wxTraceLevel(int level, const char *fmt ...)
1043{
1044 if (wxDebugContext::GetLevel() < level)
1045 return;
1046
1047 va_list ap;
1048 static char buffer[512];
1049
1050 va_start(ap, fmt);
1051
1052#ifdef __WINDOWS__
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
1066#ifdef __WINDOWS__
1067 OutputDebugString((LPCSTR)buffer) ;
1068#else
1069 fprintf(stderr, buffer);
1070#endif
1071}
1072
1073#else // USE_MEMORY_TRACING && DEBUG
1074void wxTrace(const char *WXUNUSED(fmt) ...)
1075{
1076}
1077
1078void wxTraceLevel(int WXUNUSED(level), const char *WXUNUSED(fmt) ...)
1079{
1080}
1081#endif
1082