SDL 2.0
SDL_test_memory.c
Go to the documentation of this file.
1/*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
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
40{
41 void *mem;
42 size_t size;
44 char stack_names[10][256];
47
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
66{
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{
81
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, (unsigned long long)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
125}
126
127static void SDL_UntrackAllocation(void *mem)
128{
129 SDL_tracked_allocation *entry, *prev;
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 {
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
152 if (mem) {
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
174 mem = SDL_realloc_orig(ptr, size);
175 if (mem && mem != ptr) {
176 if (ptr) {
178 }
180 }
181 return mem;
182}
183
184static void SDLCALL SDLTest_TrackedFree(void *ptr)
185{
186 if (!ptr) {
187 return;
188 }
189
192 }
194 SDL_free_orig(ptr);
195}
196
198{
199 if (SDL_malloc_orig) {
200 return 0;
201 }
202
204
206 if (s_previous_allocations != 0) {
207 SDL_Log("SDLTest_TrackAllocations(): There are %d previous allocations, disabling free() validation", s_previous_allocations);
208 }
209
214
219 return 0;
220}
221
223{
224 char *message = NULL;
225 size_t message_size = 0;
226 char line[128], *tmp;
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;
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: */
#define SDL_assert(condition)
Definition: SDL_assert.h:169
#define SDL_strlcpy
#define SDL_GetNumAllocations
#define SDL_GetMemoryFunctions
#define SDL_Log
#define SDL_snprintf
#define SDL_SetMemoryFunctions
#define SDLCALL
Definition: SDL_internal.h:49
GLuint GLuint GLsizei count
Definition: SDL_opengl.h:1571
GLintptr offset
GLuint index
GLuint GLsizei const GLchar * message
GLsizeiptr size
#define SDL_zero(x)
Definition: SDL_stdinc.h:416
void *(* SDL_malloc_func)(size_t size)
Definition: SDL_stdinc.h:366
void(* SDL_free_func)(void *mem)
Definition: SDL_stdinc.h:369
SDL_bool
Definition: SDL_stdinc.h:162
@ SDL_TRUE
Definition: SDL_stdinc.h:164
@ SDL_FALSE
Definition: SDL_stdinc.h:163
#define SDL_arraysize(array)
Definition: SDL_stdinc.h:115
uint64_t Uint64
Definition: SDL_stdinc.h:216
void *(* SDL_calloc_func)(size_t nmemb, size_t size)
Definition: SDL_stdinc.h:367
#define SDL_PRIx64
Definition: SDL_stdinc.h:249
void *(* SDL_realloc_func)(void *mem, size_t size)
Definition: SDL_stdinc.h:368
int SDLTest_Crc32Calc(SDLTest_Crc32Context *crcContext, CrcUint8 *inBuf, CrcUint32 inLen, CrcUint32 *crc32)
calculate a crc32 from a data block
int SDLTest_Crc32Init(SDLTest_Crc32Context *crcContext)
Initialize the CRC context.
#define CrcUint8
#define CrcUint32
static void SDL_TrackAllocation(void *mem, size_t size)
#define ADD_LINE()
static SDLTest_Crc32Context s_crc32_context
static int s_previous_allocations
static SDL_calloc_func SDL_calloc_orig
static void SDLTest_TrackedFree(void *ptr)
int SDLTest_TrackAllocations()
Start tracking SDL memory allocations.
static SDL_realloc_func SDL_realloc_orig
static SDL_free_func SDL_free_orig
void SDLTest_LogAllocations()
Print a log of any outstanding allocations.
static void * SDLTest_TrackedMalloc(size_t size)
static void SDL_UntrackAllocation(void *mem)
static SDL_malloc_func SDL_malloc_orig
static void * SDLTest_TrackedCalloc(size_t nmemb, size_t size)
static SDL_tracked_allocation * s_tracked_allocations[256]
static unsigned int get_allocation_bucket(void *mem)
static SDL_bool SDL_IsAllocationTracked(void *mem)
static void * SDLTest_TrackedRealloc(void *ptr, size_t size)
#define NULL
Definition: begin_code.h:167
char stack_names[10][256]
struct SDL_tracked_allocation * next
SDL_Cursor * cursor
Definition: testwm2.c:40
static screen_context_t context
Definition: video.c:25