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