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