ReactOS  0.4.15-dev-2704-gd5265b0
fxtagtracker.cpp
Go to the documentation of this file.
1 /*++
2 
3 Copyright (c) Microsoft Corporation
4 
5 Module Name:
6 
7  FxTagTracker.cpp
8 
9 Abstract:
10 
11 Author:
12 
13 Environment:
14 
15  Both kernel and user mode
16 
17 Revision History:
18 
19 
20 
21 
22 
23 
24 
25 --*/
26 
27 #include "fxobjectpch.hpp"
28 
29 extern "C" {
30 
31 #if defined(EVENT_TRACING)
32 #include "fxtagtracker.tmh"
33 #endif
34 
35 #if (FX_CORE_MODE == FX_CORE_KERNEL_MODE)
36 //
37 // rtlsupportapi.h causes problems in AMD64 and ARM builds.
38 //
39 extern
40 _Success_(return != 0)
41 USHORT
42 STDCALL
44  _In_ ULONG FramesToSkip,
48  );
49 #endif
50 
51 }
52 
54 /*++
55 
56 Routine Description:
57  Destructor for this object. Will verify that the object is being freed
58  without any outstanding tags.
59 
60 Arguments:
61  None
62 
63 Return Value:
64  None
65 
66  --*/
67 {
68  KIRQL irql;
70 
73 
75 
76  pExtension = GetDriverGlobals()->DebugExtension;
77 
78  //
79  // Remove this tracker from the list of allocated trackers
80  //
81  pExtension->AllocatedTagTrackersLock.Acquire(&irql);
83  pExtension->AllocatedTagTrackersLock.Release(irql);
84  } else {
86  }
87 
88  //
89  // Delete any outstanding tracking blocks.
90  //
91  m_SpinLock.Acquire(&irql);
92 
93  current = m_Next;
94  m_Next = NULL;
95 
96  while (current != NULL) {
97  next = current->Next;
98  delete current;
99  current = next;
100  }
101 
102  m_SpinLock.Release(irql);
103 }
104 
105 VOID
107  _Inout_ FxTagTrackingStackFrames** StackFrames,
108  _In_ USHORT NumFrames,
109  _In_reads_(NumFrames) PVOID* Frames
110  )
111 {
113  FxTagTrackingStackFrames* stackFrames;
114 
115  //
116  // FxTagHistory structs are stored in a circular buffer and reused,
117  // so we also reuse the FxTagTrackingStackFrames that each allocates.
118  //
119  stackFrames = *StackFrames;
120  if (stackFrames == NULL) {
122  stackFrames = new(pFxDriverGlobals) FxTagTrackingStackFrames;
123  if (stackFrames == NULL) {
124  return;
125  }
126 
127  *StackFrames = stackFrames;
128  }
129 
130  stackFrames->NumFrames = NumFrames;
131 
132  for (int i = 0; i < NumFrames; i++) {
133  stackFrames->Frames[i] = (ULONG64)Frames[i];
134  }
135 }
136 
137 VOID
139  __in PVOID Tag,
140  __in LONG Line,
142  __in FxTagRefType RefType,
143  __in ULONG RefCount
144  )
145 /*++
146 
147 Routine Description:
148  Update tag history and either create or free an existing tag tracking block.
149 
150 Arguments:
151 
152  Tag - Unique tag associated with the reference
153 
154  Line - Line where the reference is referenced/released
155 
156  File - Buffer containing the file name
157 
158  RefType - Enumerated type ( AddRef or Release )
159 
160  RefCount - Approximate current reference count (see FxTagHistory.RefCount comment)
161 
162 Return Value:
163 
164  VOID
165 
166 --*/
167 {
169  FxTagHistory* pTagHistory;
170  FxTagTrackingBlock* pBlock;
171  LONG pos;
172  KIRQL irql;
173  USHORT numFrames = 0;
174  PVOID frames[FRAMES_TO_CAPTURE];
175 
177 
180 
181  //
182  // Prefast reports that m_CurRefHistory can be negative which can lead to
183  // underflow. But we know that m_CurRefHistory would never be negative.
184  // Hence we assert for the condition below and assume that it would be true.
185  //
187 
188  pTagHistory = m_TagHistory + pos;
189 
190  pTagHistory->RefType = RefType;
191  pTagHistory->RefCount = RefCount;
192  pTagHistory->Line = Line;
193  pTagHistory->Tag = Tag;
194  pTagHistory->File = File;
195 
196  if (m_CaptureStack) {
199  frames,
200  NULL);
201  if (numFrames > 0) {
202  CopyStackFrames(&pTagHistory->StackFrames, numFrames, frames);
203  }
204  }
205 
206  //
207  // We use the perf counter here and the tick count in the tracking block.
208  // Use the tick count here as well until we decide that correlating the
209  // perf counter to system time is not important.
210  //
211  // pTagHistory->Time = KeQueryPerformanceCounter(NULL);
212  Mx::MxQueryTickCount(&pTagHistory->Time);
213 
214  if (RefType == TagAddRef) {
215 
216  //
217  // Try to allocate some memory for the new block. If unsuccessful,
218  // fallback to a failed count increment.
219  //
221 
222  if (pBlock == NULL) {
224  }
225  else {
226  m_SpinLock.Acquire(&irql);
227  pBlock->Next = m_Next;
228  m_Next = pBlock;
229  m_SpinLock.Release(irql);
230 
231  if (m_CaptureStack && numFrames > 0) {
232  CopyStackFrames(&pBlock->StackFrames, numFrames, frames);
233  }
234  }
235  }
236  else {
237  FxTagTrackingBlock **prev;
238 
239  //
240  // Walk the list of current blocks and attempt to find the tag being
241  // released. If not found, decrement the failed count. If no failed
242  // tags exists, ASSERT immediately.
243  //
244 
245  m_SpinLock.Acquire(&irql);
246  prev = &m_Next;
247  pBlock = *prev;
248 
249  while (pBlock != NULL) {
250  if (pBlock->Tag == Tag) {
251  *prev = pBlock->Next;
252  break;
253  }
254 
255  prev = &pBlock->Next;
256  pBlock = pBlock->Next;
257  }
258 
259  m_SpinLock.Release(irql);
260 
261  if (pBlock == NULL) {
262  //
263  // Check to see if we have any credits in our Low Memory Count.
264  // In this fassion we can tell if we have acquired any locks without
265  // the memory for adding tracking blocks.
266  //
268  //
269  // We have just released a lock that neither had a corresponding
270  // tracking block, nor a credit in LowMemoryCount.
271  //
273 
276  "releasing %s %p on object %p that was not acquired, !wdftagtracker %p",
277  m_TrackerType == FxTagTrackerTypePower ? "power tag" : "tag",
278  Tag,
280  this);
281 
283  }
284  }
285  else {
286  delete pBlock;
287  pBlock = NULL;
288  }
289  }
290 }
291 
292 VOID
294  VOID
295  )
296 /*++
297 
298 Routine Description:
299  Iterates over any existing tags, dumping any existing tags to the debugger.
300  Will assert if there any outstanding tags (assumes that the caller wants
301  no current tags).
302 
303 Arguments:
304  None
305 
306 Return Value:
307  None
308 
309  --*/
310 {
313  LONG abandoned;
314  KIRQL irql;
315  BOOLEAN committed;
316 
318 
319  committed = m_OwningObject->IsCommitted();
320 
321  //
322  // If the object was not committed, then it was an FxObject derived
323  // class that was *embedded* as a field in another structure or class.
324  // As such, we are allowing one outstanding reference at this time. We will
325  // catch > 1 outstanding references below in the while loop.
326  //
327  if (committed) {
328  if (m_Next != NULL || m_FailedCount != 0) {
330  "Dropped references on a tag tracker, "
331  "show references with: !wdftagtracker %p", this);
332  //
333  // If this ASSERT fails, look in the history .. you'll
334  // likely find that you released more references than you had
335  //
336  ASSERT(m_Next == NULL && m_FailedCount == 0);
337  }
338  }
339 
340  m_SpinLock.Acquire(&irql);
341 
342  current = m_Next;
343  abandoned = 0;
344 
345  while (current != NULL) {
346  next = current->Next;
347 
348  if (committed) {
350  "Abandonded ref on object %p tag %p (%s @ %d)",
351  m_OwningObject, current->Tag, current->File, current->Line);
352  abandoned++;
353  }
354 
355  if (committed == FALSE) {
356  //
357  // The next time we encounter an abandoned reference, we will complain
358  // about it...we have used up our allowance of one leaked reference
359  // because the object is an embedded object.
360  //
361  // NOTE: we might be eating the real outstanding reference here
362  // and not tracing it and then tracing the initial creation
363  // reference as the leaked reference which will be confusing.
364  // This is b/c there is no way to distinguish what is the
365  // tracking block used to track the creatio of the object.
366  //
367  committed = TRUE;
368 
370  "Possibly Abandonded ref on object %p tag %p (%s @ %d). "
371  "Is benign unless there are other outstanding leaked references.",
372  m_OwningObject, current->Tag, current->File, current->Line);
373  }
374 
375  current = next;
376  }
377 
378  m_SpinLock.Release(irql);
379 
380  ASSERTMSG("Abandoned tags on ref\n", abandoned == 0);
381 }
382 
383 
FxObject * m_OwningObject
return
Definition: dirsup.c:529
VOID CheckForAbandondedTags(VOID)
#define FX_ASSERT_AND_ASSUME_FOR_PREFAST(b)
Definition: fxmacros.hpp:284
LIST_ENTRY m_TrackerEntry
FxTagTrackingStackFrames * StackFrames
FxTagHistory m_TagHistory[TAG_HISTORY_DEPTH]
static __inline VOID MxQueryTickCount(__out PLARGE_INTEGER TickCount)
Definition: mxgeneralkm.h:116
#define __in_opt
Definition: dbghelp.h:38
#define TRUE
Definition: types.h:120
_In_ ULONG FramesToCapture
KIRQL irql
Definition: wave.h:1
FxDriverGlobalsDebugExtension * DebugExtension
Definition: fxglobals.h:376
LARGE_INTEGER Time
FORCEINLINE BOOLEAN RemoveEntryList(_In_ PLIST_ENTRY Entry)
Definition: rtlfuncs.h:105
BOOLEAN m_CaptureStack
UCHAR KIRQL
Definition: env_spec_w32.h:591
struct Line Line
Definition: wdfdevice.h:4081
FxTagRefType
#define FALSE
Definition: types.h:117
long LONG
Definition: pedump.c:60
#define ASSERTMSG(msg, exp)
Definition: nt_native.h:431
_In_ ULONG _Out_opt_ PULONG BackTraceHash
unsigned char BOOLEAN
FxTagRefType RefType
FxTagTrackingStackFrames * StackFrames
struct FxTagTrackingBlock * Next
#define _Out_opt_
Definition: no_sal2.h:214
#define TRACINGDEVICE
Definition: dbgtrace.h:58
PFX_DRIVER_GLOBALS pFxDriverGlobals
_Success_(return !=0) USHORT STDCALL RtlCaptureStackBackTrace(_In_ ULONG FramesToSkip
Definition: fsctrl.c:3139
#define STDCALL
Definition: wdf.h:45
#define ASSERT(a)
Definition: mode.c:44
BOOLEAN IsCommitted(VOID)
Definition: fxobject.hpp:1087
HRESULT Next([in] ULONG celt, [out, size_is(celt), length_is(*pceltFetched)] STATPROPSETSTG *rgelt, [out] ULONG *pceltFetched)
#define _Inout_
Definition: no_sal2.h:162
FxTagTrackerType m_TrackerType
VOID UpdateTagHistory(__in PVOID Tag, __in LONG Line, __in_opt PSTR File, __in FxTagRefType RefType, __in ULONG RefCount)
Definition: ncftp.h:79
unsigned __int64 ULONG64
Definition: imports.h:198
#define FRAMES_TO_CAPTURE
#define InterlockedDecrement
Definition: armddk.h:52
VOID CopyStackFrames(_Inout_ FxTagTrackingStackFrames **StackFrames, _In_ USHORT NumFrames, _In_reads_(NumFrames) PVOID *Frames)
FxTagTrackingBlock * m_Next
_Must_inspect_result_ _In_ WDFDEVICE _In_ BOOLEAN _In_opt_ PVOID Tag
Definition: wdfdevice.h:4061
ULONG64 Frames[FRAMES_TO_CAPTURE]
#define TRACE_LEVEL_ERROR
Definition: storswtr.h:27
#define TRACE_LEVEL_WARNING
Definition: storswtr.h:28
#define _In_
Definition: no_sal2.h:158
static unsigned __int64 next
Definition: rand_nt.c:6
#define InterlockedIncrement
Definition: armddk.h:53
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
unsigned short USHORT
Definition: pedump.c:61
signed char * PSTR
Definition: retypes.h:7
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGPNP, "Enter, WDFDEVICE %p", Device)
unsigned int * PULONG
Definition: retypes.h:1
#define NULL
Definition: types.h:112
NTSYSAPI USHORT NTAPI RtlCaptureStackBackTrace(_In_ ULONG FramesToSkip, _In_ ULONG FramesToCapture, _Out_writes_to_(FramesToCapture, return) PVOID *BackTrace, _Out_opt_ PULONG BackTraceHash)
unsigned int ULONG
Definition: retypes.h:1
_In_ ULONG _Out_writes_to_(FramesToCapture, return) PVOID *BackTrace
Definition: File.h:15
#define _In_reads_(s)
Definition: no_sal2.h:168
_Must_inspect_result_ _In_ WDFDEVICE _In_ BOOLEAN _In_opt_ PVOID _In_ LONG _In_z_ PCHAR File
Definition: wdfdevice.h:4061
#define __in
Definition: dbghelp.h:35
PFX_DRIVER_GLOBALS GetDriverGlobals(VOID)
Definition: fxstump.hpp:98
FxVerifierDbgBreakPoint(pFxDriverGlobals)
struct task_struct * current
Definition: linux.c:32
#define FRAMES_TO_SKIP
#define TAG_HISTORY_DEPTH