diff --git a/src/z_zone.c b/src/z_zone.c
index 0852fabaeac03f3751d33063cb14f63105678537..c0c7d75aad3381d66fe684e92ef6484fcb78dad9 100644
--- a/src/z_zone.c
+++ b/src/z_zone.c
@@ -45,6 +45,19 @@ static boolean Z_calloc = false;
 #include "memcheck.h"
 #endif
 
+#if defined(__SANITIZE_ADDRESS__)
+#   include <sanitizer/asan_interface.h>
+#elif defined(__has_feature)
+#   if __has_feature(address_sanitizer)
+#       include <sanitizer/asan_interface.h>
+#   endif
+#endif
+
+#if !defined(ASAN_POISON_MEMORY_REGION)
+#    define ASAN_POISON_MEMORY_REGION(a, b) do {} while(0)
+#    define ASAN_UNPOISON_MEMORY_REGION(a, b) do {} while(0)
+#endif
+
 #define ZONEID 0xa441d13d
 
 #ifdef ZDEBUG
@@ -137,6 +150,7 @@ void Z_Free(void *ptr)
 #endif
 
 	block = MEMBLOCK(ptr);
+	ASAN_UNPOISON_MEMORY_REGION(block, sizeof(memblock_t));
 #ifdef PARANOIA
 	if (block->id != ZONEID)
 #ifdef ZDEBUG
@@ -165,8 +179,13 @@ void Z_Free(void *ptr)
 #ifdef VALGRIND_DESTROY_MEMPOOL
 	VALGRIND_DESTROY_MEMPOOL(block);
 #endif
+
+	ASAN_UNPOISON_MEMORY_REGION(block->prev, sizeof(memblock_t));
 	block->prev->next = block->next;
+	ASAN_POISON_MEMORY_REGION(block->prev, sizeof(memblock_t));
+	ASAN_UNPOISON_MEMORY_REGION(block->next, sizeof(memblock_t));
 	block->next->prev = block->prev;
+	ASAN_POISON_MEMORY_REGION(block->next, sizeof(memblock_t));
 	free(block);
 }
 
@@ -237,7 +256,9 @@ void *Z_MallocAlign(size_t size, INT32 tag, void *user, INT32 alignbits)
 	block->next = head.next;
 	block->prev = &head;
 	head.next = block;
+	ASAN_UNPOISON_MEMORY_REGION(block->next, sizeof(memblock_t));
 	block->next->prev = block;
+	ASAN_POISON_MEMORY_REGION(block->next, sizeof(memblock_t));
 
 	block->tag = tag;
 	block->user = NULL;
@@ -263,6 +284,8 @@ void *Z_MallocAlign(size_t size, INT32 tag, void *user, INT32 alignbits)
 		I_Error("Z_Malloc: attempted to allocate purgable block "
 			"(size %s) with no user", sizeu1(size));
 
+	ASAN_POISON_MEMORY_REGION(block, sizeof(memblock_t));
+
 	return ptr;
 }
 
@@ -341,6 +364,7 @@ void *Z_ReallocAlign(void *ptr, size_t size, INT32 tag, void *user, INT32 alignb
 	}
 
 	block = MEMBLOCK(ptr);
+	ASAN_UNPOISON_MEMORY_REGION(block, sizeof(memblock_t));
 #ifdef PARANOIA
 	if (block->id != ZONEID)
 #ifdef ZDEBUG
@@ -353,6 +377,12 @@ void *Z_ReallocAlign(void *ptr, size_t size, INT32 tag, void *user, INT32 alignb
 	if (block == NULL)
 		return NULL;
 
+	if (size < block->realsize)
+		copysize = size;
+	else
+		copysize = block->realsize;
+	ASAN_POISON_MEMORY_REGION(block, sizeof(memblock_t));
+
 #ifdef ZDEBUG
 	// Write every Z_Realloc call to a debug file.
 	DEBFILE(va("Z_Realloc at %s:%d\n", file, line));
@@ -361,11 +391,6 @@ void *Z_ReallocAlign(void *ptr, size_t size, INT32 tag, void *user, INT32 alignb
 	rez = Z_MallocAlign(size, tag, user, alignbits);
 #endif
 
-	if (size < block->realsize)
-		copysize = size;
-	else
-		copysize = block->realsize;
-
 	M_Memcpy(rez, ptr, copysize);
 
 #ifdef ZDEBUG
@@ -397,9 +422,12 @@ void Z_FreeTags(INT32 lowtag, INT32 hightag)
 	Z_CheckHeap(420);
 	for (block = head.next; block != &head; block = next)
 	{
+		ASAN_UNPOISON_MEMORY_REGION(block, sizeof(memblock_t));
 		next = block->next; // get link before freeing
 		if (block->tag >= lowtag && block->tag <= hightag)
 			Z_Free(MEMORY(block));
+		else
+			ASAN_POISON_MEMORY_REGION(block, sizeof(memblock_t));
 	}
 }
 
@@ -492,6 +520,7 @@ void Z_CheckHeap(INT32 i)
 				);
 		}
 #endif
+		ASAN_UNPOISON_MEMORY_REGION(block, sizeof(memblock_t));
 		if (block->user != NULL && *(block->user) != given)
 		{
 			I_Error("Z_CheckHeap %d: block %u"
@@ -504,6 +533,7 @@ void Z_CheckHeap(INT32 i)
 #endif
 				);
 		}
+		ASAN_UNPOISON_MEMORY_REGION(block->next, sizeof(memblock_t));
 		if (block->next->prev != block)
 		{
 			I_Error("Z_CheckHeap %d: block %u"
@@ -516,6 +546,9 @@ void Z_CheckHeap(INT32 i)
 #endif
 				);
 		}
+		ASAN_POISON_MEMORY_REGION(block->next, sizeof(memblock_t));
+
+		ASAN_UNPOISON_MEMORY_REGION(block->prev, sizeof(memblock_t));
 		if (block->prev->next != block)
 		{
 			I_Error("Z_CheckHeap %d: block %u"
@@ -528,6 +561,8 @@ void Z_CheckHeap(INT32 i)
 #endif
 				);
 		}
+		ASAN_POISON_MEMORY_REGION(block->prev, sizeof(memblock_t));
+
 		if (block->id != ZONEID)
 		{
 			I_Error("Z_CheckHeap %d: block %u"
@@ -540,6 +575,7 @@ void Z_CheckHeap(INT32 i)
 #endif
 				);
 		}
+		ASAN_POISON_MEMORY_REGION(block, sizeof(memblock_t));
 	}
 }
 
@@ -566,6 +602,7 @@ void Z_ChangeTag(void *ptr, INT32 tag)
 		return;
 
 	block = MEMBLOCK(ptr);
+	ASAN_UNPOISON_MEMORY_REGION(block, sizeof(memblock_t));
 
 #ifdef PARANOIA
 	if (block->id != ZONEID) I_Error("Z_ChangeTag at %s:%d: wrong id", file, line);
@@ -576,6 +613,7 @@ void Z_ChangeTag(void *ptr, INT32 tag)
 			"tried to make block purgable but it has no owner");
 
 	block->tag = tag;
+	ASAN_POISON_MEMORY_REGION(block, sizeof(memblock_t));
 }
 
 /** Changes a memory block's user.
@@ -598,6 +636,7 @@ void Z_SetUser(void *ptr, void **newuser)
 
 	block = MEMBLOCK(ptr);
 
+	ASAN_UNPOISON_MEMORY_REGION(block, sizeof(memblock_t));
 #ifdef PARANOIA
 	if (block->id != ZONEID) I_Error("Z_SetUser at %s:%d: wrong id", file, line);
 #endif
@@ -608,6 +647,7 @@ void Z_SetUser(void *ptr, void **newuser)
 
 	block->user = (void*)newuser;
 	*newuser = ptr;
+	ASAN_POISON_MEMORY_REGION(block, sizeof(memblock_t));
 }
 
 // -----------------