]> git.saurik.com Git - wxWidgets.git/blame - src/common/memory.cpp
Unix compilation fixed
[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
2db0bbde
JS
652 wxMemStruct * st = NULL;
653 for (st = from; st != 0; st = st->m_next)
c801d85f
KB
654 {
655 void* data = st->GetActualData();
184b5d99
JS
656// if ((data != (void*)m_debugStream) && (data != (void*) m_streamBuf))
657 if (data != (void*) wxLog::GetActiveTarget())
c801d85f
KB
658 {
659 (st->*func) ();
660 }
661 }
662}
663
664
665/*
666 Print out the list.
667 */
668bool wxDebugContext::PrintList (void)
669{
ea57084d 670#ifdef __WXDEBUG__
184b5d99
JS
671// if (!HasStream())
672// return FALSE;
c801d85f 673
bd7d06f2 674 TraverseList ((PmSFV)&wxMemStruct::PrintNode, (checkPoint ? checkPoint->m_next : (wxMemStruct*)NULL));
c801d85f
KB
675
676 return TRUE;
677#else
678 return FALSE;
679#endif
680}
681
682bool wxDebugContext::Dump(void)
683{
ea57084d 684#ifdef __WXDEBUG__
184b5d99
JS
685// if (!HasStream())
686// return FALSE;
c801d85f 687
2917e920 688// if (TRUE)
c801d85f 689 {
223d09f6 690 wxChar* appName = wxT("application");
c801d85f
KB
691 wxString appNameStr("");
692 if (wxTheApp)
693 {
694 appNameStr = wxTheApp->GetAppName();
4de6207a 695 appName = WXSTRINGCAST appNameStr;
5fa399c9 696 wxLogMessage(wxT("----- Memory dump of %s at %s -----"), appName, WXSTRINGCAST wxNow() );
e55ad60e
RR
697 }
698 else
699 {
5fa399c9 700 wxLogMessage( wxT("----- Memory dump -----") );
c801d85f
KB
701 }
702 }
bd7d06f2 703 TraverseList ((PmSFV)&wxMemStruct::Dump, (checkPoint ? checkPoint->m_next : (wxMemStruct*)NULL));
3f4a0c5b 704
5fa399c9
JS
705 wxLogMessage( wxT("") );
706 wxLogMessage( wxT("") );
c801d85f
KB
707
708 return TRUE;
709#else
710 return FALSE;
711#endif
712}
713
33ac7e6f 714#ifdef __WXDEBUG__
c801d85f
KB
715struct wxDebugStatsStruct
716{
717 long instanceCount;
718 long totalSize;
4de6207a 719 wxChar *instanceClass;
c801d85f
KB
720 wxDebugStatsStruct *next;
721};
722
4de6207a 723static wxDebugStatsStruct *FindStatsStruct(wxDebugStatsStruct *st, wxChar *name)
c801d85f
KB
724{
725 while (st)
726 {
4de6207a 727 if (wxStrcmp(st->instanceClass, name) == 0)
c801d85f
KB
728 return st;
729 st = st->next;
730 }
731 return NULL;
732}
733
734static wxDebugStatsStruct *InsertStatsStruct(wxDebugStatsStruct *head, wxDebugStatsStruct *st)
735{
736 st->next = head;
737 return st;
738}
33ac7e6f 739#endif
c801d85f
KB
740
741bool wxDebugContext::PrintStatistics(bool detailed)
742{
ea57084d 743#ifdef __WXDEBUG__
184b5d99
JS
744// if (!HasStream())
745// return FALSE;
c801d85f 746
2917e920 747// if (TRUE)
e55ad60e 748 {
223d09f6
KB
749 wxChar* appName = wxT("application");
750 wxString appNameStr(wxT(""));
e55ad60e
RR
751 if (wxTheApp)
752 {
753 appNameStr = wxTheApp->GetAppName();
4de6207a 754 appName = WXSTRINGCAST appNameStr;
5fa399c9 755 wxLogMessage(wxT("----- Memory statistics of %s at %s -----"), appName, WXSTRINGCAST wxNow() );
e55ad60e
RR
756 }
757 else
758 {
5fa399c9 759 wxLogMessage( wxT("----- Memory statistics -----") );
e55ad60e
RR
760 }
761 }
3f4a0c5b 762
c801d85f
KB
763 bool currentMode = GetDebugMode();
764 SetDebugMode(FALSE);
3f4a0c5b 765
c801d85f
KB
766 long noNonObjectNodes = 0;
767 long noObjectNodes = 0;
768 long totalSize = 0;
769
770 wxDebugStatsStruct *list = NULL;
771
bd7d06f2 772 wxMemStruct *from = (checkPoint ? checkPoint->m_next : (wxMemStruct*)NULL );
c801d85f
KB
773 if (!from)
774 from = wxDebugContext::GetHead ();
775
3f4a0c5b 776 wxMemStruct *st;
c801d85f
KB
777 for (st = from; st != 0; st = st->m_next)
778 {
779 void* data = st->GetActualData();
184b5d99
JS
780// if (detailed && (data != (void*)m_debugStream) && (data != (void*) m_streamBuf))
781 if (detailed && (data != (void*) wxLog::GetActiveTarget()))
c801d85f 782 {
223d09f6 783 wxChar *className = wxT("nonobject");
c801d85f
KB
784 if (st->m_isObject && st->GetActualData())
785 {
786 wxObject *obj = (wxObject *)st->GetActualData();
787 if (obj->GetClassInfo()->GetClassName())
abe5726a 788 className = (wxChar*)obj->GetClassInfo()->GetClassName();
c801d85f
KB
789 }
790 wxDebugStatsStruct *stats = FindStatsStruct(list, className);
791 if (!stats)
792 {
793 stats = (wxDebugStatsStruct *)malloc(sizeof(wxDebugStatsStruct));
794 stats->instanceClass = className;
795 stats->instanceCount = 0;
796 stats->totalSize = 0;
797 list = InsertStatsStruct(list, stats);
798 }
799 stats->instanceCount ++;
800 stats->totalSize += st->RequestSize();
801 }
802
184b5d99
JS
803// if ((data != (void*)m_debugStream) && (data != (void*) m_streamBuf))
804 if (data != (void*) wxLog::GetActiveTarget())
c801d85f
KB
805 {
806 totalSize += st->RequestSize();
807 if (st->m_isObject)
808 noObjectNodes ++;
809 else
810 noNonObjectNodes ++;
811 }
812 }
813
814 if (detailed)
815 {
816 while (list)
817 {
5fa399c9 818 wxLogMessage(wxT("%ld objects of class %s, total size %ld"),
c801d85f
KB
819 list->instanceCount, list->instanceClass, list->totalSize);
820 wxDebugStatsStruct *old = list;
821 list = old->next;
822 free((char *)old);
823 }
5fa399c9 824 wxLogMessage(wxT(""));
c801d85f 825 }
3f4a0c5b 826
c801d85f
KB
827 SetDebugMode(currentMode);
828
5fa399c9
JS
829 wxLogMessage(wxT("Number of object items: %ld"), noObjectNodes);
830 wxLogMessage(wxT("Number of non-object items: %ld"), noNonObjectNodes);
831 wxLogMessage(wxT("Total allocated size: %ld"), totalSize);
832 wxLogMessage(wxT(""));
833 wxLogMessage(wxT(""));
c801d85f
KB
834
835 return TRUE;
836#else
33ac7e6f 837 (void)detailed;
c801d85f
KB
838 return FALSE;
839#endif
3f4a0c5b 840}
c801d85f
KB
841
842bool wxDebugContext::PrintClasses(void)
843{
184b5d99
JS
844// if (!HasStream())
845// return FALSE;
c801d85f 846
2917e920 847// if (TRUE)
c801d85f 848 {
223d09f6
KB
849 wxChar* appName = wxT("application");
850 wxString appNameStr(wxT(""));
c801d85f
KB
851 if (wxTheApp)
852 {
853 appNameStr = wxTheApp->GetAppName();
4de6207a 854 appName = WXSTRINGCAST appNameStr;
5fa399c9 855 wxLogMessage(wxT("----- Classes in %s -----"), appName);
c801d85f
KB
856 }
857 }
858
859 int n = 0;
f4a8c29f
GL
860 wxNode *node;
861 wxClassInfo *info;
862
0c32066b
JS
863 wxClassInfo::sm_classTable->BeginFind();
864 node = wxClassInfo::sm_classTable->Next();
f4a8c29f 865 while (node)
c801d85f 866 {
f4a8c29f 867 info = (wxClassInfo *)node->Data();
c801d85f
KB
868 if (info->GetClassName())
869 {
184b5d99 870 wxString msg(info->GetClassName());
223d09f6 871 msg += wxT(" ");
184b5d99
JS
872
873 if (info->GetBaseClassName1() && !info->GetBaseClassName2())
874 {
223d09f6 875 msg += wxT("is a ");
184b5d99
JS
876 msg += info->GetBaseClassName1();
877 }
878 else if (info->GetBaseClassName1() && info->GetBaseClassName2())
879 {
223d09f6 880 msg += wxT("is a ");
184b5d99 881 msg += info->GetBaseClassName1() ;
223d09f6 882 msg += wxT(", ");
184b5d99
JS
883 msg += info->GetBaseClassName2() ;
884 }
885 if (info->GetConstructor())
223d09f6 886 msg += wxT(": dynamic");
184b5d99 887
5fa399c9 888 wxLogMessage(msg);
c801d85f 889 }
e55ad60e 890 node = wxClassInfo::sm_classTable->Next();
c801d85f
KB
891 n ++;
892 }
5fa399c9
JS
893 wxLogMessage(wxT(""));
894 wxLogMessage(wxT("There are %d classes derived from wxObject."), n);
895 wxLogMessage(wxT(""));
896 wxLogMessage(wxT(""));
c801d85f 897 return TRUE;
3f4a0c5b 898}
c801d85f
KB
899
900void wxDebugContext::SetCheckpoint(bool all)
901{
902 if (all)
903 checkPoint = NULL;
904 else
905 checkPoint = m_tail;
906}
907
908// Checks all nodes since checkpoint, or since start.
909int wxDebugContext::Check(bool checkAll)
910{
911 int nFailures = 0;
3f4a0c5b 912
bd7d06f2 913 wxMemStruct *from = (checkPoint ? checkPoint->m_next : (wxMemStruct*)NULL );
c801d85f
KB
914 if (!from || checkAll)
915 from = wxDebugContext::GetHead ();
916
917 for (wxMemStruct * st = from; st != 0; st = st->m_next)
918 {
919 if (st->AssertIt ())
920 nFailures += st->CheckBlock ();
921 else
922 return -1;
923 }
924
925 return nFailures;
926}
927
928// Count the number of non-wxDebugContext-related objects
929// that are outstanding
4fabb575 930int wxDebugContext::CountObjectsLeft(bool sinceCheckpoint)
c801d85f
KB
931{
932 int n = 0;
4fabb575
JS
933
934 wxMemStruct *from = NULL;
935 if (sinceCheckpoint && checkPoint)
936 from = checkPoint->m_next;
9a29912f 937 else
4fabb575 938 from = wxDebugContext::GetHead () ;
c801d85f
KB
939
940 for (wxMemStruct * st = from; st != 0; st = st->m_next)
941 {
942 void* data = st->GetActualData();
184b5d99
JS
943// if ((data != (void*)m_debugStream) && (data != (void*) m_streamBuf))
944 if (data != (void*) wxLog::GetActiveTarget())
c801d85f
KB
945 n ++;
946 }
947
948 return n ;
949}
950
c801d85f 951// TODO: store whether this is a vector or not.
4de6207a 952void * wxDebugAlloc(size_t size, wxChar * fileName, int lineNum, bool isObject, bool WXUNUSED(isVect) )
c801d85f
KB
953{
954 // If not in debugging allocation mode, do the normal thing
955 // so we don't leave any trace of ourselves in the node list.
956
86b3203f
DW
957#if defined(__VISAGECPP__) && (__IBMCPP__ < 400 || __IBMC__ < 400 )
958// VA 3.0 still has trouble in here
959 return (void *)malloc(size);
960#endif
c801d85f
KB
961 if (!wxDebugContext::GetDebugMode())
962 {
963 return (void *)malloc(size);
964 }
3f4a0c5b 965
94b49b93
JS
966 int totSize = wxDebugContext::TotSize (size);
967 char * buf = (char *) malloc(totSize);
c801d85f 968 if (!buf) {
5fa399c9 969 wxLogMessage(wxT("Call to malloc (%ld) failed."), (long)size);
3f4a0c5b 970 return 0;
c801d85f
KB
971 }
972 wxMemStruct * st = (wxMemStruct *)buf;
973 st->m_firstMarker = MemStartCheck;
974 st->m_reqSize = size;
975 st->m_fileName = fileName;
976 st->m_lineNum = lineNum;
977 st->m_id = MemStructId;
978 st->m_prev = 0;
979 st->m_next = 0;
980 st->m_isObject = isObject;
981
982 // Errors from Append() shouldn't really happen - but just in case!
983 if (st->Append () == 0) {
3f4a0c5b 984 st->ErrorMsg ("Trying to append new node");
c801d85f 985 }
3f4a0c5b 986
c801d85f 987 if (wxDebugContext::GetCheckPrevious ()) {
3f4a0c5b
VZ
988 if (st->CheckAllPrevious () < 0) {
989 st->ErrorMsg ("Checking previous nodes");
990 }
c801d85f 991 }
3f4a0c5b 992
c801d85f
KB
993 // Set up the extra markers at the middle and end.
994 char * ptr = wxDebugContext::MidMarkerPos (buf);
995 * (wxMarkerType *) ptr = MemMidCheck;
996 ptr = wxDebugContext::EndMarkerPos (buf, size);
997 * (wxMarkerType *) ptr = MemEndCheck;
998
999 // pointer returned points to the start of the caller's
1000 // usable area.
1001 void *m_actualData = (void *) wxDebugContext::CallerMemPos (buf);
1002 st->m_actualData = m_actualData;
1003
1004 return m_actualData;
1005}
1006
1007// TODO: check whether was allocated as a vector
bd7d06f2 1008void wxDebugFree(void * buf, bool WXUNUSED(isVect) )
c801d85f
KB
1009{
1010 if (!buf)
1011 return;
3f4a0c5b 1012
86b3203f
DW
1013#if defined(__VISAGECPP__) && (__IBMCPP__ < 400 || __IBMC__ < 400 )
1014// VA 3.0 still has trouble in here
1015 free((char *)buf);
1016#endif
c801d85f
KB
1017 // If not in debugging allocation mode, do the normal thing
1018 // so we don't leave any trace of ourselves in the node list.
1019 if (!wxDebugContext::GetDebugMode())
1020 {
1021 free((char *)buf);
1022 return;
1023 }
1024
1025 // Points to the start of the entire allocated area.
1026 char * startPointer = wxDebugContext::StartPos ((char *) buf);
1027 // Find the struct and make sure that it's identifiable.
1028 wxMemStruct * st = (wxMemStruct *) wxDebugContext::StructPos (startPointer);
1029
1030 if (! st->ValidateNode ())
3f4a0c5b 1031 return;
c801d85f
KB
1032
1033 // If this is the current checkpoint, we need to
1034 // move the checkpoint back so it points to a valid
1035 // node.
1036 if (st == wxDebugContext::checkPoint)
1037 wxDebugContext::checkPoint = wxDebugContext::checkPoint->m_prev;
1038
1039 if (! st->Unlink ())
1040 {
1041 st->ErrorMsg ("Unlinking deleted node");
1042 }
3f4a0c5b 1043
c801d85f
KB
1044 // Now put in the fill char into the id slot and the caller requested
1045 // memory locations.
1046 st->SetDeleted ();
1047 (void) memset (wxDebugContext::CallerMemPos (startPointer), MemFillChar,
3f4a0c5b 1048 st->RequestSize ());
c801d85f
KB
1049
1050 // Don't allow delayed freeing of memory in this version
1051// if (!wxDebugContext::GetDelayFree())
1052// free((void *)st);
1053 free((char *)st);
1054}
1055
1056// Trace: send output to the current debugging stream
33ac7e6f 1057void wxTrace(const wxChar * ...)
c801d85f 1058{
f6bcfd97
BP
1059#if 1
1060 wxFAIL_MSG(wxT("wxTrace is now obsolete. Please use wxDebugXXX instead."));
1061#else
1062 va_list ap;
4de6207a 1063 static wxChar buffer[512];
c801d85f
KB
1064
1065 va_start(ap, fmt);
1066
2049ba38 1067#ifdef __WXMSW__
c801d85f
KB
1068 wvsprintf(buffer,fmt,ap) ;
1069#else
1070 vsprintf(buffer,fmt,ap) ;
1071#endif
1072
1073 va_end(ap);
1074
1075 if (wxDebugContext::HasStream())
1076 {
1077 wxDebugContext::GetStream() << buffer;
1078 wxDebugContext::GetStream().flush();
1079 }
1080 else
2049ba38 1081#ifdef __WXMSW__
25889d3c 1082#ifdef __WIN32__
4de6207a 1083 OutputDebugString((LPCTSTR)buffer) ;
25889d3c
JS
1084#else
1085 OutputDebugString((const char*) buffer) ;
1086#endif
c801d85f
KB
1087#else
1088 fprintf(stderr, buffer);
1089#endif
f6bcfd97 1090#endif
c801d85f
KB
1091}
1092
1093// Trace with level
33ac7e6f 1094void wxTraceLevel(int, const wxChar * ...)
c801d85f 1095{
f6bcfd97
BP
1096#if 1
1097 wxFAIL_MSG(wxT("wxTrace is now obsolete. Please use wxDebugXXX instead."));
1098#else
c801d85f
KB
1099 if (wxDebugContext::GetLevel() < level)
1100 return;
3f4a0c5b 1101
c801d85f 1102 va_list ap;
4de6207a 1103 static wxChar buffer[512];
c801d85f
KB
1104
1105 va_start(ap, fmt);
1106
2049ba38 1107#ifdef __WXMSW__
f6bcfd97 1108 wxWvsprintf(buffer,fmt,ap) ;
c801d85f
KB
1109#else
1110 vsprintf(buffer,fmt,ap) ;
1111#endif
1112
1113 va_end(ap);
1114
1115 if (wxDebugContext::HasStream())
1116 {
1117 wxDebugContext::GetStream() << buffer;
1118 wxDebugContext::GetStream().flush();
1119 }
1120 else
2049ba38 1121#ifdef __WXMSW__
25889d3c 1122#ifdef __WIN32__
4de6207a 1123 OutputDebugString((LPCTSTR)buffer) ;
25889d3c
JS
1124#else
1125 OutputDebugString((const char*) buffer) ;
1126#endif
c801d85f
KB
1127#else
1128 fprintf(stderr, buffer);
1129#endif
f6bcfd97 1130#endif
c801d85f
KB
1131}
1132
ea57084d 1133#else // wxUSE_MEMORY_TRACING && defined(__WXDEBUG__)
c801d85f
KB
1134void wxTrace(const char *WXUNUSED(fmt) ...)
1135{
1136}
1137
1138void wxTraceLevel(int WXUNUSED(level), const char *WXUNUSED(fmt) ...)
1139{
1140}
1141#endif
1142