+ExFreePoolWithTag()
[captive.git] / src / libcaptive / mm / pool.c
index 36224c8..4f37778 100644 (file)
 #include "reactos/ntos/types.h"        /* for PVOID etc. */
 #include <glib/gmessages.h>
 #include <glib/gmem.h>
+#include <glib/ghash.h>
+
+
+/* map PVOID->GUINT_TO_POINTER(ULONG Tag) */
+static GHashTable *memory_Tag_hash;
+
+static void memory_Tag_hash_init(void)
+{
+       if (memory_Tag_hash)
+               return;
+       memory_Tag_hash=g_hash_table_new(g_direct_hash,g_direct_equal);
+}
 
 
 /**
  * @PoolType: Type of memory to allocate. Safely ignored by libcaptive as it is
  * too low level for it.
  * @NumberOfBytes: Size of the requested allocation. Value 0 permitted (returns %NULL).
- * @Tag: 4-bytes of block identification for debugging purposes.
- * Ignored by libcaptive.
+ * @Tag: 4-bytes of block identification for debugging purposes and/or ExFreePoolWithTag().
+ * Bit 7 (==%0x80 ) of each byte must be cleared.
+ * %PROTECTED_POOL with @Tag bit 31 set is not yet implemented.
  *
  * Allocates the specified memory block. libcaptive passes the allocation to
- * g_malloc(). @Tag is no longer trackable for the allocated memory block.
- * @Tag is ignored by libcaptive.
+ * g_malloc() and @Tag is marked to this allocation.
  *
  * Returns: Memory block base if successfuly allocated. %NULL otherwise.
  * The allocated memory block is not cleared.
  */
 PVOID ExAllocatePoolWithTag(ULONG PoolType,ULONG NumberOfBytes,ULONG Tag)
 {
+PVOID r;
+
+       g_return_val_if_fail((Tag&0x80808080)==0,NULL);
+
+       memory_Tag_hash_init();
+
        if (!NumberOfBytes)
                return NULL;
+       /* FIXME: >=PAGE_SIZE allocations should be PAGE_SIZE aligned */
+       r=g_malloc(NumberOfBytes);
+
+       g_assert(FALSE==g_hash_table_lookup_extended(memory_Tag_hash,
+                                               r,      /* lookup_key */
+                                               NULL,   /* orig_key */
+                                               NULL)); /* value */
+       g_hash_table_insert(memory_Tag_hash,
+                       (gpointer)r,    /* key */
+                       GUINT_TO_POINTER(Tag)); /* value */
 
-       return g_malloc(NumberOfBytes);
+       return r;
 }
 
 /**
@@ -56,15 +84,19 @@ PVOID ExAllocatePoolWithTag(ULONG PoolType,ULONG NumberOfBytes,ULONG Tag)
  * @NumberOfBytes: Size of the requested allocation. Value 0 permitted (returns %NULL).
  *
  * Allocates the specified memory block. Calls ExAllocatePoolWithTag() with
- * undeterministic @Tag value.
+ * @Tag value %0x00000000. At least this value seems to be assumed by WXP <ntddk.h>
+ * although it is not officially documented for W32.
  *
  * Returns: Memory block base if successfuly allocated. %NULL otherwise.
  * The allocated memory block is not cleared.
  */
 PVOID ExAllocatePool(POOL_TYPE PoolType,ULONG NumberOfBytes)
 {
+       /* FIXME: It would be better to mark such block as 'unTagged' but we would have
+        * to maintain some structure for 'memory_Tag_hash' values instead of just GUINT_TO_POINTER().
+        */
        return ExAllocatePoolWithTag(PoolType,NumberOfBytes,
-                       0);     /* Tag; reactos uses TAG_NONE ('None') but it is not documented for W32 */
+                       0x00000000); /* Tag; reactos uses TAG_NONE ('None') but it W32 uses %0x00000000 */
 }
 
 /**
@@ -77,7 +109,51 @@ PVOID ExAllocatePool(POOL_TYPE PoolType,ULONG NumberOfBytes)
  */
 VOID ExFreePool(IN PVOID Block)
 {
+gboolean errbool;
+
        g_return_if_fail(Block!=NULL);
 
+       memory_Tag_hash_init();
+
+       errbool=g_hash_table_remove(memory_Tag_hash,Block);
+       g_assert(errbool==TRUE);
+
        g_free(Block);
 }
+
+
+/**
+ * ExFreePoolWithTag:
+ * @Block: Base address of the memory block. %NULL value is forbidden.
+ * @Tag: 4-bytes of required block identification.
+ * Bit 7 (==%0x80 ) of each byte must be cleared.
+ * %PROTECTED_POOL with @Tag bit 31 set is not yet implemented.
+ * Value %0x0000000 is permitted for blocks marked with any Tag.
+ *
+ * Deallocate the given memory block. Block must be already successfuly
+ * allocated by a previous ExAllocatePoolWithTag() call.
+ * Block may be allocated by ExAllocatePool() if @Tag is passed %0x00000000.
+ * Please see more about @Tag in ExAllocatePool().
+ * It is forbidden to pass invalid @Tag for @Block.
+ *
+ * You can no longer assume anything about this base address / memory block.
+ */
+VOID ExFreePoolWithTag(IN PVOID Block,IN ULONG Tag)
+{
+gpointer memory_Tag_gpointer;
+gboolean errbool;
+
+       g_return_if_fail(Block!=NULL);
+       g_return_if_fail((Tag&0x80808080)==0);
+
+       memory_Tag_hash_init();
+
+       errbool=g_hash_table_lookup_extended(memory_Tag_hash,
+                                               Block,  /* lookup_key */
+                                               NULL,   /* orig_key */
+                                               &memory_Tag_gpointer);  /* value */
+       g_return_if_fail(errbool==TRUE);
+       g_return_if_fail(!Tag || GPOINTER_TO_UINT(memory_Tag_gpointer)==Tag);
+
+       ExFreePool(Block);
+}