Hi,
This patch is written for MSI, but could be adapted to other code. It
keeps a linked list of allocated memory and removes free'd memory from
the list.
It requires that you change all the HeapAlloc's or mallocs in a dll to
msi_alloc (for example), but can detect unfree'd memory and invalid free's.
I have discovered quite a few problems in my own code with this patch,
so hopefully somebody else will find it useful too.
Mike
Index: dlls/msi/msi.c
===================================================================
RCS file: /home/mike/src/wine-cvs/wine/dlls/msi/msi.c,v
retrieving revision 1.102
diff -u -p -r1.102 msi.c
--- dlls/msi/msi.c 20 Sep 2005 11:59:14 -0000 1.102
+++ dlls/msi/msi.c 21 Sep 2005 15:02:32 -0000
@@ -1273,6 +1273,31 @@ end:
}
+struct list msi_memory_list;
+CRITICAL_SECTION msi_mem_cs;
+
+CRITICAL_SECTION msi_mem_cs;
+static CRITICAL_SECTION_DEBUG msi_mem_cs_debug =
+{
+ 0, 0, &msi_mem_cs,
+ { &msi_mem_cs_debug.ProcessLocksList,
+ &msi_mem_cs_debug.ProcessLocksList },
+ 0, 0, { (DWORD_PTR)(__FILE__ ": msi_mem_cs") }
+};
+CRITICAL_SECTION msi_mem_cs = { &msi_mem_cs_debug, -1, 0, 0, 0, 0 };
+
+static void msi_dump_allocated_memory(void)
+{
+ struct msi_mem_list *mem;
+
+ EnterCriticalSection( &msi_mem_cs );
+ LIST_FOR_EACH_ENTRY( mem, &msi_memory_list, struct msi_mem_list, entry )
+ ERR("unfreed memory %p line %d file %s\n", mem, mem->line, mem->file);
+ LeaveCriticalSection( &msi_mem_cs );
+}
+
+extern void msi_close_handles(void);
+
/******************************************************************
* DllMain
*/
@@ -1281,11 +1306,13 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL,
switch(fdwReason)
{
case DLL_PROCESS_ATTACH:
+ list_init( &msi_memory_list );
msi_hInstance = hinstDLL;
DisableThreadLibraryCalls(hinstDLL);
msi_dialog_register_class();
break;
case DLL_PROCESS_DETACH:
+ msi_dump_allocated_memory();
msi_dialog_unregister_class();
/* FIXME: Cleanup */
break;
Index: dlls/msi/msipriv.h
===================================================================
RCS file: /home/mike/src/wine-cvs/wine/dlls/msi/msipriv.h,v
retrieving revision 1.96
diff -u -p -r1.96 msipriv.h
--- dlls/msi/msipriv.h 21 Sep 2005 10:55:23 -0000 1.96
+++ dlls/msi/msipriv.h 21 Sep 2005 15:02:32 -0000
@@ -31,6 +31,7 @@
#include "objidl.h"
#include "winnls.h"
#include "wine/list.h"
+#include "wine/debug.h"
#define MSI_DATASIZEMASK 0x00ff
#define MSITYPE_VALID 0x0100
@@ -418,66 +419,136 @@ extern DWORD gUIFilter;
extern LPVOID gUIContext;
extern WCHAR gszLogFile[MAX_PATH];
-/* memory allocation macro functions */
-static inline void *msi_alloc( size_t len )
-{
- return HeapAlloc( GetProcessHeap(), 0, len );
-}
+extern struct list msi_memory_list;
+extern CRITICAL_SECTION msi_mem_cs;
-static inline void *msi_alloc_zero( size_t len )
-{
- return HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, len );
-}
+#define MSI_MEM_MAGIC 0x04250919
-static inline void *msi_realloc( void *mem, size_t len )
+struct msi_mem_list {
+ int magic;
+ struct list entry;
+ int line;
+ const char *file;
+};
+
+#define MSI_MEMORY_DEBUG
+
+static inline void *__msi_alloc( int flags, size_t len, int line, const char *file )
{
- return HeapReAlloc( GetProcessHeap(), 0, mem, len );
+#ifdef MSI_MEMORY_DEBUG
+ struct msi_mem_list *elem;
+ EnterCriticalSection( &msi_mem_cs );
+ elem = HeapAlloc( GetProcessHeap(), flags, sizeof *elem + len );
+ if (elem)
+ {
+ elem->magic = MSI_MEM_MAGIC;
+ elem->line = line;
+ elem->file = file;
+ list_add_tail( &msi_memory_list, &elem->entry );
+ elem++;
+ }
+ LeaveCriticalSection( &msi_mem_cs );
+ return elem;
+#else
+ return HeapAlloc( GetProcessHeap(), flags, len );
+#endif
}
-static inline void *msi_realloc_zero( void *mem, size_t len )
+static inline void *__msi_realloc( void *mem, int flags, size_t len, int line, const char *file )
{
- return HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, mem, len );
-}
+#ifdef MSI_MEMORY_DEBUG
+ struct msi_mem_list *elem = mem;
+ if (!elem--) return NULL;
-static inline BOOL msi_free( void *mem )
+ if (elem->magic != MSI_MEM_MAGIC)
+ {
+ MESSAGE("msi: bad realloc %s # %d\n", file, line);
+ return NULL;
+ }
+ EnterCriticalSection( &msi_mem_cs );
+ list_remove( &elem->entry );
+ elem = HeapReAlloc( GetProcessHeap(), flags, elem, sizeof *elem + len );
+ if (elem)
+ {
+ list_add_tail( &msi_memory_list, &elem->entry );
+ elem++;
+ }
+ LeaveCriticalSection( &msi_mem_cs );
+
+ return elem;
+#else
+ return HeapReAlloc( GetProcessHeap(), flags, mem, len );
+#endif
+}
+static inline BOOL __msi_free( void *mem, int line, const char *file )
{
+#ifdef MSI_MEMORY_DEBUG
+ struct msi_mem_list *elem = mem;
+ if (!elem--) return TRUE;
+ if (elem->magic != MSI_MEM_MAGIC)
+ {
+ MESSAGE("msi: bad free %s # %d\n", file, line);
+ (*(int*)0) = 0;
+ return FALSE;
+ }
+ elem->magic = 0;
+ EnterCriticalSection( &msi_mem_cs );
+ list_remove( &elem->entry );
+ LeaveCriticalSection( &msi_mem_cs );
+ return HeapFree( GetProcessHeap(), 0, elem );
+#else
return HeapFree( GetProcessHeap(), 0, mem );
+#endif
}
-inline static char *strdupWtoA( LPCWSTR str )
+#define msi_alloc( len ) __msi_alloc( 0, len, __LINE__, __FILE__ )
+#define msi_alloc_zero( len ) __msi_alloc( HEAP_ZERO_MEMORY, len, __LINE__, __FILE__ )
+#define msi_realloc( mem, len ) __msi_realloc( mem, 0, len, __LINE__, __FILE__ )
+#define msi_realloc_zero( mem, len ) __msi_realloc( mem, HEAP_ZERO_MEMORY, len, __LINE__, __FILE__ )
+#define msi_free( mem ) __msi_free( mem, __LINE__, __FILE__ )
+
+inline static char *__strdupWtoA( LPCWSTR str, int line, const char *file )
{
LPSTR ret = NULL;
DWORD len;
-
- if (!str) return ret;
+ if (!str)
+ return ret;
+
len = WideCharToMultiByte( CP_ACP, 0, str, -1, NULL, 0, NULL, NULL);
- ret = msi_alloc( len );
+ ret = __msi_alloc( 0, len, line, file );
if (ret)
WideCharToMultiByte( CP_ACP, 0, str, -1, ret, len, NULL, NULL );
return ret;
}
-inline static LPWSTR strdupAtoW( LPCSTR str )
+#define strdupWtoA( str ) __strdupWtoA( str, __LINE__, __FILE__ )
+
+inline static LPWSTR __strdupAtoW( LPCSTR str, int line, const char *file )
{
LPWSTR ret = NULL;
DWORD len;
- if (!str) return ret;
+ if (!str)
+ return ret;
len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
- ret = msi_alloc( len * sizeof(WCHAR) );
+ ret = __msi_alloc( 0, len * sizeof(WCHAR), line, file );
if (ret)
MultiByteToWideChar( CP_ACP, 0, str, -1, ret, len );
return ret;
}
+#define strdupAtoW( str ) __strdupAtoW( str, __LINE__, __FILE__ )
-inline static LPWSTR strdupW( LPCWSTR src )
+inline static LPWSTR __strdupW( LPCWSTR src, int line, const char *file )
{
LPWSTR dest;
if (!src) return NULL;
- dest = msi_alloc( (lstrlenW(src)+1)*sizeof(WCHAR) );
- if (dest)
- lstrcpyW(dest, src);
+ dest = __msi_alloc( 0, (lstrlenW(src)+1)*sizeof(WCHAR), line, file );
+ if (!dest)
+ return NULL;
+ lstrcpyW(dest, src);
return dest;
}
+#define strdupW( str ) __strdupW( str, __LINE__, __FILE__ )
+
#endif /* __WINE_MSI_PRIVATE__ */