]> git.saurik.com Git - wxWidgets.git/blob - include/wx/memory.h
fixed wxDebugContext to work with global and static objects (patch 901031)
[wxWidgets.git] / include / wx / memory.h
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: memory.h
3 // Purpose: MDI classes
4 // Author: Arthur Seaton, Julian Smart
5 // Modified by:
6 // Created: 29/01/98
7 // RCS-ID: $Id$
8 // Copyright: (c) 1998 Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 #ifndef _WX_MEMORYH__
13 #define _WX_MEMORYH__
14
15 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
16 #pragma interface "memory.h"
17 #endif
18
19 #include "wx/defs.h"
20 #include "wx/string.h"
21 #include "wx/msgout.h"
22
23 /*
24 The macro which will be expanded to include the file and line number
25 info, or to be a straight call to the new operator.
26 */
27
28 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
29
30 #include <stddef.h>
31
32 #ifdef __WXDEBUG__
33
34 WXDLLIMPEXP_BASE void * wxDebugAlloc(size_t size, wxChar * fileName, int lineNum, bool isObject, bool isVect = FALSE);
35 WXDLLIMPEXP_BASE void wxDebugFree(void * buf, bool isVect = FALSE);
36
37 //**********************************************************************************
38 /*
39 The global operator new used for everything apart from getting
40 dynamic storage within this function itself.
41 */
42
43 // We'll only do malloc and free for the moment: leave the interesting
44 // stuff for the wxObject versions.
45 // devik 2000-8-29: All new/delete ops are now inline because they can't
46 // be marked as dllexport/dllimport. It then leads to weird bugs when
47 // used on MSW as DLL
48
49 #if wxUSE_GLOBAL_MEMORY_OPERATORS
50
51 // Undefine temporarily (new is #defined in object.h) because we want to
52 // declare some new operators.
53 #ifdef new
54 #undef new
55 #endif
56
57 #if defined(__SUNCC__)
58 #define wxUSE_ARRAY_MEMORY_OPERATORS 0
59 #elif !( defined (__VISUALC__) && (__VISUALC__ <= 1020) ) || defined( __MWERKS__)
60 #define wxUSE_ARRAY_MEMORY_OPERATORS 1
61 #elif defined (__SGI_CC_)
62 // only supported by -n32 compilers
63 #ifndef __EDG_ABI_COMPATIBILITY_VERSION
64 #define wxUSE_ARRAY_MEMORY_OPERATORS 0
65 #endif
66 #elif !( defined (__VISUALC__) && (__VISUALC__ <= 1020) ) || defined( __MWERKS__)
67 #define wxUSE_ARRAY_MEMORY_OPERATORS 1
68 #else
69 // ::operator new[] is a recent C++ feature, so assume it's not supported
70 #define wxUSE_ARRAY_MEMORY_OPERATORS 0
71 #endif
72
73 inline void * operator new (size_t size, wxChar * fileName, int lineNum)
74 {
75 return wxDebugAlloc(size, fileName, lineNum, FALSE, FALSE);
76 }
77
78 inline void * operator new (size_t size)
79 {
80 return wxDebugAlloc(size, NULL, 0, FALSE);
81 }
82
83 inline void operator delete (void * buf)
84 {
85 wxDebugFree(buf, FALSE);
86 }
87
88 #if wxUSE_ARRAY_MEMORY_OPERATORS
89 inline void * operator new[] (size_t size)
90 {
91 return wxDebugAlloc(size, NULL, 0, FALSE, TRUE);
92 }
93
94 inline void * operator new[] (size_t size, wxChar * fileName, int lineNum)
95 {
96 return wxDebugAlloc(size, fileName, lineNum, FALSE, TRUE);
97 }
98
99 inline void operator delete[] (void * buf)
100 {
101 wxDebugFree(buf, TRUE);
102 }
103 #endif
104
105 // VC++ 6.0 and MWERKS
106 #if ( defined(__VISUALC__) && (__VISUALC__ >= 1200) ) || defined(__MWERKS__)
107 inline void operator delete(void* pData, wxChar* /* fileName */, int /* lineNum */)
108 {
109 wxDebugFree(pData, FALSE);
110 }
111 inline void operator delete[](void* pData, wxChar* /* fileName */, int /* lineNum */)
112 {
113 wxDebugFree(pData, TRUE);
114 }
115 #endif // __VISUALC__>=1200
116 #endif // wxUSE_GLOBAL_MEMORY_OPERATORS
117 #endif // __WXDEBUG__
118
119 //**********************************************************************************
120
121 typedef unsigned int wxMarkerType;
122
123 /*
124 Define the struct which will be placed at the start of all dynamically
125 allocated memory.
126 */
127
128 class WXDLLIMPEXP_BASE wxMemStruct {
129
130 friend class WXDLLIMPEXP_BASE wxDebugContext; // access to the m_next pointer for list traversal.
131
132 public:
133 public:
134 int AssertList ();
135
136 size_t RequestSize () { return m_reqSize; }
137 wxMarkerType Marker () { return m_firstMarker; }
138
139 // When an object is deleted we set the id slot to a specific value.
140 inline void SetDeleted ();
141 inline int IsDeleted ();
142
143 int Append ();
144 int Unlink ();
145
146 // Used to determine if the object is really a wxMemStruct.
147 // Not a foolproof test by any means, but better than none I hope!
148 int AssertIt ();
149
150 // Do all validation on a node.
151 int ValidateNode ();
152
153 // Check the integrity of a node and of the list, node by node.
154 int CheckBlock ();
155 int CheckAllPrevious ();
156
157 // Print a single node.
158 void PrintNode ();
159
160 // Called when the memory linking functions get an error.
161 void ErrorMsg (const char *);
162 void ErrorMsg ();
163
164 inline void *GetActualData(void) const { return m_actualData; }
165
166 void Dump(void);
167
168 public:
169 // Check for underwriting. There are 2 of these checks. This one
170 // inside the struct and another right after the struct.
171 wxMarkerType m_firstMarker;
172
173 // File name and line number are from cpp.
174 wxChar* m_fileName;
175 int m_lineNum;
176
177 // The amount of memory requested by the caller.
178 size_t m_reqSize;
179
180 // Used to try to verify that we really are dealing with an object
181 // of the required class. Can be 1 of 2 values these indicating a valid
182 // wxMemStruct object, or a deleted wxMemStruct object.
183 wxMarkerType m_id;
184
185 wxMemStruct * m_prev;
186 wxMemStruct * m_next;
187
188 void * m_actualData;
189 bool m_isObject;
190 };
191
192
193 typedef void (wxMemStruct::*PmSFV) ();
194
195
196 /*
197 Debugging class. This will only have a single instance, but it's
198 a reasonable way to keep everything together and to make this
199 available for change if needed by someone else.
200 A lot of this stuff would be better off within the wxMemStruct class, but
201 it's stuff which we need to access at times when there is no wxMemStruct
202 object so we use this class instead. Think of it as a collection of
203 globals which have to do with the wxMemStruct class.
204 */
205
206 class WXDLLIMPEXP_BASE wxDebugContext {
207
208 protected:
209 // Used to set alignment for markers.
210 static size_t CalcAlignment ();
211
212 // Returns the amount of padding needed after something of the given
213 // size. This is so that when we cast pointers backwards and forwards
214 // the pointer value will be valid for a wxMarkerType.
215 static size_t GetPadding (const size_t size) ;
216
217 // Traverse the list.
218 static void TraverseList (PmSFV, wxMemStruct *from = NULL);
219
220 static int debugLevel;
221 static bool debugOn;
222
223 static int m_balign; // byte alignment
224 static int m_balignmask; // mask for performing byte alignment
225 public:
226 // Set a checkpoint to dump only the memory from
227 // a given point
228 static wxMemStruct *checkPoint;
229
230 wxDebugContext(void);
231 ~wxDebugContext(void);
232
233 static int GetLevel(void) { return debugLevel; }
234 static void SetLevel(int level) { debugLevel = level; }
235
236 static bool GetDebugMode(void) { return debugOn; }
237 static void SetDebugMode(bool flag) { debugOn = flag; }
238
239 static void SetCheckpoint(bool all = FALSE);
240 static wxMemStruct *GetCheckpoint(void) { return checkPoint; }
241
242 // Calculated from the request size and any padding needed
243 // before the final marker.
244 static size_t PaddedSize (const size_t reqSize);
245
246 // Calc the total amount of space we need from the system
247 // to satisfy a caller request. This includes all padding.
248 static size_t TotSize (const size_t reqSize);
249
250 // Return valid pointers to offsets within the allocated memory.
251 static char * StructPos (const char * buf);
252 static char * MidMarkerPos (const char * buf);
253 static char * CallerMemPos (const char * buf);
254 static char * EndMarkerPos (const char * buf, const size_t size);
255
256 // Given a pointer to the start of the caller requested area
257 // return a pointer to the start of the entire alloc\'d buffer.
258 static char * StartPos (const char * caller);
259
260 // Access to the list.
261 static wxMemStruct * GetHead () { return m_head; }
262 static wxMemStruct * GetTail () { return m_tail; }
263
264 // Set the list sentinals.
265 static wxMemStruct * SetHead (wxMemStruct * st) { return (m_head = st); }
266 static wxMemStruct * SetTail (wxMemStruct * st) { return (m_tail = st); }
267
268 // If this is set then every new operation checks the validity
269 // of the all previous nodes in the list.
270 static bool GetCheckPrevious () { return m_checkPrevious; }
271 static void SetCheckPrevious (bool value) { m_checkPrevious = value; }
272
273 // Checks all nodes, or all nodes if checkAll is TRUE
274 static int Check(bool checkAll = FALSE);
275
276 // Print out the list of wxMemStruct nodes.
277 static bool PrintList(void);
278
279 // Dump objects
280 static bool Dump(void);
281
282 // Print statistics
283 static bool PrintStatistics(bool detailed = TRUE);
284
285 // Print out the classes in the application.
286 static bool PrintClasses(void);
287
288 // Count the number of non-wxDebugContext-related objects
289 // that are outstanding
290 static int CountObjectsLeft(bool sinceCheckpoint = FALSE);
291
292 // This function is used to output the dump
293 static void OutputDumpLine(const wxChar *szFormat, ...);
294
295 private:
296 // Store these here to allow access to the list without
297 // needing to have a wxMemStruct object.
298 static wxMemStruct* m_head;
299 static wxMemStruct* m_tail;
300
301 // Set to FALSE if we're not checking all previous nodes when
302 // we do a new. Set to TRUE when we are.
303 static bool m_checkPrevious;
304 };
305
306 // Final cleanup (e.g. deleting the log object and doing memory leak checking)
307 // will be delayed until all wxDebugContextDumpDelayCounter objects have been
308 // destructed. Adding one wxDebugContextDumpDelayCounter per file will delay
309 // memory leak checking until after destructing all global objects.
310 class WXDLLIMPEXP_BASE wxDebugContextDumpDelayCounter
311 {
312 public:
313 wxDebugContextDumpDelayCounter() {
314 sm_count++;
315 }
316
317 ~wxDebugContextDumpDelayCounter() {
318 sm_count--;
319 if(!sm_count) DoDump();
320 }
321 private:
322 void DoDump();
323 static int sm_count;
324 };
325
326 // make leak dump after all globals have been destructed
327 static wxDebugContextDumpDelayCounter wxDebugContextDumpDelayCounter_File;
328 #define WXDEBUG_DUMPDELAYCOUNTER \
329 static wxDebugContextDumpDelayCounter wxDebugContextDumpDelayCounter_Extra;
330
331 // Output a debug message, in a system dependent fashion.
332 void WXDLLIMPEXP_BASE wxTrace(const wxChar *fmt ...) ATTRIBUTE_PRINTF_1;
333 void WXDLLIMPEXP_BASE wxTraceLevel(int level, const wxChar *fmt ...) ATTRIBUTE_PRINTF_2;
334
335 #define WXTRACE wxTrace
336 #define WXTRACELEVEL wxTraceLevel
337
338 #else // (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
339
340 #define WXDEBUG_DUMPDELAYCOUNTER
341
342 // Borland C++ Builder 6 seems to have troubles with inline functions (see bug
343 // 819700)
344 #if 0
345 inline void wxTrace(const wxChar *WXUNUSED(fmt)) {}
346 inline void wxTraceLevel(int WXUNUSED(level), const wxChar *WXUNUSED(fmt)) {}
347 #else
348 #define wxTrace(fmt)
349 #define wxTraceLevel(l, fmt)
350 #endif
351
352 #define WXTRACE TRUE ? (void)0 : wxTrace
353 #define WXTRACELEVEL TRUE ? (void)0 : wxTraceLevel
354
355 #endif // (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
356
357 #endif
358 // _WX_MEMORYH__
359