]> git.lyx.org Git - lyx.git/blob - development/Win32/vld/src/callstack.cpp
Add support for glue length in parskip (#12867)
[lyx.git] / development / Win32 / vld / src / callstack.cpp
1 ////////////////////////////////////////////////////////////////////////////////
2 //
3 //  Visual Leak Detector - CallStack Class Implementations
4 //  Copyright (c) 2005-2009 Dan Moulding
5 //
6 //  This library is free software; you can redistribute it and/or
7 //  modify it under the terms of the GNU Lesser General Public
8 //  License as published by the Free Software Foundation; either
9 //  version 2.1 of the License, or (at your option) any later version.
10 //
11 //  This library is distributed in the hope that it will be useful,
12 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 //  Lesser General Public License for more details.
15 //
16 //  You should have received a copy of the GNU Lesser General Public
17 //  License along with this library; if not, write to the Free Software
18 //  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19 //
20 //  See COPYING.txt for the full terms of the GNU Lesser General Public License.
21 //
22 ////////////////////////////////////////////////////////////////////////////////
23
24 #include <cassert>
25 #include <windows.h>
26 #ifndef __out_xcount
27 #define __out_xcount(x) // Workaround for the specstrings.h bug in the Platform SDK.
28 #endif
29 #define DBGHELP_TRANSLATE_TCHAR
30 #include <dbghelp.h>    // Provides symbol handling services.
31 #define VLDBUILD
32 #include "callstack.h"  // This class' header.
33 #include "utility.h"    // Provides various utility functions.
34 #include "vldheap.h"    // Provides internal new and delete operators.
35 #include "vldint.h"     // Provides access to VLD internals.
36
37 #define MAXSYMBOLNAMELENGTH 256
38
39 // Imported global variables.
40 extern HANDLE             currentprocess;
41 extern HANDLE             currentthread;
42 extern CRITICAL_SECTION   stackwalklock;
43 extern CRITICAL_SECTION   symbollock;
44
45 // Constructor - Initializes the CallStack with an initial size of zero and one
46 //   Chunk of capacity.
47 //
48 CallStack::CallStack ()
49 {
50     m_capacity   = CALLSTACKCHUNKSIZE;
51     m_size       = 0;
52     m_status     = 0x0;
53     m_store.next = NULL;
54     m_topchunk   = &m_store;
55     m_topindex   = 0;
56 }
57
58 // Copy Constructor - For efficiency, we want to avoid ever making copies of
59 //   CallStacks (only pointer passing or reference passing should be performed).
60 //   The sole purpose of this copy constructor is to ensure that no copying is
61 //   being done inadvertently.
62 //
63 CallStack::CallStack (const CallStack &)
64 {
65     // Don't make copies of CallStacks!
66     assert(FALSE);
67 }
68
69 // Destructor - Frees all memory allocated to the CallStack.
70 //
71 CallStack::~CallStack ()
72 {
73     CallStack::chunk_t *chunk = m_store.next;
74     CallStack::chunk_t *temp;
75
76     while (chunk) {
77         temp = chunk;
78         chunk = temp->next;
79         delete temp;
80     }
81 }
82
83 // operator = - Assignment operator. For efficiency, we want to avoid ever
84 //   making copies of CallStacks (only pointer passing or reference passing
85 //   should be performed). The sole purpose of this assignment operator is to
86 //   ensure that no copying is being done inadvertently.
87 //
88 CallStack& CallStack::operator = (const CallStack &)
89 {
90     // Don't make copies of CallStacks!
91     assert(FALSE);
92     return *this;
93 }
94
95 // operator == - Equality operator. Compares the CallStack to another CallStack
96 //   for equality. Two CallStacks are equal if they are the same size and if
97 //   every frame in each is identical to the corresponding frame in the other.
98 //
99 //  other (IN) - Reference to the CallStack to compare the current CallStack
100 //    against for equality.
101 //
102 //  Return Value:
103 //
104 //    Returns true if the two CallStacks are equal. Otherwise returns false.
105 //
106 BOOL CallStack::operator == (const CallStack &other) const
107 {
108     const CallStack::chunk_t *chunk = &m_store;
109     UINT32                    index;
110     const CallStack::chunk_t *otherchunk = &other.m_store;
111     const CallStack::chunk_t *prevchunk = NULL;
112
113     if (m_size != other.m_size) {
114         // They can't be equal if the sizes are different.
115         return FALSE;
116     }
117
118     // Walk the chunk list and within each chunk walk the frames array until we
119     // either find a mismatch, or until we reach the end of the call stacks.
120     while (prevchunk != m_topchunk) {
121         for (index = 0; index < ((chunk == m_topchunk) ? m_topindex : CALLSTACKCHUNKSIZE); index++) {
122             if (chunk->frames[index] != otherchunk->frames[index]) {
123                 // Found a mismatch. They are not equal.
124                 return FALSE;
125             }
126         }
127         prevchunk = chunk;
128         chunk = chunk->next;
129         otherchunk = otherchunk->next;
130     }
131
132     // Reached the end of the call stacks. They are equal.
133     return TRUE;
134 }
135
136 // operator [] - Random access operator. Retrieves the frame at the specified
137 //   index.
138 //
139 //   Note: We give up a bit of efficiency here, in favor of efficiency of push
140 //     operations. This is because walking of a CallStack is done infrequently
141 //     (only if a leak is found), whereas pushing is done very frequently (for
142 //     each frame in the program's call stack when the program allocates some
143 //     memory).
144 //
145 //  - index (IN): Specifies the index of the frame to retrieve.
146 //
147 //  Return Value:
148 //
149 //    Returns the program counter for the frame at the specified index. If the
150 //    specified index is out of range for the CallStack, the return value is
151 //    undefined.
152 //
153 SIZE_T CallStack::operator [] (UINT32 index) const
154 {
155     UINT32                    count;
156     const CallStack::chunk_t *chunk = &m_store;
157     UINT32                    chunknumber = index / CALLSTACKCHUNKSIZE;
158
159     for (count = 0; count < chunknumber; count++) {
160         chunk = chunk->next;
161     }
162
163     return chunk->frames[index % CALLSTACKCHUNKSIZE];
164 }
165
166 // clear - Resets the CallStack, returning it to a state where no frames have
167 //   been pushed onto it, readying it for reuse.
168 //
169 //   Note: Calling this function does not release any memory allocated to the
170 //     CallStack. We give up a bit of memory-usage efficiency here in favor of
171 //     performance of push operations.
172 //
173 //  Return Value:
174 //
175 //    None.
176 //
177 VOID CallStack::clear ()
178 {
179     m_size     = 0;
180     m_topchunk = &m_store;
181     m_topindex = 0;
182 }
183
184 // dump - Dumps a nicely formatted rendition of the CallStack, including
185 //   symbolic information (function names and line numbers) if available.
186 //
187 //   Note: The symbol handler must be initialized prior to calling this
188 //     function.
189 //
190 //  - showinternalframes (IN): If true, then all frames in the CallStack will be
191 //      dumped. Otherwise, frames internal to the heap will not be dumped.
192 //
193 //  Return Value:
194 //
195 //    None.
196 //
197 VOID CallStack::dump (BOOL showinternalframes) const
198 {
199     DWORD            displacement;
200     DWORD64          displacement64;
201     BOOL             foundline;
202     UINT32           frame;
203     SYMBOL_INFO     *functioninfo;
204     LPWSTR           functionname;
205     SIZE_T           programcounter;
206     IMAGEHLP_LINE64  sourceinfo = { 0 };
207     BYTE             symbolbuffer [sizeof(SYMBOL_INFO) + (MAXSYMBOLNAMELENGTH * sizeof(WCHAR)) - 1] = { 0 };
208
209     if (m_status & CALLSTACK_STATUS_INCOMPLETE) {
210         // This call stack appears to be incomplete. Using StackWalk64 may be
211         // more reliable.
212         report(L"    HINT: The following call stack may be incomplete. Setting \"StackWalkMethod\"\n"
213                L"      in the vld.ini file to \"safe\" instead of \"fast\" may result in a more\n"
214                L"      complete stack trace.\n");
215     }
216
217     // Initialize structures passed to the symbol handler.
218     functioninfo = (SYMBOL_INFO*)&symbolbuffer;
219     functioninfo->SizeOfStruct = sizeof(SYMBOL_INFO);
220     functioninfo->MaxNameLen = MAXSYMBOLNAMELENGTH;
221     sourceinfo.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
222
223     // Iterate through each frame in the call stack.
224     for (frame = 0; frame < m_size; frame++) {
225         // Try to get the source file and line number associated with
226         // this program counter address.
227         programcounter = (*this)[frame];
228         EnterCriticalSection(&symbollock);
229         if ((foundline = SymGetLineFromAddrW64(currentprocess, programcounter, &displacement, &sourceinfo)) == TRUE) {
230             if (!showinternalframes) {
231                 _wcslwr_s(sourceinfo.FileName, wcslen(sourceinfo.FileName) + 1);
232                 if (wcsstr(sourceinfo.FileName, L"afxmem.cpp") ||
233                     wcsstr(sourceinfo.FileName, L"dbgheap.c") ||
234                     wcsstr(sourceinfo.FileName, L"malloc.c") ||
235                     wcsstr(sourceinfo.FileName, L"new.cpp") ||
236                     wcsstr(sourceinfo.FileName, L"newaop.cpp")) {
237                     // Don't show frames in files internal to the heap.
238                     continue;
239                 }
240             }
241         }
242
243         // Try to get the name of the function containing this program
244         // counter address.
245         if (SymFromAddrW(currentprocess, (*this)[frame], &displacement64, functioninfo)) {
246             functionname = functioninfo->Name;
247         }
248         else {
249             functionname = L"(Function name unavailable)";
250         }
251         LeaveCriticalSection(&symbollock);
252
253         // Display the current stack frame's information.
254         if (foundline) {
255             report(L"    %s (%d): %s\n", sourceinfo.FileName, sourceinfo.LineNumber, functionname);
256         }
257         else {
258             report(L"    " ADDRESSFORMAT L" (File and line number not available): ", (*this)[frame]);
259             report(L"%s\n", functionname);
260         }
261     }
262 }
263
264 // push_back - Pushes a frame's program counter onto the CallStack. Pushes are
265 //   always appended to the back of the chunk list (aka the "top" chunk).
266 //
267 //   Note: This function will allocate additional memory as necessary to make
268 //     room for new program counter addresses.
269 //
270 //  - programcounter (IN): The program counter address of the frame to be pushed
271 //      onto the CallStack.
272 //
273 //  Return Value:
274 //
275 //    None.
276 //
277 VOID CallStack::push_back (const SIZE_T programcounter)
278 {
279     CallStack::chunk_t *chunk;
280
281     if (m_size == m_capacity) {
282         // At current capacity. Allocate additional storage.
283         chunk = new CallStack::chunk_t;
284         chunk->next = NULL;
285         m_topchunk->next = chunk;
286         m_topchunk = chunk;
287         m_topindex = 0;
288         m_capacity += CALLSTACKCHUNKSIZE;
289     }
290     else if (m_topindex == CALLSTACKCHUNKSIZE) {
291         // There is more capacity, but not in this chunk. Go to the next chunk.
292         // Note that this only happens if this CallStack has previously been
293         // cleared (clearing resets the data, but doesn't give up any allocated
294         // space).
295         m_topchunk = m_topchunk->next;
296         m_topindex = 0;
297     }
298
299     m_topchunk->frames[m_topindex++] = programcounter;
300     m_size++;
301 }
302
303 // getstacktrace - Traces the stack as far back as possible, or until 'maxdepth'
304 //   frames have been traced. Populates the CallStack with one entry for each
305 //   stack frame traced.
306 //
307 //   Note: This function uses a very efficient method to walk the stack from
308 //     frame to frame, so it is quite fast. However, unconventional stack frames
309 //     (such as those created when frame pointer omission optimization is used)
310 //     will not be successfully walked by this function and will cause the
311 //     stack trace to terminate prematurely.
312 //
313 //  - maxdepth (IN): Maximum number of frames to trace back.
314 //
315 //  - framepointer (IN): Frame (base) pointer at which to begin the stack trace.
316 //      If NULL, then the stack trace will begin at this function.
317 //
318 //  Return Value:
319 //
320 //    None.
321 //
322 VOID FastCallStack::getstacktrace (UINT32 maxdepth, SIZE_T *framepointer)
323 {
324     UINT32  count = 0;
325
326     if (framepointer == NULL) {
327         // Begin the stack trace with the current frame. Obtain the current
328         // frame pointer.
329         FRAMEPOINTER(framepointer);
330     }
331
332     while (count < maxdepth) {
333         if ((SIZE_T*)*framepointer < framepointer) {
334             if ((SIZE_T*)*framepointer == NULL) {
335                 // Looks like we reached the end of the stack.
336                 break;
337             }
338             else {
339                 // Invalid frame pointer. Frame pointer addresses should always
340                 // increase as we move up the stack.
341                 m_status |= CALLSTACK_STATUS_INCOMPLETE;
342                 break;
343             }
344         }
345         if ((SIZE_T)*framepointer & (sizeof(SIZE_T*) - 1)) {
346             // Invalid frame pointer. Frame pointer addresses should always
347             // be aligned to the size of a pointer. This probably means that
348             // we've encountered a frame that was created by a module built with
349             // frame pointer omission (FPO) optimization turned on.
350             m_status |= CALLSTACK_STATUS_INCOMPLETE;
351             break;
352         }
353         if (IsBadReadPtr((SIZE_T*)*framepointer, sizeof(SIZE_T*))) {
354             // Bogus frame pointer. Again, this probably means that we've
355             // encountered a frame built with FPO optimization.
356             m_status |= CALLSTACK_STATUS_INCOMPLETE;
357             break;
358         }
359         count++;
360         push_back(*(framepointer + 1));
361         framepointer = (SIZE_T*)*framepointer;
362     }
363 }
364
365 // getstacktrace - Traces the stack as far back as possible, or until 'maxdepth'
366 //   frames have been traced. Populates the CallStack with one entry for each
367 //   stack frame traced.
368 //
369 //   Note: This function uses a documented Windows API to walk the stack. This
370 //     API is supposed to be the most reliable way to walk the stack. It claims
371 //     to be able to walk stack frames that do not follow the conventional stack
372 //     frame layout. However, this robustness comes at a cost: it is *extremely*
373 //     slow compared to walking frames by following frame (base) pointers.
374 //
375 //  - maxdepth (IN): Maximum number of frames to trace back.
376 //
377 //  - framepointer (IN): Frame (base) pointer at which to begin the stack trace.
378 //      If NULL, then the stack trace will begin at this function.
379 //
380 //  Return Value:
381 //
382 //    None.
383 //
384 VOID SafeCallStack::getstacktrace (UINT32 maxdepth, SIZE_T *framepointer)
385 {
386     DWORD        architecture;
387     CONTEXT      context;
388     UINT32       count = 0;
389     STACKFRAME64 frame;
390     SIZE_T       programcounter;
391     SIZE_T       stackpointer;
392
393     if (framepointer == NULL) {
394         // Begin the stack trace with the current frame. Obtain the current
395         // frame pointer.
396         FRAMEPOINTER(framepointer);
397     }
398
399     // Get the required values for initialization of the STACKFRAME64 structure
400     // to be passed to StackWalk64(). Required fields are AddrPC and AddrFrame.
401 #if defined(_M_IX86) || defined(_M_X64)
402     architecture   = X86X64ARCHITECTURE;
403     programcounter = *(framepointer + 1);
404     stackpointer   = *framepointer;  // An approximation.
405     context.BPREG  = *framepointer;
406     context.IPREG  = programcounter;
407     context.SPREG  = stackpointer;
408 #else
409 // If you want to retarget Visual Leak Detector to another processor
410 // architecture then you'll need to provide architecture-specific code to
411 // obtain the program counter and stack pointer from the given frame pointer.
412 #error "Visual Leak Detector is not supported on this architecture."
413 #endif // _M_IX86 || _M_X64
414
415     // Initialize the STACKFRAME64 structure.
416     memset(&frame, 0x0, sizeof(frame));
417     frame.AddrFrame.Offset = *framepointer;
418     frame.AddrFrame.Mode   = AddrModeFlat;
419     frame.AddrPC.Offset    = programcounter;
420     frame.AddrPC.Mode      = AddrModeFlat;
421     frame.AddrStack.Offset = stackpointer;
422     frame.AddrStack.Mode   = AddrModeFlat;
423
424     // Walk the stack.
425     EnterCriticalSection(&stackwalklock);
426     while (count < maxdepth) {
427         count++;
428         if (!StackWalk64(architecture, currentprocess, currentthread, &frame, &context, NULL,
429                          SymFunctionTableAccess64, SymGetModuleBase64, NULL)) {
430             // Couldn't trace back through any more frames.
431             break;
432         }
433         if (frame.AddrFrame.Offset == 0) {
434             // End of stack.
435             break;
436         }
437
438         // Push this frame's program counter onto the CallStack.
439         push_back((SIZE_T)frame.AddrPC.Offset);
440     }
441     LeaveCriticalSection(&stackwalklock);
442 }