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