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