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