SDL  2.0
SDL_test_memory.c File Reference
#include "SDL_config.h"
#include "SDL_assert.h"
#include "SDL_stdinc.h"
#include "SDL_log.h"
#include "SDL_test_crc32.h"
#include "SDL_test_memory.h"
+ Include dependency graph for SDL_test_memory.c:

Go to the source code of this file.

Data Structures

struct  SDL_tracked_allocation
 

Macros

#define ADD_LINE()
 

Functions

static unsigned int get_allocation_bucket (void *mem)
 
static SDL_bool SDL_IsAllocationTracked (void *mem)
 
static void SDL_TrackAllocation (void *mem, size_t size)
 
static void SDL_UntrackAllocation (void *mem)
 
static voidSDLTest_TrackedMalloc (size_t size)
 
static voidSDLTest_TrackedCalloc (size_t nmemb, size_t size)
 
static voidSDLTest_TrackedRealloc (void *ptr, size_t size)
 
static void SDLTest_TrackedFree (void *ptr)
 
int SDLTest_TrackAllocations ()
 Start tracking SDL memory allocations. More...
 
void SDLTest_LogAllocations ()
 Print a log of any outstanding allocations. More...
 

Variables

static SDLTest_Crc32Context s_crc32_context
 
static SDL_malloc_func SDL_malloc_orig = NULL
 
static SDL_calloc_func SDL_calloc_orig = NULL
 
static SDL_realloc_func SDL_realloc_orig = NULL
 
static SDL_free_func SDL_free_orig = NULL
 
static int s_previous_allocations = 0
 
static SDL_tracked_allocations_tracked_allocations [256]
 

Macro Definition Documentation

◆ ADD_LINE

#define ADD_LINE ( )
Value:
message_size += (SDL_strlen(line) + 1); \
tmp = (char *)SDL_realloc_orig(message, message_size); \
if (!tmp) { \
return; \
} \
message = tmp; \
SDL_strlcat(message, line, message_size)
GLuint GLsizei const GLchar * message
static SDL_realloc_func SDL_realloc_orig
#define SDL_strlen

Referenced by SDLTest_LogAllocations().

Function Documentation

◆ get_allocation_bucket()

static unsigned int get_allocation_bucket ( void mem)
static

Definition at line 56 of file SDL_test_memory.c.

References CrcUint32, CrcUint8, SDL_arraysize, and SDLTest_Crc32Calc().

Referenced by SDL_IsAllocationTracked(), SDL_TrackAllocation(), and SDL_UntrackAllocation().

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 }
static SDL_tracked_allocation * s_tracked_allocations[256]
GLuint index
#define SDL_arraysize(array)
Definition: SDL_stdinc.h:93
#define CrcUint32
#define CrcUint8
int SDLTest_Crc32Calc(SDLTest_Crc32Context *crcContext, CrcUint8 *inBuf, CrcUint32 inLen, CrcUint32 *crc32)
calculate a crc32 from a data block
static SDLTest_Crc32Context s_crc32_context

◆ SDL_IsAllocationTracked()

static SDL_bool SDL_IsAllocationTracked ( void mem)
static

Definition at line 65 of file SDL_test_memory.c.

References get_allocation_bucket(), SDL_tracked_allocation::mem, SDL_tracked_allocation::next, SDL_FALSE, and SDL_TRUE.

Referenced by SDL_TrackAllocation(), SDLTest_TrackedFree(), and SDLTest_TrackedRealloc().

66 {
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 }
static unsigned int get_allocation_bucket(void *mem)
static SDL_tracked_allocation * s_tracked_allocations[256]
GLuint index
struct SDL_tracked_allocation * next

◆ SDL_TrackAllocation()

static void SDL_TrackAllocation ( void mem,
size_t  size 
)
static

Definition at line 77 of file SDL_test_memory.c.

References context, cursor, get_allocation_bucket(), SDL_tracked_allocation::mem, SDL_tracked_allocation::next, SDL_arraysize, SDL_IsAllocationTracked(), SDL_malloc_orig, SDL_zero, SDL_tracked_allocation::size, SDL_tracked_allocation::stack, and SDL_tracked_allocation::stack_names.

Referenced by SDLTest_TrackedCalloc(), SDLTest_TrackedMalloc(), and SDLTest_TrackedRealloc().

78 {
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 }
static unsigned int get_allocation_bucket(void *mem)
static screen_context_t context
Definition: video.c:25
GLintptr offset
static SDL_tracked_allocation * s_tracked_allocations[256]
#define SDL_zero(x)
Definition: SDL_stdinc.h:416
static SDL_bool SDL_IsAllocationTracked(void *mem)
GLsizeiptr size
GLuint index
SDL_Cursor * cursor
#define SDL_arraysize(array)
Definition: SDL_stdinc.h:93
static SDL_malloc_func SDL_malloc_orig
struct SDL_tracked_allocation * next
char stack_names[10][256]

◆ SDL_UntrackAllocation()

static void SDL_UntrackAllocation ( void mem)
static

Definition at line 127 of file SDL_test_memory.c.

References get_allocation_bucket(), SDL_tracked_allocation::mem, SDL_tracked_allocation::next, NULL, and SDL_free_orig.

Referenced by SDLTest_TrackedFree(), and SDLTest_TrackedRealloc().

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 }
static unsigned int get_allocation_bucket(void *mem)
static SDL_tracked_allocation * s_tracked_allocations[256]
GLuint index
static SDL_free_func SDL_free_orig
#define NULL
Definition: begin_code.h:164
struct SDL_tracked_allocation * next

◆ SDLTest_LogAllocations()

void SDLTest_LogAllocations ( )

Print a log of any outstanding allocations.

Note
This can be called after SDL_Quit()

Definition at line 222 of file SDL_test_memory.c.

References ADD_LINE, SDL_tracked_allocation::next, NULL, SDL_arraysize, SDL_Log, SDL_malloc_orig, SDL_PRIx64, SDL_snprintf, SDL_strlcpy, SDL_tracked_allocation::size, SDL_tracked_allocation::stack, and SDL_tracked_allocation::stack_names.

Referenced by SDLTest_CommonQuit().

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 }
#define SDL_strlcpy
GLuint GLsizei const GLchar * message
GLuint GLuint GLsizei count
Definition: SDL_opengl.h:1571
uint64_t Uint64
Definition: SDL_stdinc.h:194
static SDL_tracked_allocation * s_tracked_allocations[256]
#define ADD_LINE()
#define SDL_Log
GLuint index
#define SDL_PRIx64
Definition: SDL_stdinc.h:227
#define NULL
Definition: begin_code.h:164
#define SDL_snprintf
#define SDL_arraysize(array)
Definition: SDL_stdinc.h:93
static SDL_malloc_func SDL_malloc_orig
struct SDL_tracked_allocation * next
char stack_names[10][256]

◆ SDLTest_TrackAllocations()

int SDLTest_TrackAllocations ( )

Start tracking SDL memory allocations.

Note
This should be called before any other SDL functions for complete tracking coverage

Definition at line 197 of file SDL_test_memory.c.

References s_previous_allocations, SDL_calloc_orig, SDL_free_orig, SDL_GetMemoryFunctions, SDL_GetNumAllocations, SDL_Log, SDL_malloc_orig, SDL_realloc_orig, SDL_SetMemoryFunctions, SDLTest_Crc32Init(), SDLTest_TrackedCalloc(), SDLTest_TrackedFree(), SDLTest_TrackedMalloc(), and SDLTest_TrackedRealloc().

Referenced by SDLTest_CommonCreateState().

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 
213  &SDL_free_orig);
214 
219  return 0;
220 }
static int s_previous_allocations
static SDL_calloc_func SDL_calloc_orig
static void SDLTest_TrackedFree(void *ptr)
static void * SDLTest_TrackedMalloc(size_t size)
#define SDL_SetMemoryFunctions
static void * SDLTest_TrackedCalloc(size_t nmemb, size_t size)
static SDL_realloc_func SDL_realloc_orig
#define SDL_Log
#define SDL_GetMemoryFunctions
static SDL_free_func SDL_free_orig
int SDLTest_Crc32Init(SDLTest_Crc32Context *crcContext)
Initialize the CRC context.
static SDL_malloc_func SDL_malloc_orig
#define SDL_GetNumAllocations
static void * SDLTest_TrackedRealloc(void *ptr, size_t size)
static SDLTest_Crc32Context s_crc32_context

◆ SDLTest_TrackedCalloc()

static void* SDLTest_TrackedCalloc ( size_t  nmemb,
size_t  size 
)
static

Definition at line 158 of file SDL_test_memory.c.

References SDL_tracked_allocation::mem, SDL_calloc_orig, and SDL_TrackAllocation().

Referenced by SDLTest_TrackAllocations().

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 }
static SDL_calloc_func SDL_calloc_orig
static void SDL_TrackAllocation(void *mem, size_t size)
GLsizeiptr size

◆ SDLTest_TrackedFree()

static void SDLTest_TrackedFree ( void ptr)
static

Definition at line 184 of file SDL_test_memory.c.

References s_previous_allocations, SDL_assert, SDL_free_orig, SDL_IsAllocationTracked(), and SDL_UntrackAllocation().

Referenced by SDLTest_TrackAllocations().

185 {
186  if (!ptr) {
187  return;
188  }
189 
190  if (!s_previous_allocations) {
192  }
194  SDL_free_orig(ptr);
195 }
static int s_previous_allocations
static void SDL_UntrackAllocation(void *mem)
static SDL_bool SDL_IsAllocationTracked(void *mem)
static SDL_free_func SDL_free_orig
#define SDL_assert(condition)
Definition: SDL_assert.h:169

◆ SDLTest_TrackedMalloc()

static void* SDLTest_TrackedMalloc ( size_t  size)
static

Definition at line 147 of file SDL_test_memory.c.

References SDL_tracked_allocation::mem, SDL_malloc_orig, and SDL_TrackAllocation().

Referenced by SDLTest_TrackAllocations().

148 {
149  void *mem;
150 
151  mem = SDL_malloc_orig(size);
152  if (mem) {
154  }
155  return mem;
156 }
static void SDL_TrackAllocation(void *mem, size_t size)
GLsizeiptr size
static SDL_malloc_func SDL_malloc_orig

◆ SDLTest_TrackedRealloc()

static void* SDLTest_TrackedRealloc ( void ptr,
size_t  size 
)
static

Definition at line 169 of file SDL_test_memory.c.

References SDL_tracked_allocation::mem, SDL_assert, SDL_IsAllocationTracked(), SDL_realloc_orig, SDL_TrackAllocation(), and SDL_UntrackAllocation().

Referenced by SDLTest_TrackAllocations().

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) {
178  }
180  }
181  return mem;
182 }
static void SDL_TrackAllocation(void *mem, size_t size)
static SDL_realloc_func SDL_realloc_orig
static void SDL_UntrackAllocation(void *mem)
static SDL_bool SDL_IsAllocationTracked(void *mem)
GLsizeiptr size
#define SDL_assert(condition)
Definition: SDL_assert.h:169

Variable Documentation

◆ s_crc32_context

SDLTest_Crc32Context s_crc32_context
static

Definition at line 48 of file SDL_test_memory.c.

◆ s_previous_allocations

int s_previous_allocations = 0
static

Definition at line 53 of file SDL_test_memory.c.

Referenced by SDLTest_TrackAllocations(), and SDLTest_TrackedFree().

◆ s_tracked_allocations

SDL_tracked_allocation* s_tracked_allocations[256]
static

Definition at line 54 of file SDL_test_memory.c.

◆ SDL_calloc_orig

SDL_calloc_func SDL_calloc_orig = NULL
static

Definition at line 50 of file SDL_test_memory.c.

Referenced by SDLTest_TrackAllocations(), and SDLTest_TrackedCalloc().

◆ SDL_free_orig

SDL_free_func SDL_free_orig = NULL
static

◆ SDL_malloc_orig

◆ SDL_realloc_orig

SDL_realloc_func SDL_realloc_orig = NULL
static

Definition at line 51 of file SDL_test_memory.c.

Referenced by SDLTest_TrackAllocations(), and SDLTest_TrackedRealloc().