]> git.saurik.com Git - wxWidgets.git/blame - src/common/memory.cpp
fixed URL parsing problem
[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
3096bd2f 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{
223d09f6 113 wxLogDebug(wxT("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{
223d09f6 124 wxLogDebug(wxT("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
223d09f6 332 wxString msg(wxT(""));
184b5d99 333
f97c9854 334 if (m_fileName)
223d09f6 335 msg.Printf(wxT("%s(%d): "), m_fileName, (int)m_lineNum);
f97c9854
JS
336
337 if (info && info->GetClassName())
184b5d99 338 msg += info->GetClassName();
f97c9854 339 else
223d09f6 340 msg += wxT("object");
184b5d99
JS
341
342 wxString msg2;
223d09f6 343 msg2.Printf(wxT(" 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)
223d09f6
KB
353 msg.Printf(wxT("%s(%d): "), m_fileName, (int)m_lineNum);
354 msg += wxT("non-object data");
184b5d99 355 wxString msg2;
223d09f6 356 msg2.Printf(wxT(" 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
223d09f6 371 wxString msg(wxT(""));
c801d85f 372 if (m_fileName)
223d09f6 373 msg.Printf(wxT("%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
223d09f6 386 msg += wxT("unknown object class");
184b5d99
JS
387
388 wxString msg2("");
223d09f6 389 msg2.Printf(wxT(" at $%lX, size %d"), (long)GetActualData(), (int)RequestSize());
184b5d99
JS
390 msg += msg2;
391
392 wxLogDebug(msg);
c801d85f
KB
393 }
394 else
395 {
223d09f6 396 wxString msg(wxT(""));
c801d85f 397 if (m_fileName)
223d09f6 398 msg.Printf(wxT("%s(%d): "), m_fileName, (int)m_lineNum);
184b5d99
JS
399
400 wxString msg2("");
223d09f6 401 msg2.Printf(wxT("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__
223d09f6 421 wxLogDebug(wxT("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 {
223d09f6 669 wxChar* appName = wxT("application");
c801d85f
KB
670 wxString appNameStr("");
671 if (wxTheApp)
672 {
673 appNameStr = wxTheApp->GetAppName();
4de6207a 674 appName = WXSTRINGCAST appNameStr;
223d09f6 675 wxLogDebug(wxT("----- Memory dump of %s at %s -----"), appName, WXSTRINGCAST wxNow() );
e55ad60e
RR
676 }
677 else
678 {
223d09f6 679 wxLogDebug( wxT("----- Memory dump -----") );
c801d85f
KB
680 }
681 }
bd7d06f2 682 TraverseList ((PmSFV)&wxMemStruct::Dump, (checkPoint ? checkPoint->m_next : (wxMemStruct*)NULL));
3f4a0c5b 683
223d09f6
KB
684 wxLogDebug( wxT("") );
685 wxLogDebug( wxT("") );
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 {
223d09f6
KB
726 wxChar* appName = wxT("application");
727 wxString appNameStr(wxT(""));
e55ad60e
RR
728 if (wxTheApp)
729 {
730 appNameStr = wxTheApp->GetAppName();
4de6207a 731 appName = WXSTRINGCAST appNameStr;
223d09f6 732 wxLogDebug(wxT("----- Memory statistics of %s at %s -----"), appName, WXSTRINGCAST wxNow() );
e55ad60e
RR
733 }
734 else
735 {
223d09f6 736 wxLogDebug( wxT("----- 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 {
223d09f6 760 wxChar *className = wxT("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 {
223d09f6 795 wxLogDebug(wxT("%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 }
223d09f6 801 wxLogDebug(wxT(""));
c801d85f 802 }
3f4a0c5b 803
c801d85f
KB
804 SetDebugMode(currentMode);
805
223d09f6
KB
806 wxLogDebug(wxT("Number of object items: %ld"), noObjectNodes);
807 wxLogDebug(wxT("Number of non-object items: %ld"), noNonObjectNodes);
808 wxLogDebug(wxT("Total allocated size: %ld"), totalSize);
809 wxLogDebug(wxT(""));
810 wxLogDebug(wxT(""));
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 {
223d09f6
KB
825 wxChar* appName = wxT("application");
826 wxString appNameStr(wxT(""));
c801d85f
KB
827 if (wxTheApp)
828 {
829 appNameStr = wxTheApp->GetAppName();
4de6207a 830 appName = WXSTRINGCAST appNameStr;
223d09f6 831 wxLogDebug(wxT("----- 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());
223d09f6 847 msg += wxT(" ");
184b5d99
JS
848
849 if (info->GetBaseClassName1() && !info->GetBaseClassName2())
850 {
223d09f6 851 msg += wxT("is a ");
184b5d99
JS
852 msg += info->GetBaseClassName1();
853 }
854 else if (info->GetBaseClassName1() && info->GetBaseClassName2())
855 {
223d09f6 856 msg += wxT("is a ");
184b5d99 857 msg += info->GetBaseClassName1() ;
223d09f6 858 msg += wxT(", ");
184b5d99
JS
859 msg += info->GetBaseClassName2() ;
860 }
861 if (info->GetConstructor())
223d09f6 862 msg += wxT(": dynamic");
184b5d99
JS
863
864 wxLogDebug(msg);
c801d85f 865 }
e55ad60e 866 node = wxClassInfo::sm_classTable->Next();
c801d85f
KB
867 n ++;
868 }
223d09f6
KB
869 wxLogDebug(wxT(""));
870 wxLogDebug(wxT("There are %d classes derived from wxObject."), n);
871 wxLogDebug(wxT(""));
872 wxLogDebug(wxT(""));
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 990
2bd5bbc9 991#if !defined(__VISAGECPP__) // already defines this by default
c801d85f
KB
992void operator delete (void * buf)
993{
994#ifdef NO_DEBUG_ALLOCATION
995 free((char*) buf);
996#else
997 wxDebugFree(buf);
998#endif
999}
2bd5bbc9 1000#endif
c801d85f 1001
76626af2 1002// VC++ 6.0
3f4a0c5b 1003#if defined(__VISUALC__) && (__VISUALC__ >= 1200)
4de6207a 1004void operator delete(void* pData, wxChar* /* fileName */, int /* lineNum */)
76626af2 1005{
184b5d99
JS
1006// ::operator delete(pData);
1007 // JACS 21/11/1998: surely we need to call wxDebugFree?
1008 wxDebugFree(pData, FALSE);
1009}
1010// New operator 21/11/1998
1011void operator delete[](void* pData, char* /* fileName */, int /* lineNum */)
1012{
1013 wxDebugFree(pData, TRUE);
76626af2
JS
1014}
1015#endif
1016
5dcf05ae 1017#if wxUSE_ARRAY_MEMORY_OPERATORS
0f358732 1018
c801d85f
KB
1019void operator delete[] (void * buf)
1020{
1021#ifdef NO_DEBUG_ALLOCATION
1022 free((char*) buf);
1023#else
1024 wxDebugFree(buf, TRUE);
1025#endif
1026}
5260b1c5 1027#endif
c801d85f
KB
1028
1029#endif
1030
1031// TODO: store whether this is a vector or not.
4de6207a 1032void * wxDebugAlloc(size_t size, wxChar * fileName, int lineNum, bool isObject, bool WXUNUSED(isVect) )
c801d85f
KB
1033{
1034 // If not in debugging allocation mode, do the normal thing
1035 // so we don't leave any trace of ourselves in the node list.
1036
1037 if (!wxDebugContext::GetDebugMode())
1038 {
1039 return (void *)malloc(size);
1040 }
3f4a0c5b 1041
94b49b93
JS
1042 int totSize = wxDebugContext::TotSize (size);
1043 char * buf = (char *) malloc(totSize);
c801d85f 1044 if (!buf) {
223d09f6 1045 wxLogDebug(wxT("Call to malloc (%ld) failed."), (long)size);
3f4a0c5b 1046 return 0;
c801d85f
KB
1047 }
1048 wxMemStruct * st = (wxMemStruct *)buf;
1049 st->m_firstMarker = MemStartCheck;
1050 st->m_reqSize = size;
1051 st->m_fileName = fileName;
1052 st->m_lineNum = lineNum;
1053 st->m_id = MemStructId;
1054 st->m_prev = 0;
1055 st->m_next = 0;
1056 st->m_isObject = isObject;
1057
1058 // Errors from Append() shouldn't really happen - but just in case!
1059 if (st->Append () == 0) {
3f4a0c5b 1060 st->ErrorMsg ("Trying to append new node");
c801d85f 1061 }
3f4a0c5b 1062
c801d85f 1063 if (wxDebugContext::GetCheckPrevious ()) {
3f4a0c5b
VZ
1064 if (st->CheckAllPrevious () < 0) {
1065 st->ErrorMsg ("Checking previous nodes");
1066 }
c801d85f 1067 }
3f4a0c5b 1068
c801d85f
KB
1069 // Set up the extra markers at the middle and end.
1070 char * ptr = wxDebugContext::MidMarkerPos (buf);
1071 * (wxMarkerType *) ptr = MemMidCheck;
1072 ptr = wxDebugContext::EndMarkerPos (buf, size);
1073 * (wxMarkerType *) ptr = MemEndCheck;
1074
1075 // pointer returned points to the start of the caller's
1076 // usable area.
1077 void *m_actualData = (void *) wxDebugContext::CallerMemPos (buf);
1078 st->m_actualData = m_actualData;
1079
1080 return m_actualData;
1081}
1082
1083// TODO: check whether was allocated as a vector
bd7d06f2 1084void wxDebugFree(void * buf, bool WXUNUSED(isVect) )
c801d85f
KB
1085{
1086 if (!buf)
1087 return;
3f4a0c5b 1088
c801d85f
KB
1089 // If not in debugging allocation mode, do the normal thing
1090 // so we don't leave any trace of ourselves in the node list.
1091 if (!wxDebugContext::GetDebugMode())
1092 {
1093 free((char *)buf);
1094 return;
1095 }
1096
1097 // Points to the start of the entire allocated area.
1098 char * startPointer = wxDebugContext::StartPos ((char *) buf);
1099 // Find the struct and make sure that it's identifiable.
1100 wxMemStruct * st = (wxMemStruct *) wxDebugContext::StructPos (startPointer);
1101
1102 if (! st->ValidateNode ())
3f4a0c5b 1103 return;
c801d85f
KB
1104
1105 // If this is the current checkpoint, we need to
1106 // move the checkpoint back so it points to a valid
1107 // node.
1108 if (st == wxDebugContext::checkPoint)
1109 wxDebugContext::checkPoint = wxDebugContext::checkPoint->m_prev;
1110
1111 if (! st->Unlink ())
1112 {
1113 st->ErrorMsg ("Unlinking deleted node");
1114 }
3f4a0c5b 1115
c801d85f
KB
1116 // Now put in the fill char into the id slot and the caller requested
1117 // memory locations.
1118 st->SetDeleted ();
1119 (void) memset (wxDebugContext::CallerMemPos (startPointer), MemFillChar,
3f4a0c5b 1120 st->RequestSize ());
c801d85f
KB
1121
1122 // Don't allow delayed freeing of memory in this version
1123// if (!wxDebugContext::GetDelayFree())
1124// free((void *)st);
1125 free((char *)st);
1126}
1127
1128// Trace: send output to the current debugging stream
4de6207a 1129void wxTrace(const wxChar *fmt ...)
c801d85f
KB
1130{
1131 va_list ap;
4de6207a 1132 static wxChar buffer[512];
c801d85f
KB
1133
1134 va_start(ap, fmt);
1135
2049ba38 1136#ifdef __WXMSW__
c801d85f
KB
1137 wvsprintf(buffer,fmt,ap) ;
1138#else
1139 vsprintf(buffer,fmt,ap) ;
1140#endif
1141
1142 va_end(ap);
1143
1144 if (wxDebugContext::HasStream())
1145 {
1146 wxDebugContext::GetStream() << buffer;
1147 wxDebugContext::GetStream().flush();
1148 }
1149 else
2049ba38 1150#ifdef __WXMSW__
25889d3c 1151#ifdef __WIN32__
4de6207a 1152 OutputDebugString((LPCTSTR)buffer) ;
25889d3c
JS
1153#else
1154 OutputDebugString((const char*) buffer) ;
1155#endif
c801d85f
KB
1156#else
1157 fprintf(stderr, buffer);
1158#endif
1159}
1160
1161// Trace with level
4de6207a 1162void wxTraceLevel(int level, const wxChar *fmt ...)
c801d85f
KB
1163{
1164 if (wxDebugContext::GetLevel() < level)
1165 return;
3f4a0c5b 1166
c801d85f 1167 va_list ap;
4de6207a 1168 static wxChar buffer[512];
c801d85f
KB
1169
1170 va_start(ap, fmt);
1171
2049ba38 1172#ifdef __WXMSW__
c801d85f
KB
1173 wvsprintf(buffer,fmt,ap) ;
1174#else
1175 vsprintf(buffer,fmt,ap) ;
1176#endif
1177
1178 va_end(ap);
1179
1180 if (wxDebugContext::HasStream())
1181 {
1182 wxDebugContext::GetStream() << buffer;
1183 wxDebugContext::GetStream().flush();
1184 }
1185 else
2049ba38 1186#ifdef __WXMSW__
25889d3c 1187#ifdef __WIN32__
4de6207a 1188 OutputDebugString((LPCTSTR)buffer) ;
25889d3c
JS
1189#else
1190 OutputDebugString((const char*) buffer) ;
1191#endif
c801d85f
KB
1192#else
1193 fprintf(stderr, buffer);
1194#endif
1195}
1196
ea57084d 1197#else // wxUSE_MEMORY_TRACING && defined(__WXDEBUG__)
c801d85f
KB
1198void wxTrace(const char *WXUNUSED(fmt) ...)
1199{
1200}
1201
1202void wxTraceLevel(int WXUNUSED(level), const char *WXUNUSED(fmt) ...)
1203{
1204}
1205#endif
1206