]> git.saurik.com Git - wxWidgets.git/blame - src/common/memory.cpp
[gtk] fixed bug that caused segfaults in wxYield when wxToolBar has non-button contr...
[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{
223d09f6 114 wxLogDebug(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{
223d09f6 125 wxLogDebug(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
184b5d99 347 wxLogDebug(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
360 wxLogDebug(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
393 wxLogDebug(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
JS
403 msg += msg2;
404 wxLogDebug(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__
223d09f6 422 wxLogDebug(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
476wxDebugContext::wxDebugContext(void)
477{
478// m_streamBuf = new wxDebugStreamBuf;
479// m_debugStream = new ostream(m_streamBuf);
480}
481
482wxDebugContext::~wxDebugContext(void)
483{
484 SetStream(NULL, NULL);
485}
486
487/*
488 * It's bizarre, but with BC++ 4.5, the value of str changes
489 * between SetFile and SetStream.
490 */
491
492void wxDebugContext::SetStream(ostream *str, streambuf *buf)
493{
c801d85f
KB
494 if (m_debugStream)
495 {
496 m_debugStream->flush();
497 delete m_debugStream;
498 }
499 m_debugStream = NULL;
500
501 // Not allowed in Watcom (~streambuf is protected).
502 // Is this trying to say something significant to us??
503#ifndef __WATCOMC__
504 if (m_streamBuf)
505 {
506 streambuf* oldBuf = m_streamBuf;
507 m_streamBuf = NULL;
508 delete oldBuf;
509 }
510#endif
511 m_streamBuf = buf;
512 m_debugStream = str;
513}
514
515bool wxDebugContext::SetFile(const wxString& file)
516{
4de6207a 517 ofstream *str = new ofstream(file.fn_str());
c801d85f
KB
518
519 if (str->bad())
520 {
521 delete str;
522 return FALSE;
523 }
524 else
525 {
c801d85f
KB
526 SetStream(str);
527 return TRUE;
528 }
529}
530
531bool wxDebugContext::SetStandardError(void)
532{
9ca2fe7e
JS
533 // Obsolete
534#if 0
c801d85f
KB
535#if !defined(_WINDLL)
536 wxDebugStreamBuf *buf = new wxDebugStreamBuf;
537 ostream *stream = new ostream(m_streamBuf);
538 SetStream(stream, buf);
539 return TRUE;
540#else
541 return FALSE;
542#endif
9ca2fe7e
JS
543#endif
544 return FALSE;
c801d85f
KB
545}
546
547
548/*
549 Work out the positions of the markers by creating an array of 2 markers
550 and comparing the addresses of the 2 elements. Use this number as the
551 alignment for markers.
552*/
553size_t wxDebugContext::CalcAlignment ()
554{
555 wxMarkerType ar[2];
556 return (char *) &ar[1] - (char *) &ar[0];
557}
558
559
560char * wxDebugContext::StructPos (const char * buf)
561{
562 return (char *) buf;
563}
564
565char * wxDebugContext::MidMarkerPos (const char * buf)
566{
567 return StructPos (buf) + PaddedSize (sizeof (wxMemStruct));
568}
569
570char * wxDebugContext::CallerMemPos (const char * buf)
571{
572 return MidMarkerPos (buf) + PaddedSize (sizeof(wxMarkerType));
573}
574
575
576char * wxDebugContext::EndMarkerPos (const char * buf, const size_t size)
577{
578 return CallerMemPos (buf) + PaddedSize (size);
579}
580
581
582/*
583 Slightly different as this takes a pointer to the start of the caller
584 requested region and returns a pointer to the start of the buffer.
585 */
586char * wxDebugContext::StartPos (const char * caller)
587{
588 return ((char *) (caller - wxDebugContext::PaddedSize (sizeof(wxMarkerType)) -
3f4a0c5b 589 wxDebugContext::PaddedSize (sizeof (wxMemStruct))));
c801d85f
KB
590}
591
592/*
593 We may need padding between various parts of the allocated memory.
594 Given a size of memory, this returns the amount of memory which should
595 be allocated in order to allow for alignment of the following object.
596
597 I don't know how portable this stuff is, but it seems to work for me at
598 the moment. It would be real nice if I knew more about this!
599*/
600size_t wxDebugContext::GetPadding (const size_t size)
601{
602 size_t pad = size % CalcAlignment ();
603 return (pad) ? sizeof(wxMarkerType) - pad : 0;
604}
605
606
607
608size_t wxDebugContext::PaddedSize (const size_t size)
609{
610 return size + GetPadding (size);
611}
612
613/*
614 Returns the total amount of memory which we need to get from the system
615 in order to satisfy a caller request. This includes space for the struct
616 plus markers and the caller's memory as well.
617*/
618size_t wxDebugContext::TotSize (const size_t reqSize)
619{
620 return (PaddedSize (sizeof (wxMemStruct)) + PaddedSize (reqSize) +
3f4a0c5b 621 2 * sizeof(wxMarkerType));
c801d85f
KB
622}
623
624
625/*
626 Traverse the list of nodes executing the given function on each node.
627*/
628void wxDebugContext::TraverseList (PmSFV func, wxMemStruct *from)
629{
630 if (!from)
631 from = wxDebugContext::GetHead ();
3f4a0c5b 632
c801d85f
KB
633 for (wxMemStruct * st = from; st != 0; st = st->m_next)
634 {
635 void* data = st->GetActualData();
184b5d99
JS
636// if ((data != (void*)m_debugStream) && (data != (void*) m_streamBuf))
637 if (data != (void*) wxLog::GetActiveTarget())
c801d85f
KB
638 {
639 (st->*func) ();
640 }
641 }
642}
643
644
645/*
646 Print out the list.
647 */
648bool wxDebugContext::PrintList (void)
649{
ea57084d 650#ifdef __WXDEBUG__
184b5d99
JS
651// if (!HasStream())
652// return FALSE;
c801d85f 653
bd7d06f2 654 TraverseList ((PmSFV)&wxMemStruct::PrintNode, (checkPoint ? checkPoint->m_next : (wxMemStruct*)NULL));
c801d85f
KB
655
656 return TRUE;
657#else
658 return FALSE;
659#endif
660}
661
662bool wxDebugContext::Dump(void)
663{
ea57084d 664#ifdef __WXDEBUG__
184b5d99
JS
665// if (!HasStream())
666// return FALSE;
c801d85f 667
2917e920 668// if (TRUE)
c801d85f 669 {
223d09f6 670 wxChar* appName = wxT("application");
c801d85f
KB
671 wxString appNameStr("");
672 if (wxTheApp)
673 {
674 appNameStr = wxTheApp->GetAppName();
4de6207a 675 appName = WXSTRINGCAST appNameStr;
223d09f6 676 wxLogDebug(wxT("----- Memory dump of %s at %s -----"), appName, WXSTRINGCAST wxNow() );
e55ad60e
RR
677 }
678 else
679 {
223d09f6 680 wxLogDebug( wxT("----- Memory dump -----") );
c801d85f
KB
681 }
682 }
bd7d06f2 683 TraverseList ((PmSFV)&wxMemStruct::Dump, (checkPoint ? checkPoint->m_next : (wxMemStruct*)NULL));
3f4a0c5b 684
223d09f6
KB
685 wxLogDebug( wxT("") );
686 wxLogDebug( wxT("") );
c801d85f
KB
687
688 return TRUE;
689#else
690 return FALSE;
691#endif
692}
693
694struct wxDebugStatsStruct
695{
696 long instanceCount;
697 long totalSize;
4de6207a 698 wxChar *instanceClass;
c801d85f
KB
699 wxDebugStatsStruct *next;
700};
701
4de6207a 702static wxDebugStatsStruct *FindStatsStruct(wxDebugStatsStruct *st, wxChar *name)
c801d85f
KB
703{
704 while (st)
705 {
4de6207a 706 if (wxStrcmp(st->instanceClass, name) == 0)
c801d85f
KB
707 return st;
708 st = st->next;
709 }
710 return NULL;
711}
712
713static wxDebugStatsStruct *InsertStatsStruct(wxDebugStatsStruct *head, wxDebugStatsStruct *st)
714{
715 st->next = head;
716 return st;
717}
718
719bool wxDebugContext::PrintStatistics(bool detailed)
720{
ea57084d 721#ifdef __WXDEBUG__
184b5d99
JS
722// if (!HasStream())
723// return FALSE;
c801d85f 724
2917e920 725// if (TRUE)
e55ad60e 726 {
223d09f6
KB
727 wxChar* appName = wxT("application");
728 wxString appNameStr(wxT(""));
e55ad60e
RR
729 if (wxTheApp)
730 {
731 appNameStr = wxTheApp->GetAppName();
4de6207a 732 appName = WXSTRINGCAST appNameStr;
223d09f6 733 wxLogDebug(wxT("----- Memory statistics of %s at %s -----"), appName, WXSTRINGCAST wxNow() );
e55ad60e
RR
734 }
735 else
736 {
223d09f6 737 wxLogDebug( wxT("----- Memory statistics -----") );
e55ad60e
RR
738 }
739 }
3f4a0c5b 740
c801d85f
KB
741 bool currentMode = GetDebugMode();
742 SetDebugMode(FALSE);
3f4a0c5b 743
c801d85f
KB
744 long noNonObjectNodes = 0;
745 long noObjectNodes = 0;
746 long totalSize = 0;
747
748 wxDebugStatsStruct *list = NULL;
749
bd7d06f2 750 wxMemStruct *from = (checkPoint ? checkPoint->m_next : (wxMemStruct*)NULL );
c801d85f
KB
751 if (!from)
752 from = wxDebugContext::GetHead ();
753
3f4a0c5b 754 wxMemStruct *st;
c801d85f
KB
755 for (st = from; st != 0; st = st->m_next)
756 {
757 void* data = st->GetActualData();
184b5d99
JS
758// if (detailed && (data != (void*)m_debugStream) && (data != (void*) m_streamBuf))
759 if (detailed && (data != (void*) wxLog::GetActiveTarget()))
c801d85f 760 {
223d09f6 761 wxChar *className = wxT("nonobject");
c801d85f
KB
762 if (st->m_isObject && st->GetActualData())
763 {
764 wxObject *obj = (wxObject *)st->GetActualData();
765 if (obj->GetClassInfo()->GetClassName())
766 className = obj->GetClassInfo()->GetClassName();
767 }
768 wxDebugStatsStruct *stats = FindStatsStruct(list, className);
769 if (!stats)
770 {
771 stats = (wxDebugStatsStruct *)malloc(sizeof(wxDebugStatsStruct));
772 stats->instanceClass = className;
773 stats->instanceCount = 0;
774 stats->totalSize = 0;
775 list = InsertStatsStruct(list, stats);
776 }
777 stats->instanceCount ++;
778 stats->totalSize += st->RequestSize();
779 }
780
184b5d99
JS
781// if ((data != (void*)m_debugStream) && (data != (void*) m_streamBuf))
782 if (data != (void*) wxLog::GetActiveTarget())
c801d85f
KB
783 {
784 totalSize += st->RequestSize();
785 if (st->m_isObject)
786 noObjectNodes ++;
787 else
788 noNonObjectNodes ++;
789 }
790 }
791
792 if (detailed)
793 {
794 while (list)
795 {
223d09f6 796 wxLogDebug(wxT("%ld objects of class %s, total size %ld"),
c801d85f
KB
797 list->instanceCount, list->instanceClass, list->totalSize);
798 wxDebugStatsStruct *old = list;
799 list = old->next;
800 free((char *)old);
801 }
223d09f6 802 wxLogDebug(wxT(""));
c801d85f 803 }
3f4a0c5b 804
c801d85f
KB
805 SetDebugMode(currentMode);
806
223d09f6
KB
807 wxLogDebug(wxT("Number of object items: %ld"), noObjectNodes);
808 wxLogDebug(wxT("Number of non-object items: %ld"), noNonObjectNodes);
809 wxLogDebug(wxT("Total allocated size: %ld"), totalSize);
810 wxLogDebug(wxT(""));
811 wxLogDebug(wxT(""));
c801d85f
KB
812
813 return TRUE;
814#else
815 return FALSE;
816#endif
3f4a0c5b 817}
c801d85f
KB
818
819bool wxDebugContext::PrintClasses(void)
820{
184b5d99
JS
821// if (!HasStream())
822// return FALSE;
c801d85f 823
2917e920 824// if (TRUE)
c801d85f 825 {
223d09f6
KB
826 wxChar* appName = wxT("application");
827 wxString appNameStr(wxT(""));
c801d85f
KB
828 if (wxTheApp)
829 {
830 appNameStr = wxTheApp->GetAppName();
4de6207a 831 appName = WXSTRINGCAST appNameStr;
223d09f6 832 wxLogDebug(wxT("----- Classes in %s -----"), appName);
c801d85f
KB
833 }
834 }
835
836 int n = 0;
f4a8c29f
GL
837 wxNode *node;
838 wxClassInfo *info;
839
0c32066b
JS
840 wxClassInfo::sm_classTable->BeginFind();
841 node = wxClassInfo::sm_classTable->Next();
f4a8c29f 842 while (node)
c801d85f 843 {
f4a8c29f 844 info = (wxClassInfo *)node->Data();
c801d85f
KB
845 if (info->GetClassName())
846 {
184b5d99 847 wxString msg(info->GetClassName());
223d09f6 848 msg += wxT(" ");
184b5d99
JS
849
850 if (info->GetBaseClassName1() && !info->GetBaseClassName2())
851 {
223d09f6 852 msg += wxT("is a ");
184b5d99
JS
853 msg += info->GetBaseClassName1();
854 }
855 else if (info->GetBaseClassName1() && info->GetBaseClassName2())
856 {
223d09f6 857 msg += wxT("is a ");
184b5d99 858 msg += info->GetBaseClassName1() ;
223d09f6 859 msg += wxT(", ");
184b5d99
JS
860 msg += info->GetBaseClassName2() ;
861 }
862 if (info->GetConstructor())
223d09f6 863 msg += wxT(": dynamic");
184b5d99
JS
864
865 wxLogDebug(msg);
c801d85f 866 }
e55ad60e 867 node = wxClassInfo::sm_classTable->Next();
c801d85f
KB
868 n ++;
869 }
223d09f6
KB
870 wxLogDebug(wxT(""));
871 wxLogDebug(wxT("There are %d classes derived from wxObject."), n);
872 wxLogDebug(wxT(""));
873 wxLogDebug(wxT(""));
c801d85f 874 return TRUE;
3f4a0c5b 875}
c801d85f
KB
876
877void wxDebugContext::SetCheckpoint(bool all)
878{
879 if (all)
880 checkPoint = NULL;
881 else
882 checkPoint = m_tail;
883}
884
885// Checks all nodes since checkpoint, or since start.
886int wxDebugContext::Check(bool checkAll)
887{
888 int nFailures = 0;
3f4a0c5b 889
bd7d06f2 890 wxMemStruct *from = (checkPoint ? checkPoint->m_next : (wxMemStruct*)NULL );
c801d85f
KB
891 if (!from || checkAll)
892 from = wxDebugContext::GetHead ();
893
894 for (wxMemStruct * st = from; st != 0; st = st->m_next)
895 {
896 if (st->AssertIt ())
897 nFailures += st->CheckBlock ();
898 else
899 return -1;
900 }
901
902 return nFailures;
903}
904
905// Count the number of non-wxDebugContext-related objects
906// that are outstanding
4fabb575 907int wxDebugContext::CountObjectsLeft(bool sinceCheckpoint)
c801d85f
KB
908{
909 int n = 0;
4fabb575
JS
910
911 wxMemStruct *from = NULL;
912 if (sinceCheckpoint && checkPoint)
913 from = checkPoint->m_next;
9a29912f 914 else
4fabb575 915 from = wxDebugContext::GetHead () ;
c801d85f
KB
916
917 for (wxMemStruct * st = from; st != 0; st = st->m_next)
918 {
919 void* data = st->GetActualData();
184b5d99
JS
920// if ((data != (void*)m_debugStream) && (data != (void*) m_streamBuf))
921 if (data != (void*) wxLog::GetActiveTarget())
c801d85f
KB
922 n ++;
923 }
924
925 return n ;
926}
927
928/*
929 The global operator new used for everything apart from getting
930 dynamic storage within this function itself.
931*/
932
933// We'll only do malloc and free for the moment: leave the interesting
934// stuff for the wxObject versions.
935
ea57084d 936#if defined(__WXDEBUG__) && wxUSE_GLOBAL_MEMORY_OPERATORS
c801d85f
KB
937
938#ifdef new
939#undef new
940#endif
941
942// Seems OK all of a sudden. Maybe to do with linking with multithreaded library?
3f4a0c5b 943#if 0 // def __VISUALC__
c801d85f
KB
944#define NO_DEBUG_ALLOCATION
945#endif
946
947// Unfortunately ~wxDebugStreamBuf doesn't work (VC++ 5) when we enable the debugging
948// code. I have no idea why. In BC++ 4.5, we have a similar problem the debug
949// stream myseriously changing pointer address between being passed from SetFile to SetStream.
950// See docs/msw/issues.txt.
4de6207a 951void * operator new (size_t size, wxChar * fileName, int lineNum)
c801d85f
KB
952{
953#ifdef NO_DEBUG_ALLOCATION
954 return malloc(size);
955#else
956 return wxDebugAlloc(size, fileName, lineNum, FALSE, FALSE);
957#endif
958}
959
7fe7d506
JS
960// Added JACS 25/11/98
961void * operator new (size_t size)
962{
963#ifdef NO_DEBUG_ALLOCATION
964 return malloc(size);
965#else
966 return wxDebugAlloc(size, NULL, 0, FALSE);
967#endif
968}
969
5dcf05ae 970#if wxUSE_ARRAY_MEMORY_OPERATORS
7fe7d506
JS
971void * operator new[] (size_t size)
972{
973#ifdef NO_DEBUG_ALLOCATION
974 return malloc(size);
975#else
976 return wxDebugAlloc(size, NULL, 0, FALSE, TRUE);
977#endif
978}
30c710fd 979#endif
7fe7d506 980
5dcf05ae 981#if wxUSE_ARRAY_MEMORY_OPERATORS
4de6207a 982void * operator new[] (size_t size, wxChar * fileName, int lineNum)
c801d85f
KB
983{
984#ifdef NO_DEBUG_ALLOCATION
985 return malloc(size);
986#else
987 return wxDebugAlloc(size, fileName, lineNum, FALSE, TRUE);
988#endif
989}
5260b1c5 990#endif
c801d85f 991
2bd5bbc9 992#if !defined(__VISAGECPP__) // already defines this by default
c801d85f
KB
993void operator delete (void * buf)
994{
995#ifdef NO_DEBUG_ALLOCATION
996 free((char*) buf);
997#else
998 wxDebugFree(buf);
999#endif
1000}
2bd5bbc9 1001#endif
c801d85f 1002
76626af2 1003// VC++ 6.0
3f4a0c5b 1004#if defined(__VISUALC__) && (__VISUALC__ >= 1200)
4de6207a 1005void operator delete(void* pData, wxChar* /* fileName */, int /* lineNum */)
76626af2 1006{
184b5d99
JS
1007// ::operator delete(pData);
1008 // JACS 21/11/1998: surely we need to call wxDebugFree?
1009 wxDebugFree(pData, FALSE);
1010}
1011// New operator 21/11/1998
1012void operator delete[](void* pData, char* /* fileName */, int /* lineNum */)
1013{
1014 wxDebugFree(pData, TRUE);
76626af2
JS
1015}
1016#endif
1017
5dcf05ae 1018#if wxUSE_ARRAY_MEMORY_OPERATORS
0f358732 1019
c801d85f
KB
1020void operator delete[] (void * buf)
1021{
1022#ifdef NO_DEBUG_ALLOCATION
1023 free((char*) buf);
1024#else
1025 wxDebugFree(buf, TRUE);
1026#endif
1027}
5260b1c5 1028#endif
c801d85f
KB
1029
1030#endif
1031
1032// TODO: store whether this is a vector or not.
4de6207a 1033void * wxDebugAlloc(size_t size, wxChar * fileName, int lineNum, bool isObject, bool WXUNUSED(isVect) )
c801d85f
KB
1034{
1035 // If not in debugging allocation mode, do the normal thing
1036 // so we don't leave any trace of ourselves in the node list.
1037
1038 if (!wxDebugContext::GetDebugMode())
1039 {
1040 return (void *)malloc(size);
1041 }
3f4a0c5b 1042
94b49b93
JS
1043 int totSize = wxDebugContext::TotSize (size);
1044 char * buf = (char *) malloc(totSize);
c801d85f 1045 if (!buf) {
223d09f6 1046 wxLogDebug(wxT("Call to malloc (%ld) failed."), (long)size);
3f4a0c5b 1047 return 0;
c801d85f
KB
1048 }
1049 wxMemStruct * st = (wxMemStruct *)buf;
1050 st->m_firstMarker = MemStartCheck;
1051 st->m_reqSize = size;
1052 st->m_fileName = fileName;
1053 st->m_lineNum = lineNum;
1054 st->m_id = MemStructId;
1055 st->m_prev = 0;
1056 st->m_next = 0;
1057 st->m_isObject = isObject;
1058
1059 // Errors from Append() shouldn't really happen - but just in case!
1060 if (st->Append () == 0) {
3f4a0c5b 1061 st->ErrorMsg ("Trying to append new node");
c801d85f 1062 }
3f4a0c5b 1063
c801d85f 1064 if (wxDebugContext::GetCheckPrevious ()) {
3f4a0c5b
VZ
1065 if (st->CheckAllPrevious () < 0) {
1066 st->ErrorMsg ("Checking previous nodes");
1067 }
c801d85f 1068 }
3f4a0c5b 1069
c801d85f
KB
1070 // Set up the extra markers at the middle and end.
1071 char * ptr = wxDebugContext::MidMarkerPos (buf);
1072 * (wxMarkerType *) ptr = MemMidCheck;
1073 ptr = wxDebugContext::EndMarkerPos (buf, size);
1074 * (wxMarkerType *) ptr = MemEndCheck;
1075
1076 // pointer returned points to the start of the caller's
1077 // usable area.
1078 void *m_actualData = (void *) wxDebugContext::CallerMemPos (buf);
1079 st->m_actualData = m_actualData;
1080
1081 return m_actualData;
1082}
1083
1084// TODO: check whether was allocated as a vector
bd7d06f2 1085void wxDebugFree(void * buf, bool WXUNUSED(isVect) )
c801d85f
KB
1086{
1087 if (!buf)
1088 return;
3f4a0c5b 1089
c801d85f
KB
1090 // If not in debugging allocation mode, do the normal thing
1091 // so we don't leave any trace of ourselves in the node list.
1092 if (!wxDebugContext::GetDebugMode())
1093 {
1094 free((char *)buf);
1095 return;
1096 }
1097
1098 // Points to the start of the entire allocated area.
1099 char * startPointer = wxDebugContext::StartPos ((char *) buf);
1100 // Find the struct and make sure that it's identifiable.
1101 wxMemStruct * st = (wxMemStruct *) wxDebugContext::StructPos (startPointer);
1102
1103 if (! st->ValidateNode ())
3f4a0c5b 1104 return;
c801d85f
KB
1105
1106 // If this is the current checkpoint, we need to
1107 // move the checkpoint back so it points to a valid
1108 // node.
1109 if (st == wxDebugContext::checkPoint)
1110 wxDebugContext::checkPoint = wxDebugContext::checkPoint->m_prev;
1111
1112 if (! st->Unlink ())
1113 {
1114 st->ErrorMsg ("Unlinking deleted node");
1115 }
3f4a0c5b 1116
c801d85f
KB
1117 // Now put in the fill char into the id slot and the caller requested
1118 // memory locations.
1119 st->SetDeleted ();
1120 (void) memset (wxDebugContext::CallerMemPos (startPointer), MemFillChar,
3f4a0c5b 1121 st->RequestSize ());
c801d85f
KB
1122
1123 // Don't allow delayed freeing of memory in this version
1124// if (!wxDebugContext::GetDelayFree())
1125// free((void *)st);
1126 free((char *)st);
1127}
1128
1129// Trace: send output to the current debugging stream
4de6207a 1130void wxTrace(const wxChar *fmt ...)
c801d85f
KB
1131{
1132 va_list ap;
4de6207a 1133 static wxChar buffer[512];
c801d85f
KB
1134
1135 va_start(ap, fmt);
1136
2049ba38 1137#ifdef __WXMSW__
c801d85f
KB
1138 wvsprintf(buffer,fmt,ap) ;
1139#else
1140 vsprintf(buffer,fmt,ap) ;
1141#endif
1142
1143 va_end(ap);
1144
1145 if (wxDebugContext::HasStream())
1146 {
1147 wxDebugContext::GetStream() << buffer;
1148 wxDebugContext::GetStream().flush();
1149 }
1150 else
2049ba38 1151#ifdef __WXMSW__
25889d3c 1152#ifdef __WIN32__
4de6207a 1153 OutputDebugString((LPCTSTR)buffer) ;
25889d3c
JS
1154#else
1155 OutputDebugString((const char*) buffer) ;
1156#endif
c801d85f
KB
1157#else
1158 fprintf(stderr, buffer);
1159#endif
1160}
1161
1162// Trace with level
4de6207a 1163void wxTraceLevel(int level, const wxChar *fmt ...)
c801d85f
KB
1164{
1165 if (wxDebugContext::GetLevel() < level)
1166 return;
3f4a0c5b 1167
c801d85f 1168 va_list ap;
4de6207a 1169 static wxChar buffer[512];
c801d85f
KB
1170
1171 va_start(ap, fmt);
1172
2049ba38 1173#ifdef __WXMSW__
c801d85f
KB
1174 wvsprintf(buffer,fmt,ap) ;
1175#else
1176 vsprintf(buffer,fmt,ap) ;
1177#endif
1178
1179 va_end(ap);
1180
1181 if (wxDebugContext::HasStream())
1182 {
1183 wxDebugContext::GetStream() << buffer;
1184 wxDebugContext::GetStream().flush();
1185 }
1186 else
2049ba38 1187#ifdef __WXMSW__
25889d3c 1188#ifdef __WIN32__
4de6207a 1189 OutputDebugString((LPCTSTR)buffer) ;
25889d3c
JS
1190#else
1191 OutputDebugString((const char*) buffer) ;
1192#endif
c801d85f
KB
1193#else
1194 fprintf(stderr, buffer);
1195#endif
1196}
1197
ea57084d 1198#else // wxUSE_MEMORY_TRACING && defined(__WXDEBUG__)
c801d85f
KB
1199void wxTrace(const char *WXUNUSED(fmt) ...)
1200{
1201}
1202
1203void wxTraceLevel(int WXUNUSED(level), const char *WXUNUSED(fmt) ...)
1204{
1205}
1206#endif
1207