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