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 - 1.102
+++ dlls/msi/msi.c 21 Sep 2005 15:02:32 -
@@ -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 - 1.96
+++ dlls/msi/msipriv.h 21 Sep 2005 15:02:32 -
@@ -31,6 +31,7 @@
#include "objidl.h"
#include "winnls.h"
#include "wine/list.h"
+#include "wine/debug.h"
#define MSI_DATASIZEMASK 0x00ff
#define MSITYPE_VALID0x0100
@@ -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