dqn: Put ASAN poisoning behind macros to allow vetting
This commit is contained in:
		
							parent
							
								
									2740987956
								
							
						
					
					
						commit
						0872da026a
					
				| @ -15,6 +15,7 @@ | ||||
|     #endif | ||||
| 
 | ||||
|     #define DQN_ASAN_POISON 1 | ||||
|     #define DQN_ASAN_VET_POISON | ||||
|     #define DQN_NO_CHECK_BREAK | ||||
|     #define DQN_IMPLEMENTATION | ||||
|     #include "dqn.h" | ||||
|  | ||||
							
								
								
									
										17
									
								
								dqn.h
									
									
									
									
									
								
							
							
						
						
									
										17
									
								
								dqn.h
									
									
									
									
									
								
							| @ -230,6 +230,23 @@ | ||||
| //   flag.
 | ||||
| //
 | ||||
| //     DQN_LEAK_TRACING
 | ||||
| //
 | ||||
| // - Define this macro to 1 to enable poisoning of memory from arenas when ASAN
 | ||||
| //   `-fsanitize=address` is enabled. Enabling this will detect memory overwrite
 | ||||
| //   by padding allocated before and after with poisoned memory which will raise
 | ||||
| //   a use-after-poison in ASAN on read/write. This is a no-op if the library is
 | ||||
| //   not compiled with ASAN.
 | ||||
| //
 | ||||
| //     DQN_ASAN_POISON 1
 | ||||
| //
 | ||||
| // - Define this macro to enable sanity checks for manually poisoned memory in
 | ||||
| //   this library when ASAN `-fsanitize=address` is enabled. These sanity checks
 | ||||
| //   ensure that memory from arenas are correctly un/poisoned when pointers are
 | ||||
| //   allocated and returned to the memory arena's. This is a no-op if we are not
 | ||||
| //   compiled with ASAN or `DQN_ASAN_POISON` is not set to `1`.
 | ||||
| //
 | ||||
| //     DQN_ASAN_VET_POISON
 | ||||
| //
 | ||||
| 
 | ||||
| // NOTE: Dqn_Strings ===============================================================================
 | ||||
| // [$CSTR] Dqn_CString8       |                             | C-string helpers
 | ||||
|  | ||||
| @ -220,8 +220,7 @@ DQN_API Dqn_String8 Dqn_Log_MakeString(Dqn_Allocator allocator, | ||||
|         header_size_no_ansi_codes = header.size - colour_esc.size - Dqn_Print_ESCResetString.size; | ||||
|     } | ||||
| 
 | ||||
|     // NOTE: Header padding
 | ||||
|     // =========================================================================
 | ||||
|     // NOTE: Header padding ========================================================================
 | ||||
|     Dqn_usize header_padding = 0; | ||||
|     { | ||||
|         DQN_LOCAL_PERSIST Dqn_usize max_header_length = 0; | ||||
| @ -229,8 +228,7 @@ DQN_API Dqn_String8 Dqn_Log_MakeString(Dqn_Allocator allocator, | ||||
|         header_padding                                = max_header_length - header_size_no_ansi_codes; | ||||
|     } | ||||
| 
 | ||||
|     // NOTE: Construct final log
 | ||||
|     // =========================================================================
 | ||||
|     // NOTE: Construct final log ===================================================================
 | ||||
|     Dqn_String8 user_msg = Dqn_String8_InitFV(allocator, fmt, args); | ||||
|     Dqn_String8 result   = Dqn_String8_Allocate(allocator, header.size + header_padding + user_msg.size, Dqn_ZeroMem_No); | ||||
|     DQN_MEMCPY(result.data,                                header.data, header.size); | ||||
|  | ||||
							
								
								
									
										30
									
								
								dqn_debug.h
									
									
									
									
									
								
							
							
						
						
									
										30
									
								
								dqn_debug.h
									
									
									
									
									
								
							| @ -38,6 +38,36 @@ | ||||
|     #define DQN_ASAN_POISON_ALIGNMENT 8 | ||||
| #endif | ||||
| 
 | ||||
| // NOTE: MSVC does not support the feature detection macro for instance so we
 | ||||
| // compile it out
 | ||||
| #if !defined(__has_feature) | ||||
|     #define __has_feature(x) 0 | ||||
| #endif | ||||
| 
 | ||||
| #if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__) | ||||
|     #include <sanitizer/asan_interface.h> | ||||
|     #if defined(DQN_ASAN_VET_POISON) | ||||
|         #define DQN_ASAN_POISON_MEMORY_REGION(ptr, size) \ | ||||
|             do { \ | ||||
|                 __asan_poison_memory_region((ptr), (size)); \ | ||||
|                 DQN_ASSERT(__asan_address_is_poisoned((ptr))); \ | ||||
|                 DQN_ASSERT(__asan_address_is_poisoned((char *)(ptr) + ((size) - 1))); \ | ||||
|                 DQN_ASSERT(!__asan_address_is_poisoned((char *)(ptr) + (size))); \ | ||||
|             } while (0) | ||||
| 
 | ||||
|         #define DQN_ASAN_UNPOISON_MEMORY_REGION(ptr, size) \ | ||||
|             do { \ | ||||
|                 __asan_unpoison_memory_region((ptr), (size)); \ | ||||
|                 DQN_ASSERT(__asan_region_is_poisoned((ptr), (size)) == 0); \ | ||||
|             } while (0) | ||||
|     #else | ||||
|         #define DQN_ASAN_POISON_MEMORY_REGION(ptr, size) __asan_poison_memory_region(ptr, size) | ||||
|         #define DQN_ASAN_UNPOISON_MEMORY_REGION(ptr, size) __asan_unpoison_memory_region(ptr, size) | ||||
|     #endif | ||||
| #else | ||||
|     #define DQN_ASAN_POISON_MEMORY_REGION(ptr, size) (void)(ptr); (void)(size) | ||||
|     #define DQN_ASAN_UNPOISON_MEMORY_REGION(ptr, size) (void)(ptr); (void)(size) | ||||
| #endif | ||||
| 
 | ||||
| // NOTE: [$CALL] Dqn_CallSite ======================================================================
 | ||||
| struct Dqn_CallSite | ||||
|  | ||||
| @ -10,8 +10,6 @@ | ||||
| #include "b_stacktrace.h" | ||||
| 
 | ||||
| // NOTE: [$OS_H] OS Headers ========================================================================
 | ||||
| #include <sanitizer/asan_interface.h> | ||||
| 
 | ||||
| #if defined(DQN_OS_WIN32) | ||||
|     #pragma comment(lib, "bcrypt") | ||||
|     #pragma comment(lib, "wininet") | ||||
|  | ||||
| @ -840,6 +840,17 @@ DQN_API Dqn_Library *Dqn_Library_Init() | ||||
|     } | ||||
|     #endif | ||||
| 
 | ||||
|     // ============================================================================================
 | ||||
| 
 | ||||
|     Dqn_Log_DebugF("Dqn Library initialised with features\n"); | ||||
| 
 | ||||
|     if (DQN_ASAN_POISON) | ||||
|         Dqn_Print_StdLnF(Dqn_PrintStd_Err, "  - ASAN manual poisoning"); | ||||
| 
 | ||||
|     #if defined(DQN_ASAN_VET_POISON) | ||||
|     Dqn_Print_StdLnF(Dqn_PrintStd_Err, "  - ASAN manual poisoning vetting"); | ||||
|     #endif | ||||
| 
 | ||||
|     return result; | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -1,6 +1,4 @@ | ||||
| // NOTE: [$ALLO] Dqn_Allocator =====================================================================
 | ||||
| #include <ios> | ||||
| #include <sanitizer/asan_interface.h> | ||||
| DQN_API void *Dqn_Allocator_Alloc(Dqn_Allocator allocator, size_t size, uint8_t align, Dqn_ZeroMem zero_mem) | ||||
| { | ||||
|     void *result = NULL; | ||||
| @ -237,8 +235,9 @@ DQN_API Dqn_MemBlock *Dqn_MemBlock_Init(Dqn_usize reserve, Dqn_usize commit, uin | ||||
|         if (DQN_ASAN_POISON) { // NOTE: Poison (guard page + entire block), we unpoison as we allocate
 | ||||
|             DQN_ASSERT(Dqn_IsPowerOfTwoAligned(result->data, DQN_ASAN_POISON_ALIGNMENT)); | ||||
|             DQN_ASSERT(Dqn_IsPowerOfTwoAligned(result->size, DQN_ASAN_POISON_ALIGNMENT)); | ||||
|             void *poison_ptr = DQN_CAST(void *)Dqn_AlignUpPowerOfTwo(DQN_CAST(char *)result + sizeof(Dqn_MemBlock), DQN_ASAN_POISON_ALIGNMENT); | ||||
|             ASAN_POISON_MEMORY_REGION(poison_ptr, g_dqn_library->os_page_size + result->size); | ||||
|             void *poison_ptr          = DQN_CAST(void *)Dqn_AlignUpPowerOfTwo(DQN_CAST(char *)result + sizeof(Dqn_MemBlock), DQN_ASAN_POISON_ALIGNMENT); | ||||
|             Dqn_usize bytes_to_poison = g_dqn_library->os_page_size + result->size; | ||||
|             DQN_ASAN_POISON_MEMORY_REGION(poison_ptr, bytes_to_poison); | ||||
|         } | ||||
|     } | ||||
|     return result; | ||||
| @ -261,9 +260,8 @@ DQN_API void *Dqn_MemBlock_Alloc(Dqn_MemBlock *block, Dqn_usize size, uint8_t al | ||||
|     block->used = new_used; | ||||
|     DQN_ASSERT(Dqn_IsPowerOfTwoAligned(result, alignment)); | ||||
| 
 | ||||
|     if (DQN_ASAN_POISON) { | ||||
|         ASAN_UNPOISON_MEMORY_REGION(result, size); | ||||
|     } | ||||
|     if (DQN_ASAN_POISON) | ||||
|         DQN_ASAN_UNPOISON_MEMORY_REGION(result, size); | ||||
| 
 | ||||
|     if (zero_mem == Dqn_ZeroMem_Yes) { | ||||
|         Dqn_usize reused_bytes = DQN_MIN(block->commit - size_required.data_offset, size); | ||||
| @ -286,9 +284,8 @@ DQN_API void Dqn_MemBlock_Free(Dqn_MemBlock *block) | ||||
|     if (!block) | ||||
|         return; | ||||
|     Dqn_usize release_size = block->size + Dqn_MemBlock_MetadataSize(); | ||||
|     if (DQN_ASAN_POISON) { | ||||
|         ASAN_UNPOISON_MEMORY_REGION(block, release_size); | ||||
|     } | ||||
|     if (DQN_ASAN_POISON) | ||||
|         DQN_ASAN_UNPOISON_MEMORY_REGION(block, release_size); | ||||
|     Dqn_VMem_Release(block, release_size); | ||||
| } | ||||
| 
 | ||||
| @ -307,13 +304,10 @@ DQN_API void Dqn_MemBlock_PopTo(Dqn_MemBlock *block, Dqn_usize to) | ||||
|         return; | ||||
| 
 | ||||
|     if (DQN_ASAN_POISON) { | ||||
|         // TODO(doyle): The poison API takes addresses that are 8 byte aligned
 | ||||
|         // so there are gaps here if we are dealing with objects that aren't 8
 | ||||
|         // byte aligned unfortunately.
 | ||||
|         void *poison_ptr          = DQN_CAST(void *)Dqn_AlignUpPowerOfTwo(DQN_CAST(char *)block->data + to, DQN_ASAN_POISON_ALIGNMENT); | ||||
|         void *end_ptr             = DQN_CAST(char *)block->data + block->used; | ||||
|         void *poison_ptr          = DQN_CAST(char *)block->data + to; | ||||
|         void *end_ptr             = DQN_CAST(void *)Dqn_AlignUpPowerOfTwo((DQN_CAST(uintptr_t)block->data + block->used), DQN_ASAN_POISON_ALIGNMENT); | ||||
|         uintptr_t bytes_to_poison = DQN_CAST(uintptr_t)end_ptr - DQN_CAST(uintptr_t)poison_ptr; | ||||
|         ASAN_POISON_MEMORY_REGION(poison_ptr, bytes_to_poison); | ||||
|         DQN_ASAN_POISON_MEMORY_REGION(poison_ptr, bytes_to_poison); | ||||
|     } | ||||
|     block->used = to; | ||||
| } | ||||
|  | ||||
| @ -31,8 +31,7 @@ DQN_API void Dqn_Print_Std(Dqn_PrintStd std_handle, Dqn_String8 string) | ||||
|     DQN_ASSERT(std_handle == Dqn_PrintStd_Out || std_handle == Dqn_PrintStd_Err); | ||||
| 
 | ||||
|     #if defined(DQN_OS_WIN32) | ||||
|     // NOTE: Get the output handles from kernel
 | ||||
|     // =========================================================================
 | ||||
|     // NOTE: Get the output handles from kernel ====================================================
 | ||||
|     DQN_THREAD_LOCAL void *std_out_print_handle     = nullptr; | ||||
|     DQN_THREAD_LOCAL void *std_err_print_handle     = nullptr; | ||||
|     DQN_THREAD_LOCAL bool  std_out_print_to_console = false; | ||||
| @ -47,8 +46,7 @@ DQN_API void Dqn_Print_Std(Dqn_PrintStd std_handle, Dqn_String8 string) | ||||
|         std_err_print_to_console = GetConsoleMode(std_err_print_handle, &mode) != 0; | ||||
|     } | ||||
| 
 | ||||
|     // NOTE: Select the output handle
 | ||||
|     // =========================================================================
 | ||||
|     // NOTE: Select the output handle ==============================================================
 | ||||
|     void *print_handle    = std_out_print_handle; | ||||
|     bool print_to_console = std_out_print_to_console; | ||||
|     if (std_handle == Dqn_PrintStd_Err) { | ||||
| @ -56,8 +54,7 @@ DQN_API void Dqn_Print_Std(Dqn_PrintStd std_handle, Dqn_String8 string) | ||||
|         print_to_console = std_err_print_to_console; | ||||
|     } | ||||
| 
 | ||||
|     // NOTE: Write the string
 | ||||
|     // =========================================================================
 | ||||
|     // NOTE: Write the string ======================================================================
 | ||||
|     DQN_ASSERT(string.size < DQN_CAST(unsigned long)-1); | ||||
|     unsigned long bytes_written = 0; (void)bytes_written; | ||||
|     if (print_to_console) { | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user