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