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