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