[prev in list] [next in list] [prev in thread] [next in thread] 

List:       wine-devel
Subject:    Abusing valgrind to find reference leaks
From:       "Maarten Lankhorst" <m.b.lankhorst () gmail ! com>
Date:       2008-04-29 23:18:40
Message-ID: b130c85e0804291618j605717d2g10dba847617ed268 () mail ! gmail ! com
[Download RAW message or body]

Hi all,

I've managed to abuse valgrind to show backtraces of all places where
an AddRef and Release is called when there is a memory, this is
superior to wading through an endless pile of logs without even
guarantee it will work.

I thought I should share it for the following reasons:
1. Valgrind is an awesome tool
2. Reference leaks are usually impossible or very hard to find by
using debug logs

All I'm doing is leaking memory until the destructor is called, which
gives quite useful results, I had to add a exit(1) after the leak
occured because the samples get destroyed regardless when the
interface controlling those samples is released.

The log was created with:
valgrind --trace-children=yes --leak-check=full --show-reachable=yes
--leak-resolution=high -- wine quartz_test.exe.so filtergraph 2>&1 |
tee valgrind.log

And then I removed all the memory leaks and warnings not related to
AddRef and Release.

Ideally I could get it to automatically sort the outputted data based
on the order of calling, but I'm not 100% sure how to do that yet. I
could do 1,000,000 + GetTickCount(), but the results are usable now
regardless.

This was useful for me to get the backtraces of all _AddRef's and
_Release's *ONLY* for the leaking interfaces, which saves a lot of
time determining whether the specific interface is leaking and not,
and when it starts leaking, and then determining who calls and where
it is called, so I hope it is useful for you too!

Cheers,
Maarten.

["valgrind.log" (text/x-log)]

==17983== 1,000,000 bytes in 1 blocks are still reachable in loss record 1,314 of 1,324
==17983==    at 0x7BC41E0E: RtlAllocateHeap (heap.c:191)
==17983==    by 0x63ED942: StdMediaSample2_Release (memallocator.c:525)
==17983==    by 0x63FAB84: PullPin_Thread_Process (pin.c:1557)
==17983==    by 0x63FAF89: PullPin_Thread_Main (pin.c:1624)
==17983==    by 0x7BC67D0D: (within /bulk/wine/dlls/ntdll/ntdll.dll.so)
==17983==    by 0x7BC68431: call_thread_func (thread.c:383)
==17983==    by 0x7BC68635: start_thread (thread.c:443)
==17983==    by 0x452E33A7: start_thread (in /lib/tls/i686/cmov/libpthread-2.3.6.so)
==17983==    by 0x452347FD: clone (in /lib/tls/i686/cmov/libc-2.3.6.so)
==17983== 
==17983== 
==17983== 1,000,000 bytes in 1 blocks are still reachable in loss record 1,315 of 1,324
==17983==    at 0x7BC41E0E: RtlAllocateHeap (heap.c:191)
==17983==    by 0x63ED736: StdMediaSample2_AddRef (memallocator.c:491)
==17983==    by 0x63C331A: AVISplitter_Sample (avisplit.c:382)
==17983==    by 0x63C35FD: AVISplitter_first_request (avisplit.c:447)
==17983==    by 0x63FA6FB: PullPin_Thread_Process (pin.c:1496)
==17983==    by 0x63FAF89: PullPin_Thread_Main (pin.c:1624)
==17983==    by 0x7BC67D0D: (within /bulk/wine/dlls/ntdll/ntdll.dll.so)
==17983==    by 0x7BC68431: call_thread_func (thread.c:383)
==17983==    by 0x7BC68635: start_thread (thread.c:443)
==17983==    by 0x452E33A7: start_thread (in /lib/tls/i686/cmov/libpthread-2.3.6.so)
==17983==    by 0x452347FD: clone (in /lib/tls/i686/cmov/libc-2.3.6.so)
==17983== 
==17983== 
==17983== 1,000,000 bytes in 1 blocks are still reachable in loss record 1,316 of 1,324
==17983==    at 0x7BC41E0E: RtlAllocateHeap (heap.c:191)
==17983==    by 0x63ED736: StdMediaSample2_AddRef (memallocator.c:491)
==17983==    by 0x63ED030: BaseMemAllocator_GetBuffer (memallocator.c:350)
==17983==    by 0x63C2021: AVISplitter_next_request (avisplit.c:149)
==17983==    by 0x63C360F: AVISplitter_first_request (avisplit.c:450)
==17983==    by 0x63FA6FB: PullPin_Thread_Process (pin.c:1496)
==17983==    by 0x63FAF89: PullPin_Thread_Main (pin.c:1624)
==17983==    by 0x7BC67D0D: (within /bulk/wine/dlls/ntdll/ntdll.dll.so)
==17983==    by 0x7BC68431: call_thread_func (thread.c:383)
==17983==    by 0x7BC68635: start_thread (thread.c:443)
==17983==    by 0x452E33A7: start_thread (in /lib/tls/i686/cmov/libpthread-2.3.6.so)
==17983==    by 0x452347FD: clone (in /lib/tls/i686/cmov/libc-2.3.6.so)
==17983== 
==17983== 
==17983== 1,000,000 bytes in 1 blocks are still reachable in loss record 1,317 of 1,324
==17983==    at 0x7BC41E0E: RtlAllocateHeap (heap.c:191)
==17983==    by 0x63ED736: StdMediaSample2_AddRef (memallocator.c:491)
==17983==    by 0x63C331A: AVISplitter_Sample (avisplit.c:382)
==17983==    by 0x63FA8A2: PullPin_Thread_Process (pin.c:1527)
==17983==    by 0x63FAF89: PullPin_Thread_Main (pin.c:1624)
==17983==    by 0x7BC67D0D: (within /bulk/wine/dlls/ntdll/ntdll.dll.so)
==17983==    by 0x7BC68431: call_thread_func (thread.c:383)
==17983==    by 0x7BC68635: start_thread (thread.c:443)
==17983==    by 0x452E33A7: start_thread (in /lib/tls/i686/cmov/libpthread-2.3.6.so)
==17983==    by 0x452347FD: clone (in /lib/tls/i686/cmov/libc-2.3.6.so)
==17983== 
==17983== 
==17983== 1,000,000 bytes in 1 blocks are still reachable in loss record 1,318 of 1,324
==17983==    at 0x7BC41E0E: RtlAllocateHeap (heap.c:191)
==17983==    by 0x63ED736: StdMediaSample2_AddRef (memallocator.c:491)
==17983==    by 0x63ED030: BaseMemAllocator_GetBuffer (memallocator.c:350)
==17983==    by 0x63F8F7D: OutputPin_GetDeliveryBuffer (pin.c:1072)
==17983==    by 0x63BFA9D: ACMWrapper_ProcessSampleData (acmwrapper.c:139)
==17983==    by 0x63FF187: TransformFilter_Sample (transform.c:60)
==17983==    by 0x63F82B1: MemInputPin_Receive (pin.c:799)
==17983==    by 0x63F90A8: OutputPin_SendSample (pin.c:1113)
==17983==    by 0x63C2D7A: AVISplitter_Receive (avisplit.c:292)
==17983==    by 0x63C3164: AVISplitter_thread_reader (avisplit.c:346)
==17983==    by 0x7BC67D0D: (within /bulk/wine/dlls/ntdll/ntdll.dll.so)
==17983==    by 0x7BC68431: call_thread_func (thread.c:383)
==17983== 
==17983== 
==17983== 1,000,000 bytes in 1 blocks are still reachable in loss record 1,319 of 1,324
==17983==    at 0x7BC41E0E: RtlAllocateHeap (heap.c:191)
==17983==    by 0x63ED736: StdMediaSample2_AddRef (memallocator.c:491)
==17983==    by 0x63C2DAB: AVISplitter_Receive (avisplit.c:297)
==17983==    by 0x63C3164: AVISplitter_thread_reader (avisplit.c:346)
==17983==    by 0x7BC67D0D: (within /bulk/wine/dlls/ntdll/ntdll.dll.so)
==17983==    by 0x7BC68431: call_thread_func (thread.c:383)
==17983==    by 0x7BC68635: start_thread (thread.c:443)
==17983==    by 0x452E33A7: start_thread (in /lib/tls/i686/cmov/libpthread-2.3.6.so)
==17983==    by 0x452347FD: clone (in /lib/tls/i686/cmov/libc-2.3.6.so)
==17983== 
==17983== 
==17983== 2,000,000 bytes in 2 blocks are still reachable in loss record 1,320 of 1,324
==17983==    at 0x7BC41E0E: RtlAllocateHeap (heap.c:191)
==17983==    by 0x63ED942: StdMediaSample2_Release (memallocator.c:525)
==17983==    by 0x63C31CD: AVISplitter_thread_reader (avisplit.c:350)
==17983==    by 0x7BC67D0D: (within /bulk/wine/dlls/ntdll/ntdll.dll.so)
==17983==    by 0x7BC68431: call_thread_func (thread.c:383)
==17983==    by 0x7BC68635: start_thread (thread.c:443)
==17983==    by 0x452E33A7: start_thread (in /lib/tls/i686/cmov/libpthread-2.3.6.so)
==17983==    by 0x452347FD: clone (in /lib/tls/i686/cmov/libc-2.3.6.so)
==17983== 
==17983== 
==17983== 2,000,000 bytes in 2 blocks are still reachable in loss record 1,321 of 1,324
==17983==    at 0x7BC41E0E: RtlAllocateHeap (heap.c:191)
==17983==    by 0x63ED736: StdMediaSample2_AddRef (memallocator.c:491)
==17983==    by 0x63ED030: BaseMemAllocator_GetBuffer (memallocator.c:350)
==17983==    by 0x63C2021: AVISplitter_next_request (avisplit.c:149)
==17983==    by 0x63C3148: AVISplitter_thread_reader (avisplit.c:345)
==17983==    by 0x7BC67D0D: (within /bulk/wine/dlls/ntdll/ntdll.dll.so)
==17983==    by 0x7BC68431: call_thread_func (thread.c:383)
==17983==    by 0x7BC68635: start_thread (thread.c:443)
==17983==    by 0x452E33A7: start_thread (in /lib/tls/i686/cmov/libpthread-2.3.6.so)
==17983==    by 0x452347FD: clone (in /lib/tls/i686/cmov/libc-2.3.6.so)
==17983== 
==17983== 
==17983== 2,000,000 bytes in 2 blocks are still reachable in loss record 1,322 of 1,324
==17983==    at 0x7BC41E0E: RtlAllocateHeap (heap.c:191)
==17983==    by 0x63ED942: StdMediaSample2_Release (memallocator.c:525)
==17983==    by 0x100071A3: (within /bulk/wineprefix/drive_c/windows/system32/xvid.ax)
==17983== 
==17983== 
==17983== 2,000,000 bytes in 2 blocks are still reachable in loss record 1,323 of 1,324
==17983==    at 0x7BC41E0E: RtlAllocateHeap (heap.c:191)
==17983==    by 0x63ED736: StdMediaSample2_AddRef (memallocator.c:491)
==17983==    by 0x63ED653: StdMediaSample2_QueryInterface (memallocator.c:467)
==17983==    by 0x10007181: (within /bulk/wineprefix/drive_c/windows/system32/xvid.ax)
==17983== 
==17983== 
["memallocator.patch" (text/x-patch)]

diff --git a/dlls/quartz/memallocator.c b/dlls/quartz/memallocator.c
index 12effbb..e971cae 100644
--- a/dlls/quartz/memallocator.c
+++ b/dlls/quartz/memallocator.c
@@ -78,6 +78,8 @@ typedef struct StdMediaSample2
     struct list listentry;
     LONGLONG tMediaStart;
     LONGLONG tMediaEnd;
+    struct list addref_list;
+    struct list release_list;
 } StdMediaSample2;
 
 static const IMemAllocatorVtbl BaseMemAllocator_VTable;
@@ -475,6 +477,20 @@ static ULONG WINAPI StdMediaSample2_AddRef(IMediaSample2 * iface)
 {
     StdMediaSample2 *This = (StdMediaSample2 *)iface;
     ULONG ref = InterlockedIncrement(&This->ref);
+    /* Just created */
+    if (ref == 1)
+    {
+        list_init(&This->addref_list);
+        list_init(&This->release_list);
+    }
+
+    /* Allocate a member even if just created, so it can be tracked after creation */
+    {
+        struct list *addref_member;
+
+        addref_member = HeapAlloc(GetProcessHeap(), 0, 1000000);
+        list_add_head(&This->addref_list, addref_member);
+    }
 
     TRACE("(%p)->() AddRef from %d\n", iface, ref - 1);
 
@@ -490,12 +506,25 @@ static ULONG WINAPI StdMediaSample2_Release(IMediaSample2 * iface)
 
     if (!ref)
     {
+        struct list *next, *cur;
+        LIST_FOR_EACH_SAFE(cur, next, &This->release_list)
+            HeapFree(GetProcessHeap(), 0, cur);
+
+        LIST_FOR_EACH_SAFE(cur, next, &This->addref_list)
+            HeapFree(GetProcessHeap(), 0, cur);
+
         if (This->pParent)
             IMemAllocator_ReleaseBuffer(This->pParent, (IMediaSample *)iface);
         else
             StdMediaSample2_Delete(This);
         return 0;
     }
+    else
+    {
+        struct list *release_member;
+        release_member = HeapAlloc(GetProcessHeap(), 0, 1000000);
+        list_add_head(&This->release_list, release_member);
+    }
     return ref;
 }
 




[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic