Atlas - SDL_test_memory.c

Home / ext / SDL2 / src / test Lines: 6 | Size: 7834 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)]
[FILE BEGIN]
1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2018 Sam Lantinga <[email protected]> 4 5 This software is provided 'as-is', without any express or implied 6 warranty. In no event will the authors be held liable for any damages 7 arising from the use of this software. 8 9 Permission is granted to anyone to use this software for any purpose, 10 including commercial applications, and to alter it and redistribute it 11 freely, subject to the following restrictions: 12 13 1. The origin of this software must not be misrepresented; you must not 14 claim that you wrote the original software. If you use this software 15 in a product, an acknowledgment in the product documentation would be 16 appreciated but is not required. 17 2. Altered source versions must be plainly marked as such, and must not be 18 misrepresented as being the original software. 19 3. This notice may not be removed or altered from any source distribution. 20*/ 21#include "SDL_config.h" 22#include "SDL_assert.h" 23#include "SDL_stdinc.h" 24#include "SDL_log.h" 25#include "SDL_test_crc32.h" 26#include "SDL_test_memory.h" 27 28#ifdef HAVE_LIBUNWIND_H 29#include <libunwind.h> 30#endif 31 32/* This is a simple tracking allocator to demonstrate the use of SDL's 33 memory allocation replacement functionality. 34 35 It gets slow with large numbers of allocations and shouldn't be used 36 for production code. 37*/ 38 39typedef struct SDL_tracked_allocation 40{ 41 void *mem; 42 size_t size; 43 Uint64 stack[10]; 44 char stack_names[10][256]; 45 struct SDL_tracked_allocation *next; 46} SDL_tracked_allocation; 47 48static SDLTest_Crc32Context s_crc32_context; 49static SDL_malloc_func SDL_malloc_orig = NULL; 50static SDL_calloc_func SDL_calloc_orig = NULL; 51static SDL_realloc_func SDL_realloc_orig = NULL; 52static SDL_free_func SDL_free_orig = NULL; 53static int s_previous_allocations = 0; 54static SDL_tracked_allocation *s_tracked_allocations[256]; 55 56static unsigned int get_allocation_bucket(void *mem) 57{ 58 CrcUint32 crc_value; 59 unsigned int index; 60 SDLTest_Crc32Calc(&s_crc32_context, (CrcUint8 *)&mem, sizeof(mem), &crc_value); 61 index = (crc_value & (SDL_arraysize(s_tracked_allocations) - 1)); 62 return index; 63} 64 65static SDL_bool SDL_IsAllocationTracked(void *mem) 66{ 67 SDL_tracked_allocation *entry; 68 int index = get_allocation_bucket(mem); 69 for (entry = s_tracked_allocations[index]; entry; entry = entry->next) { 70 if (mem == entry->mem) { 71 return SDL_TRUE; 72 } 73 } 74 return SDL_FALSE; 75} 76 77static void SDL_TrackAllocation(void *mem, size_t size) 78{ 79 SDL_tracked_allocation *entry; 80 int index = get_allocation_bucket(mem); 81 82 if (SDL_IsAllocationTracked(mem)) { 83 return; 84 } 85 entry = (SDL_tracked_allocation *)SDL_malloc_orig(sizeof(*entry)); 86 if (!entry) { 87 return; 88 } 89 entry->mem = mem; 90 entry->size = size; 91 92 /* Generate the stack trace for the allocation */ 93 SDL_zero(entry->stack); 94#ifdef HAVE_LIBUNWIND_H 95 { 96 int stack_index; 97 unw_cursor_t cursor; 98 unw_context_t context; 99 100 unw_getcontext(&context); 101 unw_init_local(&cursor, &context); 102 103 stack_index = 0; 104 while (unw_step(&cursor) > 0) { 105 unw_word_t offset, pc; 106 char sym[256]; 107 108 unw_get_reg(&cursor, UNW_REG_IP, &pc); 109 entry->stack[stack_index] = pc; 110 111 if (unw_get_proc_name(&cursor, sym, sizeof(sym), &offset) == 0) { 112 snprintf(entry->stack_names[stack_index], sizeof(entry->stack_names[stack_index]), "%s+0x%llx", sym, offset); 113 } 114 ++stack_index; 115 116 if (stack_index == SDL_arraysize(entry->stack)) { 117 break; 118 } 119 } 120 } 121#endif /* HAVE_LIBUNWIND_H */ 122 123 entry->next = s_tracked_allocations[index]; 124 s_tracked_allocations[index] = entry; 125} 126 127static void SDL_UntrackAllocation(void *mem) 128{ 129 SDL_tracked_allocation *entry, *prev; 130 int index = get_allocation_bucket(mem); 131 132 prev = NULL; 133 for (entry = s_tracked_allocations[index]; entry; entry = entry->next) { 134 if (mem == entry->mem) { 135 if (prev) { 136 prev->next = entry->next; 137 } else { 138 s_tracked_allocations[index] = entry->next; 139 } 140 SDL_free_orig(entry); 141 return; 142 } 143 prev = entry; 144 } 145} 146 147static void * SDLCALL SDLTest_TrackedMalloc(size_t size) 148{ 149 void *mem; 150 151 mem = SDL_malloc_orig(size); 152 if (mem) { 153 SDL_TrackAllocation(mem, size); 154 } 155 return mem; 156} 157 158static void * SDLCALL SDLTest_TrackedCalloc(size_t nmemb, size_t size) 159{ 160 void *mem; 161 162 mem = SDL_calloc_orig(nmemb, size); 163 if (mem) { 164 SDL_TrackAllocation(mem, nmemb * size); 165 } 166 return mem; 167} 168 169static void * SDLCALL SDLTest_TrackedRealloc(void *ptr, size_t size) 170{ 171 void *mem; 172 173 SDL_assert(!ptr || SDL_IsAllocationTracked(ptr)); 174 mem = SDL_realloc_orig(ptr, size); 175 if (mem && mem != ptr) { 176 if (ptr) { 177 SDL_UntrackAllocation(ptr); 178 } 179 SDL_TrackAllocation(mem, size); 180 } 181 return mem; 182} 183 184static void SDLCALL SDLTest_TrackedFree(void *ptr) 185{ 186 if (!ptr) { 187 return; 188 } 189 190 if (!s_previous_allocations) { 191 SDL_assert(SDL_IsAllocationTracked(ptr)); 192 } 193 SDL_UntrackAllocation(ptr); 194 SDL_free_orig(ptr); 195} 196 197int SDLTest_TrackAllocations() 198{ 199 if (SDL_malloc_orig) { 200 return 0; 201 } 202 203 SDLTest_Crc32Init(&s_crc32_context); 204 205 s_previous_allocations = SDL_GetNumAllocations(); 206 if (s_previous_allocations != 0) { 207 SDL_Log("SDLTest_TrackAllocations(): There are %d previous allocations, disabling free() validation", s_previous_allocations); 208 } 209 210 SDL_GetMemoryFunctions(&SDL_malloc_orig, 211 &SDL_calloc_orig, 212 &SDL_realloc_orig, 213 &SDL_free_orig); 214 215 SDL_SetMemoryFunctions(SDLTest_TrackedMalloc, 216 SDLTest_TrackedCalloc, 217 SDLTest_TrackedRealloc, 218 SDLTest_TrackedFree); 219 return 0; 220} 221 222void SDLTest_LogAllocations() 223{ 224 char *message = NULL; 225 size_t message_size = 0; 226 char line[128], *tmp; 227 SDL_tracked_allocation *entry; 228 int index, count, stack_index; 229 Uint64 total_allocated; 230 231 if (!SDL_malloc_orig) { 232 return; 233 } 234 235#define ADD_LINE() \ 236 message_size += (SDL_strlen(line) + 1); \ 237 tmp = (char *)SDL_realloc_orig(message, message_size); \ 238 if (!tmp) { \ 239 return; \ 240 } \ 241 message = tmp; \ 242 SDL_strlcat(message, line, message_size) 243 244 SDL_strlcpy(line, "Memory allocations:\n", sizeof(line)); 245 ADD_LINE(); 246 SDL_strlcpy(line, "Expect 2 allocations from within SDL_GetErrBuf()\n", sizeof(line)); 247 ADD_LINE(); 248 249 count = 0; 250 total_allocated = 0; 251 for (index = 0; index < SDL_arraysize(s_tracked_allocations); ++index) { 252 for (entry = s_tracked_allocations[index]; entry; entry = entry->next) { 253 SDL_snprintf(line, sizeof(line), "Allocation %d: %d bytes\n", count, (int)entry->size); 254 ADD_LINE(); 255 /* Start at stack index 1 to skip our tracking functions */ 256 for (stack_index = 1; stack_index < SDL_arraysize(entry->stack); ++stack_index) { 257 if (!entry->stack[stack_index]) { 258 break; 259 } 260 SDL_snprintf(line, sizeof(line), "\t0x%"SDL_PRIx64": %s\n", entry->stack[stack_index], entry->stack_names[stack_index]); 261 ADD_LINE(); 262 } 263 total_allocated += entry->size; 264 ++count; 265 } 266 } 267 SDL_snprintf(line, sizeof(line), "Total: %.2f Kb in %d allocations\n", (float)total_allocated / 1024, count); 268 ADD_LINE(); 269#undef ADD_LINE 270 271 SDL_Log("%s", message); 272} 273 274/* vi: set ts=4 sw=4 expandtab: */ 275
[FILE END]
(C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.