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)); } // -----------------