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