1 #include "precomp.h" 2 3 #ifdef _DEBUG_MEM 4 5 #define REDZONE_SIZE 32 6 #define REDZONE_LEFT 0x78 7 #define REDZONE_RIGHT 0x87 8 9 typedef struct 10 { 11 size_t size; 12 LIST_ENTRY list_entry; 13 const char *file; 14 int line; 15 } alloc_info, *palloc_info; 16 17 static size_t allocations = 0; 18 static size_t allocated_memory = 0; 19 static LIST_ENTRY alloc_list_head = {&alloc_list_head, &alloc_list_head}; 20 21 static void * 22 get_base_ptr(void *ptr) 23 { 24 return (void *)((UINT_PTR)ptr - REDZONE_SIZE - sizeof(alloc_info)); 25 } 26 27 static void * 28 get_ptr_from_base(palloc_info info) 29 { 30 return (void*)((size_t)(info + 1) + REDZONE_SIZE); 31 } 32 33 static void * 34 write_redzone(void *ptr, size_t size, const char *file, int line) 35 { 36 void *ret; 37 palloc_info info = (palloc_info)ptr; 38 39 info->size = size; 40 info->file = file; 41 info->line = line; 42 43 ptr = (void *)(info + 1); 44 memset(ptr, REDZONE_LEFT, REDZONE_SIZE); 45 ret = (void *)((size_t)ptr + REDZONE_SIZE); 46 ptr = (void *)((size_t)ret + size); 47 memset(ptr, REDZONE_RIGHT, REDZONE_SIZE); 48 return ret; 49 } 50 51 static int 52 check_redzone_region(void *ptr, unsigned char sig, void **newptr) 53 { 54 unsigned char *p, *q; 55 int ret = 1; 56 57 p = (unsigned char *)ptr; 58 q = p + REDZONE_SIZE; 59 while (p != q) 60 { 61 if (*(p++) != sig) 62 ret = 0; 63 } 64 65 if (newptr != NULL) 66 *newptr = p; 67 return ret; 68 } 69 70 static void 71 redzone_err(const char *msg, palloc_info info, void *ptr, const char *file, int line) 72 { 73 DbgPrint("CMD: %s\n", msg); 74 DbgPrint(" Block: 0x%p Size: %lu\n", ptr, info->size); 75 DbgPrint(" Allocated from %s:%d\n", info->file, info->line); 76 DbgPrint(" Detected at: %s:%d\n", file, line); 77 ASSERT(FALSE); 78 ExitProcess(1); 79 } 80 81 static void 82 check_redzone(void *ptr, const char *file, int line) 83 { 84 palloc_info info = (palloc_info)ptr; 85 ptr = (void *)(info + 1); 86 if (!check_redzone_region(ptr, REDZONE_LEFT, &ptr)) 87 redzone_err("Detected buffer underflow!", info, ptr, file, line); 88 ptr = (void *)((UINT_PTR)ptr + info->size); 89 if (!check_redzone_region(ptr, REDZONE_RIGHT, NULL)) 90 redzone_err("Detected buffer overflow!", info, ptr, file, line); 91 } 92 93 static size_t 94 calculate_size_with_redzone(size_t size) 95 { 96 return sizeof(alloc_info) + size + (2 * REDZONE_SIZE); 97 } 98 99 static void 100 add_mem_to_list(void *ptr) 101 { 102 palloc_info info = (palloc_info)ptr; 103 InsertTailList(&alloc_list_head, &info->list_entry); 104 } 105 106 static void 107 del_mem_from_list(void *ptr) 108 { 109 palloc_info info = (palloc_info)ptr; 110 RemoveEntryList(&info->list_entry); 111 } 112 113 static void 114 dump_mem_list(void) 115 { 116 palloc_info info; 117 PLIST_ENTRY entry; 118 void *ptr; 119 120 entry = alloc_list_head.Flink; 121 while (entry != &alloc_list_head) 122 { 123 info = CONTAINING_RECORD(entry, alloc_info, list_entry); 124 125 DbgPrint(" * Block: 0x%p Size: %lu allocated from %s:%d\n", get_ptr_from_base(info), info->size, info->file, info->line); 126 127 ptr = (void *)(info + 1); 128 if (!check_redzone_region(ptr, REDZONE_LEFT, &ptr)) 129 { 130 DbgPrint(" !!! Detected buffer underflow !!!\n"); 131 } 132 133 ptr = (void *)((UINT_PTR)ptr + info->size); 134 if (!check_redzone_region(ptr, REDZONE_RIGHT, NULL)) 135 { 136 DbgPrint(" !!! Detected buffer overflow !!!\n"); 137 } 138 139 entry = entry->Flink; 140 } 141 } 142 143 void * 144 cmd_alloc_dbg(size_t size, const char *file, int line) 145 { 146 void *newptr = NULL; 147 148 newptr = malloc(calculate_size_with_redzone(size)); 149 if (newptr != NULL) 150 { 151 allocations++; 152 allocated_memory += size; 153 add_mem_to_list(newptr); 154 newptr = write_redzone(newptr, size, file, line); 155 } 156 157 return newptr; 158 } 159 160 void * 161 cmd_realloc_dbg(void *ptr, size_t size, const char *file, int line) 162 { 163 size_t prev_size; 164 void *newptr = NULL; 165 166 if (ptr == NULL) 167 return cmd_alloc_dbg(size, file, line); 168 if (size == 0) 169 { 170 cmd_free_dbg(ptr, file, line); 171 return NULL; 172 } 173 174 ptr = get_base_ptr(ptr); 175 prev_size = ((palloc_info)ptr)->size; 176 check_redzone(ptr, file, line); 177 178 del_mem_from_list(ptr); 179 newptr = realloc(ptr, calculate_size_with_redzone(size)); 180 if (newptr != NULL) 181 { 182 allocated_memory += size - prev_size; 183 add_mem_to_list(newptr); 184 newptr = write_redzone(newptr, size, file, line); 185 } 186 else 187 add_mem_to_list(ptr); 188 189 return newptr; 190 } 191 192 void 193 cmd_free_dbg(void *ptr, const char *file, int line) 194 { 195 if (ptr != NULL) 196 { 197 ptr = get_base_ptr(ptr); 198 check_redzone(ptr, file, line); 199 allocations--; 200 allocated_memory -= ((palloc_info)ptr)->size; 201 del_mem_from_list(ptr); 202 } 203 204 free(ptr); 205 } 206 207 TCHAR * 208 cmd_dup_dbg(const TCHAR *str, const char *file, int line) 209 { 210 TCHAR *ptr = NULL; 211 212 if (str != NULL) 213 { 214 ptr = (TCHAR *)cmd_alloc_dbg((_tcslen(str) + 1) * sizeof(TCHAR), file, line); 215 if (ptr != NULL) 216 { 217 _tcscpy(ptr, str); 218 } 219 } 220 221 return ptr; 222 } 223 224 void 225 cmd_checkbuffer_dbg(void *ptr, const char *file, int line) 226 { 227 if (ptr != NULL) 228 { 229 ptr = get_base_ptr(ptr); 230 check_redzone(ptr, file, line); 231 } 232 } 233 234 void 235 cmd_exit(int code) 236 { 237 if (allocations != 0 || allocated_memory != 0) 238 { 239 DbgPrint("CMD: Leaking %lu bytes of memory in %lu blocks! Exit code: %d\n", allocated_memory, allocations, code); 240 if (allocations != 0) 241 dump_mem_list(); 242 } 243 244 ExitProcess(code); 245 } 246 247 #endif /* _DEBUG_MEM */ 248