Skip to content

Commit

Permalink
os_malloc: Add optional memory allocation tracing (#35)
Browse files Browse the repository at this point in the history
  • Loading branch information
TheSomeMan authored Sep 10, 2023
1 parent 9968657 commit 66324a7
Show file tree
Hide file tree
Showing 2 changed files with 219 additions and 0 deletions.
46 changes: 46 additions & 0 deletions include/os_malloc.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,31 @@
#define OS_MALLOC_H

#include <stdbool.h>
#include <stdint.h>
#include <stddef.h>
#include "attribs.h"

#ifdef __cplusplus
extern "C" {
#endif

#define OS_MALLOC_TRACE 0

/**
* This is a wrap for malloc - it allocates a block of memory of size 'size' bytes.
* @param size - the size the memory block
* @return pointer to the allocated memory block or NULL.
*/
ATTR_MALLOC
ATTR_MALLOC_SIZE(1)
#if OS_MALLOC_TRACE
void*
os_malloc_internal(const size_t size, const char* const p_file, const int32_t line);
#define os_malloc(size) os_malloc_internal(size, __FILE__, __LINE__)
#else
void*
os_malloc(const size_t size);
#endif

/**
* This is a wrap for calloc - it allocates memory block for an array of 'nmemb' elements,
Expand All @@ -35,8 +44,14 @@ os_malloc(const size_t size);
*/
ATTR_MALLOC
ATTR_CALLOC_SIZE(1, 2)
#if OS_MALLOC_TRACE
void*
os_calloc_internal(const size_t nmemb, const size_t size, const char* const p_file, const int32_t line);
#define os_calloc(nmemb, size) os_calloc_internal(nmemb, size, __FILE__, __LINE__)
#else
void*
os_calloc(const size_t nmemb, const size_t size);
#endif

/**
* @brief This is a safer wrap for realloc,
Expand All @@ -49,8 +64,14 @@ os_calloc(const size_t nmemb, const size_t size);
* @return true if the reallocation was successful.
*/
ATTR_WARN_UNUSED_RESULT
#if OS_MALLOC_TRACE
bool
os_realloc_safe_internal(void** const p_ptr, const size_t size, const char* const p_file, const int32_t line);
#define os_realloc_safe(p_ptr, size) os_realloc_safe_internal(p_ptr, size, __FILE__, __LINE__)
#else
bool
os_realloc_safe(void** const p_ptr, const size_t size);
#endif

/**
* @brief This is a safer wrap for realloc,
Expand All @@ -65,26 +86,51 @@ os_realloc_safe(void** const p_ptr, const size_t size);
*/
ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1)
#if OS_MALLOC_TRACE
bool
os_realloc_safe_and_clean_internal(void** const p_ptr, const size_t size, const char* const p_file, const int32_t line);
#define os_realloc_safe_and_clean(p_ptr, size) os_realloc_safe_and_clean_internal(p_ptr, size, __FILE__, __LINE__)
#else
bool
os_realloc_safe_and_clean(void** const p_ptr, const size_t size);
#endif

/**
* This is a wrap for 'free' - it deallocates a block of memory
* @note This function should not be used, use macro @ref os_free instead.
* @param ptr - pointer to the memory block
*/
#if OS_MALLOC_TRACE
void
os_free_internal(void* ptr, const char* const p_file, const int32_t line);
#else
void
os_free_internal(void* ptr);
#endif

/**
* @brief os_free - is a wrap for 'free' which automatically sets pointer to NULL after the memory freeing.
*/
#if OS_MALLOC_TRACE
#define os_free(ptr) \
do \
{ \
os_free_internal((void*)(ptr), __FILE__, __LINE__); \
ptr = NULL; \
} while (0)
#else
#define os_free(ptr) \
do \
{ \
os_free_internal((void*)(ptr)); \
ptr = NULL; \
} while (0)
#endif

#if OS_MALLOC_TRACE
void
os_malloc_trace_dump(void);
#endif

#ifdef __cplusplus
}
Expand Down
173 changes: 173 additions & 0 deletions src/os_malloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,90 @@
#include "os_malloc.h"
#include <stdlib.h>

#if OS_MALLOC_TRACE
#include <string.h>
#include "sys/queue.h"
#include "os_mutex.h"
#define LOG_LOCAL_LEVEL LOG_LEVEL_INFO
#include "log.h"
static const char* TAG = "MEM_TRACE";

typedef struct os_malloc_trace_info_t
{
void* p_mem;
size_t size;
TAILQ_ENTRY(os_malloc_trace_info_t) list;
const char* p_file;
int32_t line;
uint32_t timestamp;
} os_malloc_trace_info_t;

typedef TAILQ_HEAD(os_malloc_trace_list_t, os_malloc_trace_info_t) os_malloc_trace_list_t;

static os_malloc_trace_list_t g_os_malloc_trace_list;
static os_mutex_t g_p_os_malloc_trace_mutex;
static os_mutex_static_t g_os_malloc_trace_mutex_mem;
static int32_t g_os_malloc_trace_cnt;

static os_malloc_trace_list_t*
os_malloc_trace_mutex_lock(void)
{
if (NULL == g_p_os_malloc_trace_mutex)
{
g_p_os_malloc_trace_mutex = os_mutex_create_static(&g_os_malloc_trace_mutex_mem);
TAILQ_INIT(&g_os_malloc_trace_list);
g_os_malloc_trace_cnt = 0;
}
os_mutex_lock(g_p_os_malloc_trace_mutex);
return &g_os_malloc_trace_list;
}

static void
os_malloc_trace_mutex_unlock(os_malloc_trace_list_t** p_p_list)
{
os_mutex_unlock(g_p_os_malloc_trace_mutex);
*p_p_list = NULL;
}
#endif

#if OS_MALLOC_TRACE
ATTR_MALLOC
ATTR_MALLOC_SIZE(1)
void*
os_malloc_internal(const size_t size, const char* const p_file, const int32_t line)
{
return os_calloc_internal(1, size, p_file, line);
}
#else
ATTR_MALLOC
ATTR_MALLOC_SIZE(1)
void*
os_malloc(const size_t size)
{
return malloc(size);
}
#endif

#if OS_MALLOC_TRACE
void
os_free_internal(void* ptr, const char* const p_file, const int32_t line)
{
if (NULL == ptr)
{
return;
}

g_os_malloc_trace_cnt -= 1;

os_malloc_trace_info_t* const p_info = (os_malloc_trace_info_t*)((uint8_t*)ptr - sizeof(os_malloc_trace_info_t));
os_malloc_trace_list_t* p_list = os_malloc_trace_mutex_lock();
TAILQ_REMOVE(p_list, p_info, list);
os_malloc_trace_mutex_unlock(&p_list);
memset(p_info, 0, sizeof(*p_info) + p_info->size);

free(p_info);
}
#else
void
os_free_internal(void* ptr)
{
Expand All @@ -24,15 +100,71 @@ os_free_internal(void* ptr)
free(ptr);
}
}
#endif

#if OS_MALLOC_TRACE
ATTR_MALLOC
ATTR_CALLOC_SIZE(1, 2)
void*
os_calloc_internal(const size_t nmemb, const size_t size, const char* const p_file, const int32_t line)
{
void* const p_mem = calloc(1, sizeof(os_malloc_trace_info_t) + nmemb * size);
if (NULL == p_mem)
{
return NULL;
}

os_malloc_trace_info_t* const p_info = p_mem;
p_info->p_mem = p_mem;
p_info->size = size;
p_info->p_file = p_file;
p_info->line = line;
p_info->timestamp = xTaskGetTickCount();

g_os_malloc_trace_cnt += 1;

os_malloc_trace_list_t* p_list = os_malloc_trace_mutex_lock();
TAILQ_INSERT_TAIL(p_list, p_info, list);
os_malloc_trace_mutex_unlock(&p_list);
return (void*)((uint8_t*)p_mem + sizeof(os_malloc_trace_info_t));
}
#else
ATTR_MALLOC
ATTR_CALLOC_SIZE(1, 2)
void*
os_calloc(const size_t nmemb, const size_t size)
{
return calloc(nmemb, size);
}
#endif

#if OS_MALLOC_TRACE
ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1)
bool
os_realloc_safe_internal(void** const p_ptr, const size_t size, const char* const p_file, const int32_t line)
{
void* ptr = *p_ptr;
if (NULL == ptr)
{
return false;
}

const os_malloc_trace_info_t* const p_info_old
= (os_malloc_trace_info_t*)((uint8_t*)ptr - sizeof(os_malloc_trace_info_t));

void* p_new_ptr = os_malloc_internal(size, p_file, line);
if (NULL == p_new_ptr)
{
*p_ptr = NULL;
return false;
}
memcpy(p_new_ptr, ptr, ((size < p_info_old->size) ? size : p_info_old->size));
os_free_internal(ptr, p_file, line);
*p_ptr = p_new_ptr;
return true;
}
#else
ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1)
bool
Expand All @@ -47,7 +179,23 @@ os_realloc_safe(void** const p_ptr, const size_t size)
*p_ptr = p_new_ptr;
return true;
}
#endif

#if OS_MALLOC_TRACE
ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1)
bool
os_realloc_safe_and_clean_internal(void** const p_ptr, const size_t size, const char* const p_file, const int32_t line)
{
void* p_old_ptr = *p_ptr;
const bool res = os_realloc_safe_internal(p_ptr, size, p_file, line);
if (!res)
{
os_free_internal(p_old_ptr, p_file, line);
}
return res;
}
#else
ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1)
bool
Expand All @@ -63,3 +211,28 @@ os_realloc_safe_and_clean(void** const p_ptr, const size_t size)
*p_ptr = p_new_ptr;
return true;
}
#endif

#if OS_MALLOC_TRACE
void
os_malloc_trace_dump(void)
{
os_malloc_trace_list_t* p_list = os_malloc_trace_mutex_lock();
uint32_t cnt = 0;
LOG_INFO("Num blocks allocated: %d", g_os_malloc_trace_cnt);
os_malloc_trace_info_t* p_info;
TAILQ_FOREACH(p_info, p_list, list)
{
LOG_INFO(
"[%4u] %p: %u bytes (at %u), %s:%d",
cnt,
p_info->p_mem,
p_info->size,
p_info->timestamp,
p_info->p_file,
p_info->line);
cnt += 1;
}
os_malloc_trace_mutex_unlock(&p_list);
}
#endif

0 comments on commit 66324a7

Please sign in to comment.