]> git.saurik.com Git - wxWidgets.git/blame - src/common/memory.cpp
Merge new item attributes if any are already existing
[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;
d772bf43 749 wxHashTable::compatibility_iterator node;
f4a8c29f
GL
750 wxClassInfo *info;
751
0c32066b
JS
752 wxClassInfo::sm_classTable->BeginFind();
753 node = wxClassInfo::sm_classTable->Next();
f4a8c29f 754 while (node)
c801d85f 755 {
f2dec5b1 756 info = (wxClassInfo *)node->GetData();
c801d85f
KB
757 if (info->GetClassName())
758 {
184b5d99 759 wxString msg(info->GetClassName());
223d09f6 760 msg += wxT(" ");
184b5d99
JS
761
762 if (info->GetBaseClassName1() && !info->GetBaseClassName2())
763 {
223d09f6 764 msg += wxT("is a ");
184b5d99
JS
765 msg += info->GetBaseClassName1();
766 }
767 else if (info->GetBaseClassName1() && info->GetBaseClassName2())
768 {
223d09f6 769 msg += wxT("is a ");
184b5d99 770 msg += info->GetBaseClassName1() ;
223d09f6 771 msg += wxT(", ");
184b5d99
JS
772 msg += info->GetBaseClassName2() ;
773 }
774 if (info->GetConstructor())
223d09f6 775 msg += wxT(": dynamic");
184b5d99 776
5fa399c9 777 wxLogMessage(msg);
c801d85f 778 }
e55ad60e 779 node = wxClassInfo::sm_classTable->Next();
c801d85f
KB
780 n ++;
781 }
6f28211a 782 wxLogMessage(wxEmptyString);
5fa399c9 783 wxLogMessage(wxT("There are %d classes derived from wxObject."), n);
6f28211a
DS
784 wxLogMessage(wxEmptyString);
785 wxLogMessage(wxEmptyString);
786 return true;
3f4a0c5b 787}
c801d85f
KB
788
789void wxDebugContext::SetCheckpoint(bool all)
790{
791 if (all)
792 checkPoint = NULL;
793 else
794 checkPoint = m_tail;
795}
796
797// Checks all nodes since checkpoint, or since start.
798int wxDebugContext::Check(bool checkAll)
799{
800 int nFailures = 0;
3f4a0c5b 801
bd7d06f2 802 wxMemStruct *from = (checkPoint ? checkPoint->m_next : (wxMemStruct*)NULL );
c801d85f
KB
803 if (!from || checkAll)
804 from = wxDebugContext::GetHead ();
805
806 for (wxMemStruct * st = from; st != 0; st = st->m_next)
807 {
808 if (st->AssertIt ())
809 nFailures += st->CheckBlock ();
810 else
811 return -1;
812 }
813
814 return nFailures;
815}
816
817// Count the number of non-wxDebugContext-related objects
818// that are outstanding
4fabb575 819int wxDebugContext::CountObjectsLeft(bool sinceCheckpoint)
c801d85f
KB
820{
821 int n = 0;
4fabb575
JS
822
823 wxMemStruct *from = NULL;
824 if (sinceCheckpoint && checkPoint)
825 from = checkPoint->m_next;
9a29912f 826 else
4fabb575 827 from = wxDebugContext::GetHead () ;
c801d85f
KB
828
829 for (wxMemStruct * st = from; st != 0; st = st->m_next)
830 {
831 void* data = st->GetActualData();
184b5d99 832 if (data != (void*) wxLog::GetActiveTarget())
c801d85f
KB
833 n ++;
834 }
835
836 return n ;
837}
838
ced55544
VS
839// This function is used to output the dump
840void wxDebugContext::OutputDumpLine(const wxChar *szFormat, ...)
841{
842 // a buffer of 2048 bytes should be long enough for a file name
843 // and a class name
844 wxChar buf[2048];
845 int count;
846 va_list argptr;
847 va_start(argptr, szFormat);
eabc6e3c 848 buf[sizeof(buf)/sizeof(wxChar)-1] = _T('\0');
ced55544
VS
849
850 // keep 3 bytes for a \r\n\0
eabc6e3c 851 count = wxVsnprintf(buf, sizeof(buf)/sizeof(wxChar)-3, szFormat, argptr);
ced55544
VS
852
853 if ( count < 0 )
eabc6e3c 854 count = sizeof(buf)/sizeof(wxChar)-3;
ced55544
VS
855 buf[count]=_T('\r');
856 buf[count+1]=_T('\n');
857 buf[count+2]=_T('\0');
858
859 wxMessageOutputDebug dbgout;
860 dbgout.Printf(buf);
861}
862
863
0fd28ea3 864#if USE_THREADSAFE_MEMORY_ALLOCATION
6f28211a 865static bool memSectionOk = false;
b5c70253
JS
866
867class MemoryCriticalSection : public wxCriticalSection
868{
869public:
ce1c6745
DS
870 MemoryCriticalSection() {
871 memSectionOk = true;
872 }
a83ea9c1
JS
873 ~MemoryCriticalSection() {
874 memSectionOk = false;
875 }
b5c70253
JS
876};
877
878class MemoryCriticalSectionLocker
879{
880public:
881 inline MemoryCriticalSectionLocker(wxCriticalSection& critsect)
ce1c6745 882 : m_critsect(critsect), m_locked(memSectionOk) { if(m_locked) m_critsect.Enter(); }
b5c70253 883 inline ~MemoryCriticalSectionLocker() { if(m_locked) m_critsect.Leave(); }
f13b39c0 884
b5c70253
JS
885private:
886 // no assignment operator nor copy ctor
887 MemoryCriticalSectionLocker(const MemoryCriticalSectionLocker&);
888 MemoryCriticalSectionLocker& operator=(const MemoryCriticalSectionLocker&);
f13b39c0 889
b5c70253 890 wxCriticalSection& m_critsect;
ce1c6745 891 bool m_locked;
b5c70253
JS
892};
893
a83ea9c1 894static MemoryCriticalSection memLocker;
aaf1bbfd 895
766a1d00
VZ
896#endif // USE_THREADSAFE_MEMORY_ALLOCATION
897
aaf1bbfd 898
fa6ca47e 899#ifdef __WXDEBUG__
766a1d00 900#if !(defined(__WXMSW__) && (defined(WXUSINGDLL) || defined(WXMAKINGDLL_BASE)))
fa6ca47e 901#if wxUSE_GLOBAL_MEMORY_OPERATORS
aaf1bbfd
JS
902void * operator new (size_t size, wxChar * fileName, int lineNum)
903{
904 return wxDebugAlloc(size, fileName, lineNum, false, false);
3d2eaa5d
DS
905}
906
aaf1bbfd
JS
907void * operator new (size_t size)
908{
909 return wxDebugAlloc(size, NULL, 0, false);
910}
911
912void operator delete (void * buf)
913{
914 wxDebugFree(buf, false);
915}
916
917#if wxUSE_ARRAY_MEMORY_OPERATORS
918void * operator new[] (size_t size)
919{
920 return wxDebugAlloc(size, NULL, 0, false, true);
921}
922
923void * operator new[] (size_t size, wxChar * fileName, int lineNum)
924{
925 return wxDebugAlloc(size, fileName, lineNum, false, true);
926}
927
928void operator delete[] (void * buf)
929{
930 wxDebugFree(buf, true);
931}
241421a6 932#endif // wxUSE_ARRAY_MEMORY_OPERATORS
5a7d1ad8 933#endif // wxUSE_GLOBAL_MEMORY_OPERATORS
766a1d00 934#endif // !(defined(__WXMSW__) && (defined(WXUSINGDLL) || defined(WXMAKINGDLL_BASE)))
b5c70253 935
c801d85f 936// TODO: store whether this is a vector or not.
4de6207a 937void * wxDebugAlloc(size_t size, wxChar * fileName, int lineNum, bool isObject, bool WXUNUSED(isVect) )
c801d85f 938{
0fd28ea3 939#if USE_THREADSAFE_MEMORY_ALLOCATION
aaf1bbfd 940 MemoryCriticalSectionLocker lock(memLocker);
b5c70253 941#endif
f13b39c0 942
c801d85f
KB
943 // If not in debugging allocation mode, do the normal thing
944 // so we don't leave any trace of ourselves in the node list.
945
86b3203f
DW
946#if defined(__VISAGECPP__) && (__IBMCPP__ < 400 || __IBMC__ < 400 )
947// VA 3.0 still has trouble in here
948 return (void *)malloc(size);
949#endif
c801d85f
KB
950 if (!wxDebugContext::GetDebugMode())
951 {
952 return (void *)malloc(size);
953 }
3f4a0c5b 954
94b49b93
JS
955 int totSize = wxDebugContext::TotSize (size);
956 char * buf = (char *) malloc(totSize);
c801d85f 957 if (!buf) {
5fa399c9 958 wxLogMessage(wxT("Call to malloc (%ld) failed."), (long)size);
3f4a0c5b 959 return 0;
c801d85f
KB
960 }
961 wxMemStruct * st = (wxMemStruct *)buf;
962 st->m_firstMarker = MemStartCheck;
963 st->m_reqSize = size;
964 st->m_fileName = fileName;
965 st->m_lineNum = lineNum;
966 st->m_id = MemStructId;
967 st->m_prev = 0;
968 st->m_next = 0;
969 st->m_isObject = isObject;
970
971 // Errors from Append() shouldn't really happen - but just in case!
972 if (st->Append () == 0) {
3f4a0c5b 973 st->ErrorMsg ("Trying to append new node");
c801d85f 974 }
3f4a0c5b 975
c801d85f 976 if (wxDebugContext::GetCheckPrevious ()) {
3f4a0c5b
VZ
977 if (st->CheckAllPrevious () < 0) {
978 st->ErrorMsg ("Checking previous nodes");
979 }
c801d85f 980 }
3f4a0c5b 981
c801d85f
KB
982 // Set up the extra markers at the middle and end.
983 char * ptr = wxDebugContext::MidMarkerPos (buf);
984 * (wxMarkerType *) ptr = MemMidCheck;
985 ptr = wxDebugContext::EndMarkerPos (buf, size);
986 * (wxMarkerType *) ptr = MemEndCheck;
987
988 // pointer returned points to the start of the caller's
989 // usable area.
990 void *m_actualData = (void *) wxDebugContext::CallerMemPos (buf);
991 st->m_actualData = m_actualData;
992
993 return m_actualData;
994}
995
996// TODO: check whether was allocated as a vector
bd7d06f2 997void wxDebugFree(void * buf, bool WXUNUSED(isVect) )
c801d85f 998{
0fd28ea3 999#if USE_THREADSAFE_MEMORY_ALLOCATION
aaf1bbfd 1000 MemoryCriticalSectionLocker lock(memLocker);
b5c70253 1001#endif
f13b39c0 1002
c801d85f
KB
1003 if (!buf)
1004 return;
3f4a0c5b 1005
86b3203f
DW
1006#if defined(__VISAGECPP__) && (__IBMCPP__ < 400 || __IBMC__ < 400 )
1007// VA 3.0 still has trouble in here
1008 free((char *)buf);
1009#endif
c801d85f
KB
1010 // If not in debugging allocation mode, do the normal thing
1011 // so we don't leave any trace of ourselves in the node list.
1012 if (!wxDebugContext::GetDebugMode())
1013 {
1014 free((char *)buf);
1015 return;
1016 }
1017
1018 // Points to the start of the entire allocated area.
1019 char * startPointer = wxDebugContext::StartPos ((char *) buf);
1020 // Find the struct and make sure that it's identifiable.
1021 wxMemStruct * st = (wxMemStruct *) wxDebugContext::StructPos (startPointer);
1022
1023 if (! st->ValidateNode ())
3f4a0c5b 1024 return;
c801d85f
KB
1025
1026 // If this is the current checkpoint, we need to
1027 // move the checkpoint back so it points to a valid
1028 // node.
1029 if (st == wxDebugContext::checkPoint)
1030 wxDebugContext::checkPoint = wxDebugContext::checkPoint->m_prev;
1031
1032 if (! st->Unlink ())
1033 {
1034 st->ErrorMsg ("Unlinking deleted node");
1035 }
3f4a0c5b 1036
c801d85f
KB
1037 // Now put in the fill char into the id slot and the caller requested
1038 // memory locations.
1039 st->SetDeleted ();
1040 (void) memset (wxDebugContext::CallerMemPos (startPointer), MemFillChar,
3f4a0c5b 1041 st->RequestSize ());
c801d85f 1042
c801d85f
KB
1043 free((char *)st);
1044}
1045
fa6ca47e
RR
1046#endif // __WXDEBUG__
1047
c801d85f 1048// Trace: send output to the current debugging stream
33ac7e6f 1049void wxTrace(const wxChar * ...)
c801d85f 1050{
f6bcfd97
BP
1051#if 1
1052 wxFAIL_MSG(wxT("wxTrace is now obsolete. Please use wxDebugXXX instead."));
1053#else
1054 va_list ap;
4de6207a 1055 static wxChar buffer[512];
c801d85f
KB
1056
1057 va_start(ap, fmt);
1058
2049ba38 1059#ifdef __WXMSW__
c801d85f
KB
1060 wvsprintf(buffer,fmt,ap) ;
1061#else
1062 vsprintf(buffer,fmt,ap) ;
1063#endif
1064
1065 va_end(ap);
1066
1067 if (wxDebugContext::HasStream())
1068 {
1069 wxDebugContext::GetStream() << buffer;
1070 wxDebugContext::GetStream().flush();
1071 }
1072 else
2049ba38 1073#ifdef __WXMSW__
25889d3c 1074#ifdef __WIN32__
4de6207a 1075 OutputDebugString((LPCTSTR)buffer) ;
25889d3c
JS
1076#else
1077 OutputDebugString((const char*) buffer) ;
1078#endif
c801d85f
KB
1079#else
1080 fprintf(stderr, buffer);
1081#endif
f6bcfd97 1082#endif
c801d85f
KB
1083}
1084
1085// Trace with level
33ac7e6f 1086void wxTraceLevel(int, const wxChar * ...)
c801d85f 1087{
f6bcfd97
BP
1088#if 1
1089 wxFAIL_MSG(wxT("wxTrace is now obsolete. Please use wxDebugXXX instead."));
1090#else
c801d85f
KB
1091 if (wxDebugContext::GetLevel() < level)
1092 return;
3f4a0c5b 1093
c801d85f 1094 va_list ap;
4de6207a 1095 static wxChar buffer[512];
c801d85f
KB
1096
1097 va_start(ap, fmt);
1098
2049ba38 1099#ifdef __WXMSW__
f6bcfd97 1100 wxWvsprintf(buffer,fmt,ap) ;
c801d85f
KB
1101#else
1102 vsprintf(buffer,fmt,ap) ;
1103#endif
1104
1105 va_end(ap);
1106
1107 if (wxDebugContext::HasStream())
1108 {
1109 wxDebugContext::GetStream() << buffer;
1110 wxDebugContext::GetStream().flush();
1111 }
1112 else
2049ba38 1113#ifdef __WXMSW__
25889d3c 1114#ifdef __WIN32__
4de6207a 1115 OutputDebugString((LPCTSTR)buffer) ;
25889d3c
JS
1116#else
1117 OutputDebugString((const char*) buffer) ;
1118#endif
c801d85f
KB
1119#else
1120 fprintf(stderr, buffer);
1121#endif
f6bcfd97 1122#endif
c801d85f
KB
1123}
1124
ced55544 1125//----------------------------------------------------------------------------
df1f4832 1126// Final cleanup after all global objects in all files have been destroyed
ced55544
VS
1127//----------------------------------------------------------------------------
1128
1129// Don't set it to 0 by dynamic initialization
df1f4832 1130// Some compilers will really do the assignment later
ced55544
VS
1131// All global variables are initialized to 0 at the very beginning, and this is just fine.
1132int wxDebugContextDumpDelayCounter::sm_count;
1133
1134void wxDebugContextDumpDelayCounter::DoDump()
1135{
6f28211a 1136 if (wxDebugContext::CountObjectsLeft(true) > 0)
ced55544
VS
1137 {
1138 wxDebugContext::OutputDumpLine(wxT("There were memory leaks.\n"));
1139 wxDebugContext::Dump();
1140 wxDebugContext::PrintStatistics();
1141 }
1142}
1143
1144// Even if there is nothing else, make sure that there is at
df1f4832 1145// least one cleanup counter object
ced55544
VS
1146static wxDebugContextDumpDelayCounter wxDebugContextDumpDelayCounter_One;
1147
1148#endif // (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT