2013-05-01 14:52:55 +02:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include "config.h"
|
|
|
|
#endif
|
|
|
|
|
2014-02-08 18:03:38 +01:00
|
|
|
#ifdef USE_DEBUG_BACKTRACE
|
|
|
|
#include <execinfo.h>
|
|
|
|
#endif
|
|
|
|
|
2016-08-22 16:59:55 +02:00
|
|
|
#include "logging.h"
|
|
|
|
#include "error.h"
|
2013-05-01 14:52:55 +02:00
|
|
|
|
|
|
|
#define BACKTRACE_BUFFER 256
|
|
|
|
|
|
|
|
/* Memory block */
|
|
|
|
struct capwap_memory_block {
|
|
|
|
void* item;
|
|
|
|
size_t size;
|
|
|
|
const char* file;
|
|
|
|
int line;
|
2014-02-08 18:03:38 +01:00
|
|
|
#ifdef USE_DEBUG_BACKTRACE
|
2013-05-01 14:52:55 +02:00
|
|
|
void* backtrace[BACKTRACE_BUFFER];
|
|
|
|
int backtrace_count;
|
2014-02-08 18:03:38 +01:00
|
|
|
#endif
|
2013-05-01 14:52:55 +02:00
|
|
|
struct capwap_memory_block* next;
|
|
|
|
};
|
|
|
|
|
|
|
|
static struct capwap_memory_block* g_memoryblocks = NULL;
|
|
|
|
|
|
|
|
/* Alloc memory block */
|
|
|
|
void* capwap_alloc_debug(size_t size, const char* file, const int line) {
|
|
|
|
struct capwap_memory_block* block;
|
|
|
|
|
|
|
|
/* Request size > 0 */
|
|
|
|
if (size <= 0) {
|
2016-03-30 14:47:57 +02:00
|
|
|
log_printf(LOG_DEBUG, "%s(%d): Invalid memory size %zu", file, line, size);
|
2013-08-11 23:04:24 +02:00
|
|
|
exit(CAPWAP_ASSERT_CONDITION);
|
2013-05-01 14:52:55 +02:00
|
|
|
}
|
|
|
|
|
2014-09-10 21:58:23 +02:00
|
|
|
/* Alloc block with memory block */
|
|
|
|
block = (struct capwap_memory_block*)malloc(sizeof(struct capwap_memory_block) + size);
|
2013-05-01 14:52:55 +02:00
|
|
|
if (!block) {
|
2016-03-30 14:47:57 +02:00
|
|
|
log_printf(LOG_DEBUG, "Out of memory %s(%d)", file, line);
|
2013-08-11 23:04:24 +02:00
|
|
|
exit(CAPWAP_OUT_OF_MEMORY);
|
2013-05-01 14:52:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Info memory block */
|
|
|
|
block->item = (void*)(((char*)block) + sizeof(struct capwap_memory_block));
|
|
|
|
block->size = size;
|
|
|
|
block->file = file;
|
|
|
|
block->line = line;
|
2014-02-08 18:03:38 +01:00
|
|
|
#ifdef USE_DEBUG_BACKTRACE
|
2013-05-01 14:52:55 +02:00
|
|
|
block->backtrace_count = backtrace(block->backtrace, BACKTRACE_BUFFER);
|
2014-02-08 18:03:38 +01:00
|
|
|
#endif
|
2013-05-01 14:52:55 +02:00
|
|
|
block->next = g_memoryblocks;
|
|
|
|
|
|
|
|
g_memoryblocks = block;
|
|
|
|
|
|
|
|
return block->item;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Free memory block */
|
|
|
|
void capwap_free_debug(void* p, const char* file, const int line) {
|
|
|
|
struct capwap_memory_block* block;
|
|
|
|
struct capwap_memory_block* findblock;
|
|
|
|
struct capwap_memory_block* prevblock;
|
|
|
|
|
|
|
|
if (!p) {
|
2016-03-30 14:47:57 +02:00
|
|
|
log_printf(LOG_DEBUG, "%s(%d): Free NULL pointer", file, line);
|
2015-01-06 22:56:10 +01:00
|
|
|
exit(CAPWAP_ASSERT_CONDITION);
|
2013-05-01 14:52:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Memory block */
|
|
|
|
if ((size_t)p <= sizeof(struct capwap_memory_block)) {
|
2016-03-30 14:47:57 +02:00
|
|
|
log_printf(LOG_DEBUG, "%s(%d): Invalid pointer", file, line);
|
2015-01-06 22:56:10 +01:00
|
|
|
exit(CAPWAP_ASSERT_CONDITION);
|
2013-05-01 14:52:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
block = (struct capwap_memory_block*)((char*)p - sizeof(struct capwap_memory_block));
|
|
|
|
if (block->item != p) {
|
2016-03-30 14:47:57 +02:00
|
|
|
log_printf(LOG_DEBUG, "%s(%d): Invalid pointer", file, line);
|
2015-01-06 22:56:10 +01:00
|
|
|
exit(CAPWAP_ASSERT_CONDITION);
|
2013-05-01 14:52:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Find memory block */
|
|
|
|
prevblock = NULL;
|
|
|
|
findblock = g_memoryblocks;
|
|
|
|
while (findblock != NULL) {
|
|
|
|
if (findblock == block) {
|
|
|
|
if (!prevblock) {
|
|
|
|
g_memoryblocks = block->next;
|
|
|
|
} else {
|
|
|
|
prevblock->next = block->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Invalidate block */
|
|
|
|
memset(block, 0, sizeof(struct capwap_memory_block));
|
|
|
|
free(block);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Next */
|
|
|
|
prevblock = findblock;
|
|
|
|
findblock = findblock->next;
|
|
|
|
}
|
|
|
|
|
2016-03-30 14:47:57 +02:00
|
|
|
log_printf(LOG_DEBUG, "%s(%d): Unable to find memory block", file, line);
|
2013-05-01 14:52:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Dump memory alloced */
|
|
|
|
void capwap_dump_memory(void) {
|
2014-02-08 18:03:38 +01:00
|
|
|
#ifdef USE_DEBUG_BACKTRACE
|
2013-05-01 14:52:55 +02:00
|
|
|
char** backtrace_functions;
|
2014-02-08 18:03:38 +01:00
|
|
|
#endif
|
2013-05-01 14:52:55 +02:00
|
|
|
struct capwap_memory_block* findblock;
|
|
|
|
|
|
|
|
findblock = g_memoryblocks;
|
|
|
|
while (findblock != NULL) {
|
2016-03-30 14:47:57 +02:00
|
|
|
log_printf(LOG_DEBUG, "%s(%d): block at %p, %zu bytes long",
|
2016-03-30 14:30:27 +02:00
|
|
|
findblock->file, findblock->line, findblock->item, findblock->size);
|
2013-05-01 14:52:55 +02:00
|
|
|
|
2014-02-08 18:03:38 +01:00
|
|
|
#ifdef USE_DEBUG_BACKTRACE
|
2013-05-01 14:52:55 +02:00
|
|
|
backtrace_functions = backtrace_symbols(findblock->backtrace, findblock->backtrace_count);
|
|
|
|
if (backtrace_functions) {
|
|
|
|
int j;
|
|
|
|
|
|
|
|
/* Skipping capwap_alloc_debug function print out */
|
|
|
|
for (j = 1; j < findblock->backtrace_count; j++) {
|
2016-03-30 14:47:57 +02:00
|
|
|
log_printf(LOG_DEBUG, "\t%s", backtrace_functions[j]);
|
2013-05-01 14:52:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
free(backtrace_functions);
|
|
|
|
}
|
2014-02-08 18:03:38 +01:00
|
|
|
#endif
|
2013-05-01 14:52:55 +02:00
|
|
|
|
|
|
|
/* Next */
|
|
|
|
findblock = findblock->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check if all memory is free */
|
|
|
|
int capwap_check_memory_leak(int verbose) {
|
|
|
|
if ((g_memoryblocks != NULL) && (verbose != 0)) {
|
2016-03-30 14:47:57 +02:00
|
|
|
log_printf(LOG_DEBUG, "*** Detected memory leaks ! ***");
|
2013-05-01 14:52:55 +02:00
|
|
|
capwap_dump_memory();
|
2016-03-30 14:47:57 +02:00
|
|
|
log_printf(LOG_DEBUG, "*******************************");
|
2013-05-01 14:52:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return ((g_memoryblocks != NULL) ? 1 : 0);
|
|
|
|
}
|
2013-11-10 22:07:55 +01:00
|
|
|
|
|
|
|
/* Backtrace call stack */
|
2014-02-08 18:03:38 +01:00
|
|
|
#ifdef USE_DEBUG_BACKTRACE
|
2013-11-10 22:07:55 +01:00
|
|
|
void capwap_backtrace_callstack(void) {
|
|
|
|
int i;
|
|
|
|
int count;
|
|
|
|
char** functions;
|
|
|
|
void* buffer[BACKTRACE_BUFFER];
|
|
|
|
|
|
|
|
/* */
|
|
|
|
count = backtrace(buffer, BACKTRACE_BUFFER);
|
|
|
|
if (count) {
|
|
|
|
functions = backtrace_symbols(buffer, count);
|
|
|
|
if (functions) {
|
|
|
|
|
|
|
|
/* Skipping capwap_backtrace_callstack function print out */
|
|
|
|
for (i = 1; i < count; i++) {
|
2016-03-30 14:47:57 +02:00
|
|
|
log_printf(LOG_DEBUG, "\t%s", functions[i]);
|
2013-11-10 22:07:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
free(functions);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-02-08 18:03:38 +01:00
|
|
|
#endif
|