]> git.saurik.com Git - wxWidgets.git/blame - src/common/memory.cpp
add wxScrollHelper::ShowScrollbars() (implemented for GTK only right now, generic...
[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 41#if !defined(__WATCOMC__) && !(defined(__VMS__) && ( __VMS_VER < 70000000 ) )\
f172cb82 42 && !defined( __MWERKS__ )
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
aa75d6d9 373 wxDebugContext::OutputDumpLine(msg.c_str());
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;
aa75d6d9 384 wxDebugContext::OutputDumpLine(msg.c_str());
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
6dfbea27
VZ
455// Pointer to global function to call at shutdown
456wxShutdownNotifyFunction wxDebugContext::sm_shutdownFn;
457
c801d85f
KB
458wxDebugContext::wxDebugContext(void)
459{
c801d85f
KB
460}
461
462wxDebugContext::~wxDebugContext(void)
463{
c801d85f 464}
c801d85f
KB
465
466/*
467 Work out the positions of the markers by creating an array of 2 markers
468 and comparing the addresses of the 2 elements. Use this number as the
469 alignment for markers.
470*/
471size_t wxDebugContext::CalcAlignment ()
472{
473 wxMarkerType ar[2];
474 return (char *) &ar[1] - (char *) &ar[0];
475}
476
477
478char * wxDebugContext::StructPos (const char * buf)
479{
480 return (char *) buf;
481}
482
483char * wxDebugContext::MidMarkerPos (const char * buf)
484{
485 return StructPos (buf) + PaddedSize (sizeof (wxMemStruct));
486}
487
488char * wxDebugContext::CallerMemPos (const char * buf)
489{
490 return MidMarkerPos (buf) + PaddedSize (sizeof(wxMarkerType));
491}
492
493
494char * wxDebugContext::EndMarkerPos (const char * buf, const size_t size)
495{
496 return CallerMemPos (buf) + PaddedSize (size);
497}
498
499
500/*
501 Slightly different as this takes a pointer to the start of the caller
502 requested region and returns a pointer to the start of the buffer.
503 */
504char * wxDebugContext::StartPos (const char * caller)
505{
506 return ((char *) (caller - wxDebugContext::PaddedSize (sizeof(wxMarkerType)) -
3f4a0c5b 507 wxDebugContext::PaddedSize (sizeof (wxMemStruct))));
c801d85f
KB
508}
509
510/*
511 We may need padding between various parts of the allocated memory.
512 Given a size of memory, this returns the amount of memory which should
513 be allocated in order to allow for alignment of the following object.
514
515 I don't know how portable this stuff is, but it seems to work for me at
516 the moment. It would be real nice if I knew more about this!
dc1efb1d
JS
517
518 // Note: this function is now obsolete (along with CalcAlignment)
519 // because the calculations are done statically, for greater speed.
c801d85f
KB
520*/
521size_t wxDebugContext::GetPadding (const size_t size)
522{
523 size_t pad = size % CalcAlignment ();
524 return (pad) ? sizeof(wxMarkerType) - pad : 0;
525}
526
c801d85f
KB
527size_t wxDebugContext::PaddedSize (const size_t size)
528{
dc1efb1d
JS
529 // Added by Terry Farnham <TJRT@pacbell.net> to replace
530 // slow GetPadding call.
478e6b71 531 int padb;
dc1efb1d 532
478e6b71
VZ
533 padb = size & m_balignmask;
534 if(padb)
535 return(size + m_balign - padb);
536 else
537 return(size);
c801d85f
KB
538}
539
540/*
541 Returns the total amount of memory which we need to get from the system
542 in order to satisfy a caller request. This includes space for the struct
543 plus markers and the caller's memory as well.
544*/
545size_t wxDebugContext::TotSize (const size_t reqSize)
546{
547 return (PaddedSize (sizeof (wxMemStruct)) + PaddedSize (reqSize) +
3f4a0c5b 548 2 * sizeof(wxMarkerType));
c801d85f
KB
549}
550
551
552/*
553 Traverse the list of nodes executing the given function on each node.
554*/
555void wxDebugContext::TraverseList (PmSFV func, wxMemStruct *from)
556{
557 if (!from)
558 from = wxDebugContext::GetHead ();
3f4a0c5b 559
2db0bbde
JS
560 wxMemStruct * st = NULL;
561 for (st = from; st != 0; st = st->m_next)
c801d85f
KB
562 {
563 void* data = st->GetActualData();
184b5d99
JS
564// if ((data != (void*)m_debugStream) && (data != (void*) m_streamBuf))
565 if (data != (void*) wxLog::GetActiveTarget())
c801d85f
KB
566 {
567 (st->*func) ();
568 }
569 }
570}
571
572
573/*
574 Print out the list.
575 */
576bool wxDebugContext::PrintList (void)
577{
ea57084d 578#ifdef __WXDEBUG__
bd7d06f2 579 TraverseList ((PmSFV)&wxMemStruct::PrintNode, (checkPoint ? checkPoint->m_next : (wxMemStruct*)NULL));
c801d85f 580
6f28211a 581 return true;
c801d85f 582#else
6f28211a 583 return false;
c801d85f
KB
584#endif
585}
586
587bool wxDebugContext::Dump(void)
588{
ea57084d 589#ifdef __WXDEBUG__
c801d85f 590 {
aa75d6d9 591 const wxChar* appName = wxT("application");
6f28211a 592 wxString appNameStr;
c801d85f
KB
593 if (wxTheApp)
594 {
595 appNameStr = wxTheApp->GetAppName();
550cb72b 596 appName = appNameStr.c_str();
5c33522f 597 OutputDumpLine(wxT("----- Memory dump of %s at %s -----"), appName, static_cast<const wxChar *>(wxNow().c_str()));
e55ad60e
RR
598 }
599 else
600 {
ced55544 601 OutputDumpLine( wxT("----- Memory dump -----") );
c801d85f
KB
602 }
603 }
f13b39c0 604
bd7d06f2 605 TraverseList ((PmSFV)&wxMemStruct::Dump, (checkPoint ? checkPoint->m_next : (wxMemStruct*)NULL));
3f4a0c5b 606
6f28211a
DS
607 OutputDumpLine(wxEmptyString);
608 OutputDumpLine(wxEmptyString);
c801d85f 609
6f28211a 610 return true;
c801d85f 611#else
6f28211a 612 return false;
c801d85f
KB
613#endif
614}
615
33ac7e6f 616#ifdef __WXDEBUG__
c801d85f
KB
617struct wxDebugStatsStruct
618{
619 long instanceCount;
620 long totalSize;
4de6207a 621 wxChar *instanceClass;
c801d85f
KB
622 wxDebugStatsStruct *next;
623};
624
4de6207a 625static wxDebugStatsStruct *FindStatsStruct(wxDebugStatsStruct *st, wxChar *name)
c801d85f
KB
626{
627 while (st)
628 {
4de6207a 629 if (wxStrcmp(st->instanceClass, name) == 0)
c801d85f
KB
630 return st;
631 st = st->next;
632 }
633 return NULL;
634}
635
636static wxDebugStatsStruct *InsertStatsStruct(wxDebugStatsStruct *head, wxDebugStatsStruct *st)
637{
638 st->next = head;
639 return st;
640}
33ac7e6f 641#endif
c801d85f
KB
642
643bool wxDebugContext::PrintStatistics(bool detailed)
644{
ea57084d 645#ifdef __WXDEBUG__
e55ad60e 646 {
aa75d6d9 647 const wxChar* appName = wxT("application");
6f28211a 648 wxString appNameStr;
e55ad60e
RR
649 if (wxTheApp)
650 {
651 appNameStr = wxTheApp->GetAppName();
550cb72b 652 appName = appNameStr.c_str();
5c33522f 653 OutputDumpLine(wxT("----- Memory statistics of %s at %s -----"), appName, static_cast<const wxChar *>(wxNow().c_str()));
e55ad60e
RR
654 }
655 else
656 {
ced55544 657 OutputDumpLine( wxT("----- Memory statistics -----") );
e55ad60e
RR
658 }
659 }
3f4a0c5b 660
c801d85f 661 bool currentMode = GetDebugMode();
6f28211a 662 SetDebugMode(false);
3f4a0c5b 663
c801d85f
KB
664 long noNonObjectNodes = 0;
665 long noObjectNodes = 0;
666 long totalSize = 0;
667
668 wxDebugStatsStruct *list = NULL;
669
bd7d06f2 670 wxMemStruct *from = (checkPoint ? checkPoint->m_next : (wxMemStruct*)NULL );
c801d85f
KB
671 if (!from)
672 from = wxDebugContext::GetHead ();
673
3f4a0c5b 674 wxMemStruct *st;
c801d85f
KB
675 for (st = from; st != 0; st = st->m_next)
676 {
677 void* data = st->GetActualData();
b5c70253 678 if (detailed && (data != (void*) wxLog::GetActiveTarget()))
c801d85f 679 {
ba14d986 680 wxChar *className = (wxChar*) wxT("nonobject");
c801d85f
KB
681 if (st->m_isObject && st->GetActualData())
682 {
683 wxObject *obj = (wxObject *)st->GetActualData();
684 if (obj->GetClassInfo()->GetClassName())
abe5726a 685 className = (wxChar*)obj->GetClassInfo()->GetClassName();
c801d85f
KB
686 }
687 wxDebugStatsStruct *stats = FindStatsStruct(list, className);
688 if (!stats)
689 {
690 stats = (wxDebugStatsStruct *)malloc(sizeof(wxDebugStatsStruct));
691 stats->instanceClass = className;
692 stats->instanceCount = 0;
693 stats->totalSize = 0;
694 list = InsertStatsStruct(list, stats);
695 }
696 stats->instanceCount ++;
697 stats->totalSize += st->RequestSize();
698 }
699
184b5d99 700 if (data != (void*) wxLog::GetActiveTarget())
c801d85f
KB
701 {
702 totalSize += st->RequestSize();
703 if (st->m_isObject)
704 noObjectNodes ++;
705 else
706 noNonObjectNodes ++;
707 }
708 }
709
710 if (detailed)
711 {
712 while (list)
713 {
ced55544 714 OutputDumpLine(wxT("%ld objects of class %s, total size %ld"),
c801d85f
KB
715 list->instanceCount, list->instanceClass, list->totalSize);
716 wxDebugStatsStruct *old = list;
717 list = old->next;
718 free((char *)old);
719 }
6f28211a 720 OutputDumpLine(wxEmptyString);
c801d85f 721 }
3f4a0c5b 722
c801d85f
KB
723 SetDebugMode(currentMode);
724
ced55544
VS
725 OutputDumpLine(wxT("Number of object items: %ld"), noObjectNodes);
726 OutputDumpLine(wxT("Number of non-object items: %ld"), noNonObjectNodes);
727 OutputDumpLine(wxT("Total allocated size: %ld"), totalSize);
6f28211a
DS
728 OutputDumpLine(wxEmptyString);
729 OutputDumpLine(wxEmptyString);
c801d85f 730
6f28211a 731 return true;
c801d85f 732#else
33ac7e6f 733 (void)detailed;
6f28211a 734 return false;
c801d85f 735#endif
3f4a0c5b 736}
c801d85f
KB
737
738bool wxDebugContext::PrintClasses(void)
739{
c801d85f 740 {
aa75d6d9 741 const wxChar* appName = wxT("application");
6f28211a 742 wxString appNameStr;
c801d85f
KB
743 if (wxTheApp)
744 {
745 appNameStr = wxTheApp->GetAppName();
550cb72b 746 appName = appNameStr.c_str();
5fa399c9 747 wxLogMessage(wxT("----- Classes in %s -----"), appName);
c801d85f
KB
748 }
749 }
750
751 int n = 0;
644cb537 752 const wxClassInfo *info;
f4a8c29f 753
644cb537
MB
754 for (wxClassInfo::const_iterator node = wxClassInfo::begin_classinfo(),
755 end = wxClassInfo::end_classinfo();
756 node != end; ++node)
c801d85f 757 {
644cb537 758 info = *node;
c801d85f
KB
759 if (info->GetClassName())
760 {
184b5d99 761 wxString msg(info->GetClassName());
223d09f6 762 msg += wxT(" ");
184b5d99
JS
763
764 if (info->GetBaseClassName1() && !info->GetBaseClassName2())
765 {
223d09f6 766 msg += wxT("is a ");
184b5d99
JS
767 msg += info->GetBaseClassName1();
768 }
769 else if (info->GetBaseClassName1() && info->GetBaseClassName2())
770 {
223d09f6 771 msg += wxT("is a ");
184b5d99 772 msg += info->GetBaseClassName1() ;
223d09f6 773 msg += wxT(", ");
184b5d99
JS
774 msg += info->GetBaseClassName2() ;
775 }
776 if (info->GetConstructor())
223d09f6 777 msg += wxT(": dynamic");
184b5d99 778
5fa399c9 779 wxLogMessage(msg);
c801d85f 780 }
c801d85f
KB
781 n ++;
782 }
6f28211a 783 wxLogMessage(wxEmptyString);
5fa399c9 784 wxLogMessage(wxT("There are %d classes derived from wxObject."), n);
6f28211a
DS
785 wxLogMessage(wxEmptyString);
786 wxLogMessage(wxEmptyString);
787 return true;
3f4a0c5b 788}
c801d85f
KB
789
790void wxDebugContext::SetCheckpoint(bool all)
791{
792 if (all)
793 checkPoint = NULL;
794 else
795 checkPoint = m_tail;
796}
797
798// Checks all nodes since checkpoint, or since start.
799int wxDebugContext::Check(bool checkAll)
800{
801 int nFailures = 0;
3f4a0c5b 802
bd7d06f2 803 wxMemStruct *from = (checkPoint ? checkPoint->m_next : (wxMemStruct*)NULL );
c801d85f
KB
804 if (!from || checkAll)
805 from = wxDebugContext::GetHead ();
806
807 for (wxMemStruct * st = from; st != 0; st = st->m_next)
808 {
809 if (st->AssertIt ())
810 nFailures += st->CheckBlock ();
811 else
812 return -1;
813 }
814
815 return nFailures;
816}
817
818// Count the number of non-wxDebugContext-related objects
819// that are outstanding
4fabb575 820int wxDebugContext::CountObjectsLeft(bool sinceCheckpoint)
c801d85f
KB
821{
822 int n = 0;
4fabb575
JS
823
824 wxMemStruct *from = NULL;
825 if (sinceCheckpoint && checkPoint)
826 from = checkPoint->m_next;
9a29912f 827 else
4fabb575 828 from = wxDebugContext::GetHead () ;
c801d85f
KB
829
830 for (wxMemStruct * st = from; st != 0; st = st->m_next)
831 {
832 void* data = st->GetActualData();
184b5d99 833 if (data != (void*) wxLog::GetActiveTarget())
c801d85f
KB
834 n ++;
835 }
836
837 return n ;
838}
839
ced55544
VS
840// This function is used to output the dump
841void wxDebugContext::OutputDumpLine(const wxChar *szFormat, ...)
842{
843 // a buffer of 2048 bytes should be long enough for a file name
844 // and a class name
845 wxChar buf[2048];
846 int count;
847 va_list argptr;
848 va_start(argptr, szFormat);
eabc6e3c 849 buf[sizeof(buf)/sizeof(wxChar)-1] = _T('\0');
ced55544
VS
850
851 // keep 3 bytes for a \r\n\0
eabc6e3c 852 count = wxVsnprintf(buf, sizeof(buf)/sizeof(wxChar)-3, szFormat, argptr);
ced55544
VS
853
854 if ( count < 0 )
eabc6e3c 855 count = sizeof(buf)/sizeof(wxChar)-3;
ced55544
VS
856 buf[count]=_T('\r');
857 buf[count+1]=_T('\n');
858 buf[count+2]=_T('\0');
859
860 wxMessageOutputDebug dbgout;
861 dbgout.Printf(buf);
862}
863
6dfbea27
VZ
864void wxDebugContext::SetShutdownNotifyFunction(wxShutdownNotifyFunction shutdownFn)
865{
866 sm_shutdownFn = shutdownFn;
867}
868
ced55544 869
0fd28ea3 870#if USE_THREADSAFE_MEMORY_ALLOCATION
6f28211a 871static bool memSectionOk = false;
b5c70253
JS
872
873class MemoryCriticalSection : public wxCriticalSection
874{
875public:
ce1c6745
DS
876 MemoryCriticalSection() {
877 memSectionOk = true;
878 }
a83ea9c1
JS
879 ~MemoryCriticalSection() {
880 memSectionOk = false;
881 }
b5c70253
JS
882};
883
884class MemoryCriticalSectionLocker
885{
886public:
887 inline MemoryCriticalSectionLocker(wxCriticalSection& critsect)
ce1c6745 888 : m_critsect(critsect), m_locked(memSectionOk) { if(m_locked) m_critsect.Enter(); }
b5c70253 889 inline ~MemoryCriticalSectionLocker() { if(m_locked) m_critsect.Leave(); }
f13b39c0 890
b5c70253
JS
891private:
892 // no assignment operator nor copy ctor
893 MemoryCriticalSectionLocker(const MemoryCriticalSectionLocker&);
894 MemoryCriticalSectionLocker& operator=(const MemoryCriticalSectionLocker&);
f13b39c0 895
b5c70253 896 wxCriticalSection& m_critsect;
ce1c6745 897 bool m_locked;
b5c70253
JS
898};
899
a83ea9c1 900static MemoryCriticalSection memLocker;
aaf1bbfd 901
766a1d00
VZ
902#endif // USE_THREADSAFE_MEMORY_ALLOCATION
903
aaf1bbfd 904
fa6ca47e 905#ifdef __WXDEBUG__
766a1d00 906#if !(defined(__WXMSW__) && (defined(WXUSINGDLL) || defined(WXMAKINGDLL_BASE)))
fa6ca47e 907#if wxUSE_GLOBAL_MEMORY_OPERATORS
aaf1bbfd
JS
908void * operator new (size_t size, wxChar * fileName, int lineNum)
909{
910 return wxDebugAlloc(size, fileName, lineNum, false, false);
3d2eaa5d
DS
911}
912
aaf1bbfd
JS
913void * operator new (size_t size)
914{
915 return wxDebugAlloc(size, NULL, 0, false);
916}
917
918void operator delete (void * buf)
919{
920 wxDebugFree(buf, false);
921}
922
923#if wxUSE_ARRAY_MEMORY_OPERATORS
924void * operator new[] (size_t size)
925{
926 return wxDebugAlloc(size, NULL, 0, false, true);
927}
928
929void * operator new[] (size_t size, wxChar * fileName, int lineNum)
930{
931 return wxDebugAlloc(size, fileName, lineNum, false, true);
932}
933
934void operator delete[] (void * buf)
935{
936 wxDebugFree(buf, true);
937}
241421a6 938#endif // wxUSE_ARRAY_MEMORY_OPERATORS
5a7d1ad8 939#endif // wxUSE_GLOBAL_MEMORY_OPERATORS
766a1d00 940#endif // !(defined(__WXMSW__) && (defined(WXUSINGDLL) || defined(WXMAKINGDLL_BASE)))
b5c70253 941
c801d85f 942// TODO: store whether this is a vector or not.
4de6207a 943void * wxDebugAlloc(size_t size, wxChar * fileName, int lineNum, bool isObject, bool WXUNUSED(isVect) )
c801d85f 944{
0fd28ea3 945#if USE_THREADSAFE_MEMORY_ALLOCATION
aaf1bbfd 946 MemoryCriticalSectionLocker lock(memLocker);
b5c70253 947#endif
f13b39c0 948
c801d85f
KB
949 // If not in debugging allocation mode, do the normal thing
950 // so we don't leave any trace of ourselves in the node list.
951
86b3203f
DW
952#if defined(__VISAGECPP__) && (__IBMCPP__ < 400 || __IBMC__ < 400 )
953// VA 3.0 still has trouble in here
954 return (void *)malloc(size);
955#endif
c801d85f
KB
956 if (!wxDebugContext::GetDebugMode())
957 {
958 return (void *)malloc(size);
959 }
3f4a0c5b 960
94b49b93
JS
961 int totSize = wxDebugContext::TotSize (size);
962 char * buf = (char *) malloc(totSize);
c801d85f 963 if (!buf) {
5fa399c9 964 wxLogMessage(wxT("Call to malloc (%ld) failed."), (long)size);
3f4a0c5b 965 return 0;
c801d85f
KB
966 }
967 wxMemStruct * st = (wxMemStruct *)buf;
968 st->m_firstMarker = MemStartCheck;
969 st->m_reqSize = size;
970 st->m_fileName = fileName;
971 st->m_lineNum = lineNum;
972 st->m_id = MemStructId;
973 st->m_prev = 0;
974 st->m_next = 0;
975 st->m_isObject = isObject;
976
977 // Errors from Append() shouldn't really happen - but just in case!
978 if (st->Append () == 0) {
3f4a0c5b 979 st->ErrorMsg ("Trying to append new node");
c801d85f 980 }
3f4a0c5b 981
c801d85f 982 if (wxDebugContext::GetCheckPrevious ()) {
3f4a0c5b
VZ
983 if (st->CheckAllPrevious () < 0) {
984 st->ErrorMsg ("Checking previous nodes");
985 }
c801d85f 986 }
3f4a0c5b 987
c801d85f
KB
988 // Set up the extra markers at the middle and end.
989 char * ptr = wxDebugContext::MidMarkerPos (buf);
990 * (wxMarkerType *) ptr = MemMidCheck;
991 ptr = wxDebugContext::EndMarkerPos (buf, size);
992 * (wxMarkerType *) ptr = MemEndCheck;
993
994 // pointer returned points to the start of the caller's
995 // usable area.
996 void *m_actualData = (void *) wxDebugContext::CallerMemPos (buf);
997 st->m_actualData = m_actualData;
998
999 return m_actualData;
1000}
1001
1002// TODO: check whether was allocated as a vector
bd7d06f2 1003void wxDebugFree(void * buf, bool WXUNUSED(isVect) )
c801d85f 1004{
0fd28ea3 1005#if USE_THREADSAFE_MEMORY_ALLOCATION
aaf1bbfd 1006 MemoryCriticalSectionLocker lock(memLocker);
b5c70253 1007#endif
f13b39c0 1008
c801d85f
KB
1009 if (!buf)
1010 return;
3f4a0c5b 1011
86b3203f
DW
1012#if defined(__VISAGECPP__) && (__IBMCPP__ < 400 || __IBMC__ < 400 )
1013// VA 3.0 still has trouble in here
1014 free((char *)buf);
1015#endif
c801d85f
KB
1016 // If not in debugging allocation mode, do the normal thing
1017 // so we don't leave any trace of ourselves in the node list.
1018 if (!wxDebugContext::GetDebugMode())
1019 {
1020 free((char *)buf);
1021 return;
1022 }
1023
1024 // Points to the start of the entire allocated area.
1025 char * startPointer = wxDebugContext::StartPos ((char *) buf);
1026 // Find the struct and make sure that it's identifiable.
1027 wxMemStruct * st = (wxMemStruct *) wxDebugContext::StructPos (startPointer);
1028
1029 if (! st->ValidateNode ())
3f4a0c5b 1030 return;
c801d85f
KB
1031
1032 // If this is the current checkpoint, we need to
1033 // move the checkpoint back so it points to a valid
1034 // node.
1035 if (st == wxDebugContext::checkPoint)
1036 wxDebugContext::checkPoint = wxDebugContext::checkPoint->m_prev;
1037
1038 if (! st->Unlink ())
1039 {
1040 st->ErrorMsg ("Unlinking deleted node");
1041 }
3f4a0c5b 1042
c801d85f
KB
1043 // Now put in the fill char into the id slot and the caller requested
1044 // memory locations.
1045 st->SetDeleted ();
1046 (void) memset (wxDebugContext::CallerMemPos (startPointer), MemFillChar,
3f4a0c5b 1047 st->RequestSize ());
c801d85f 1048
c801d85f
KB
1049 free((char *)st);
1050}
1051
fa6ca47e
RR
1052#endif // __WXDEBUG__
1053
c801d85f 1054// Trace: send output to the current debugging stream
33ac7e6f 1055void wxTrace(const wxChar * ...)
c801d85f 1056{
f6bcfd97
BP
1057#if 1
1058 wxFAIL_MSG(wxT("wxTrace is now obsolete. Please use wxDebugXXX instead."));
1059#else
1060 va_list ap;
4de6207a 1061 static wxChar buffer[512];
c801d85f
KB
1062
1063 va_start(ap, fmt);
1064
2049ba38 1065#ifdef __WXMSW__
c801d85f
KB
1066 wvsprintf(buffer,fmt,ap) ;
1067#else
1068 vsprintf(buffer,fmt,ap) ;
1069#endif
1070
1071 va_end(ap);
1072
1073 if (wxDebugContext::HasStream())
1074 {
1075 wxDebugContext::GetStream() << buffer;
1076 wxDebugContext::GetStream().flush();
1077 }
1078 else
2049ba38 1079#ifdef __WXMSW__
25889d3c 1080#ifdef __WIN32__
4de6207a 1081 OutputDebugString((LPCTSTR)buffer) ;
25889d3c
JS
1082#else
1083 OutputDebugString((const char*) buffer) ;
1084#endif
c801d85f
KB
1085#else
1086 fprintf(stderr, buffer);
1087#endif
f6bcfd97 1088#endif
c801d85f
KB
1089}
1090
1091// Trace with level
33ac7e6f 1092void wxTraceLevel(int, const wxChar * ...)
c801d85f 1093{
f6bcfd97
BP
1094#if 1
1095 wxFAIL_MSG(wxT("wxTrace is now obsolete. Please use wxDebugXXX instead."));
1096#else
c801d85f
KB
1097 if (wxDebugContext::GetLevel() < level)
1098 return;
3f4a0c5b 1099
c801d85f 1100 va_list ap;
4de6207a 1101 static wxChar buffer[512];
c801d85f
KB
1102
1103 va_start(ap, fmt);
1104
2049ba38 1105#ifdef __WXMSW__
f6bcfd97 1106 wxWvsprintf(buffer,fmt,ap) ;
c801d85f
KB
1107#else
1108 vsprintf(buffer,fmt,ap) ;
1109#endif
1110
1111 va_end(ap);
1112
1113 if (wxDebugContext::HasStream())
1114 {
1115 wxDebugContext::GetStream() << buffer;
1116 wxDebugContext::GetStream().flush();
1117 }
1118 else
2049ba38 1119#ifdef __WXMSW__
25889d3c 1120#ifdef __WIN32__
4de6207a 1121 OutputDebugString((LPCTSTR)buffer) ;
25889d3c
JS
1122#else
1123 OutputDebugString((const char*) buffer) ;
1124#endif
c801d85f
KB
1125#else
1126 fprintf(stderr, buffer);
1127#endif
f6bcfd97 1128#endif
c801d85f
KB
1129}
1130
ced55544 1131//----------------------------------------------------------------------------
df1f4832 1132// Final cleanup after all global objects in all files have been destroyed
ced55544
VS
1133//----------------------------------------------------------------------------
1134
1135// Don't set it to 0 by dynamic initialization
df1f4832 1136// Some compilers will really do the assignment later
ced55544
VS
1137// All global variables are initialized to 0 at the very beginning, and this is just fine.
1138int wxDebugContextDumpDelayCounter::sm_count;
1139
6dfbea27
VZ
1140wxDebugContextDumpDelayCounter::wxDebugContextDumpDelayCounter()
1141{
1142 sm_count++;
1143}
1144
1145wxDebugContextDumpDelayCounter::~wxDebugContextDumpDelayCounter()
1146{
1147 if ( !--sm_count )
1148 {
1149 // Notify app if we've been asked to do that
1150 if( wxDebugContext::sm_shutdownFn )
1151 wxDebugContext::sm_shutdownFn();
1152 DoDump();
1153 }
1154}
1155
ced55544
VS
1156void wxDebugContextDumpDelayCounter::DoDump()
1157{
6f28211a 1158 if (wxDebugContext::CountObjectsLeft(true) > 0)
ced55544
VS
1159 {
1160 wxDebugContext::OutputDumpLine(wxT("There were memory leaks.\n"));
1161 wxDebugContext::Dump();
1162 wxDebugContext::PrintStatistics();
1163 }
1164}
1165
1166// Even if there is nothing else, make sure that there is at
df1f4832 1167// least one cleanup counter object
ced55544
VS
1168static wxDebugContextDumpDelayCounter wxDebugContextDumpDelayCounter_One;
1169
1170#endif // (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT