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