213 lines
7.5 KiB
C
Executable File
213 lines
7.5 KiB
C
Executable File
#if defined(GUF_ALLOC_TRACKER_IMPL_STATIC)
|
|
#define GUF_ALLOC_TRACKER_KWRDS static inline
|
|
#else
|
|
#define GUF_ALLOC_TRACKER_KWRDS
|
|
#endif
|
|
|
|
#ifndef GUF_ALLOC_TRACKER_H
|
|
#define GUF_ALLOC_TRACKER_H
|
|
|
|
#include <stdio.h>
|
|
#include "guf_common.h"
|
|
#include "guf_str_view_type.h"
|
|
|
|
typedef struct guf_alloc_tracker {
|
|
FILE *log, *err_log;
|
|
const char *name;
|
|
size_t alloc_count, realloc_count, free_count;
|
|
ptrdiff_t allocated_bytes;
|
|
unsigned id;
|
|
bool enabled;
|
|
} guf_alloc_tracker;
|
|
|
|
#if !defined(GUF_ALLOC_TRACKER_IMPL_STATIC) && !defined(GUF_ALLOC_TRACKER_IMPL)
|
|
GUF_ALLOC_TRACKER_KWRDS guf_alloc_tracker *guf_alloc_tracker_init(guf_alloc_tracker *t, unsigned id, const char* name, FILE *log, FILE *err_log);
|
|
GUF_ALLOC_TRACKER_KWRDS guf_alloc_tracker guf_alloc_tracker_new(unsigned id, const char* name, FILE *log, FILE *err_log);
|
|
|
|
GUF_ALLOC_TRACKER_KWRDS void guf_alloc_tracker_print(const guf_alloc_tracker *t, FILE *f);
|
|
GUF_ALLOC_TRACKER_KWRDS bool guf_alloc_tracker_found_leak(const guf_alloc_tracker *t);
|
|
|
|
GUF_ALLOC_TRACKER_KWRDS bool guf_track_alloc(guf_alloc_tracker *t, ptrdiff_t size);
|
|
GUF_ALLOC_TRACKER_KWRDS bool guf_track_realloc(guf_alloc_tracker *t, ptrdiff_t old_size, ptrdiff_t new_size);
|
|
GUF_ALLOC_TRACKER_KWRDS bool guf_track_free(guf_alloc_tracker *t, ptrdiff_t size);
|
|
#endif
|
|
|
|
#if defined(GUF_ALLOC_TRACKER_IMPL_STATIC) || defined(GUF_ALLOC_TRACKER_IMPL)
|
|
|
|
#include "guf_alloc.h"
|
|
#define GUF_MATH_CKDINT_IMPL_STATIC
|
|
#include "guf_math_ckdint.h"
|
|
|
|
GUF_ALLOC_TRACKER_KWRDS guf_alloc_tracker *guf_alloc_tracker_init(guf_alloc_tracker *t, unsigned id, const char* name, FILE *log, FILE *err_log)
|
|
{
|
|
GUF_ASSERT_RELEASE(t);
|
|
t->log = log;
|
|
t->err_log = err_log;
|
|
t->alloc_count = t->realloc_count = t->free_count = 0;
|
|
t->allocated_bytes = 0;
|
|
t->name = name;
|
|
t->id = id;
|
|
t->enabled = true;
|
|
return t;
|
|
}
|
|
|
|
GUF_ALLOC_TRACKER_KWRDS guf_alloc_tracker guf_alloc_tracker_new(unsigned id, const char* name, FILE *log, FILE *err_log)
|
|
{
|
|
guf_alloc_tracker t;
|
|
guf_alloc_tracker_init(&t, id, name, log, err_log);
|
|
return t;
|
|
}
|
|
|
|
GUF_ALLOC_TRACKER_KWRDS bool guf_alloc_tracker_found_leak(const guf_alloc_tracker *t)
|
|
{
|
|
GUF_ASSERT_RELEASE(t);
|
|
return (t->allocated_bytes != 0) || (t->alloc_count != t->free_count);
|
|
}
|
|
|
|
|
|
GUF_ALLOC_TRACKER_KWRDS void guf_alloc_tracker_print(const guf_alloc_tracker *t, FILE *f)
|
|
{
|
|
GUF_ASSERT(t);
|
|
if (!f) {
|
|
f = stdout;
|
|
}
|
|
|
|
if (!t) {
|
|
fprintf(f, "guf_alloc_tracker_fprint: guf_alloc_tracker is NULL");
|
|
return;
|
|
}
|
|
|
|
fprintf(f,
|
|
"guf_alloc_tracker (name '%s' id = %u):\n"
|
|
"allocated_bytes: %td\n"
|
|
"alloc_count: %zu\n"
|
|
"realloc_count: %zu\n"
|
|
"free_count: %zu\n",
|
|
t->name ? t->name : "unnamed", t->id, t->allocated_bytes, t->alloc_count, t->realloc_count, t->free_count
|
|
);
|
|
|
|
}
|
|
|
|
GUF_ALLOC_TRACKER_KWRDS bool guf_track_alloc(guf_alloc_tracker *t, ptrdiff_t size)
|
|
{
|
|
GUF_ASSERT(t);
|
|
GUF_ASSERT(size >= 0);
|
|
|
|
bool success = true;
|
|
|
|
if (guf_saturating_add_size_t(t->alloc_count, 1, &t->alloc_count) != GUF_MATH_CKD_SUCCESS && t->err_log) {
|
|
fprintf(t->err_log, "WARNING in guf_track_alloc (name '%s' id %u): alloc_count reached SIZE_MAX\n", t->name ? t->name : "unnamed", t->id);
|
|
}
|
|
|
|
if (guf_saturating_add_ptrdiff_t(t->allocated_bytes, size, &t->allocated_bytes) != GUF_MATH_CKD_SUCCESS) {
|
|
if (t->err_log) {
|
|
fprintf(t->err_log, "ERROR in guf_track_alloc (name '%s' id %u): allocated_byte overflow\n", t->name ? t->name : "unnamed", t->id);
|
|
}
|
|
success = false;
|
|
}
|
|
|
|
if (t->allocated_bytes < 0) {
|
|
if (t->err_log) {
|
|
fprintf(t->err_log, "ERROR in guf_track_alloc (name '%s' id %u): allocated_bytes < 0\n", t->name ? t->name : "unnamed", t->id);
|
|
}
|
|
success = false;
|
|
}
|
|
|
|
if (t->log) {
|
|
fprintf(t->log, "guf_alloc_tracker (name '%s' id %u): alloc (%td bytes) %s\n", t->name ? t->name : "unnamed", t->id, size, success ? "SUCCESS" : "FAILURE");
|
|
}
|
|
return success;
|
|
}
|
|
|
|
|
|
GUF_ALLOC_TRACKER_KWRDS bool guf_track_realloc(guf_alloc_tracker *t, ptrdiff_t old_size, ptrdiff_t new_size)
|
|
{
|
|
GUF_ASSERT(t);
|
|
GUF_ASSERT(old_size >= 0 && new_size >= 0);
|
|
bool success = true;
|
|
|
|
if (guf_saturating_add_size_t(t->realloc_count, 1, &t->realloc_count) && t->err_log) {
|
|
fprintf(t->err_log, "WARNING in guf_track_realloc (name '%s' id %u): realloc_count reached SIZE_MAX\n", t->name ? t->name : "unnamed", t->id);
|
|
}
|
|
|
|
if (old_size < 0 || new_size < 0) {
|
|
success = false;
|
|
if (t->err_log) {
|
|
fprintf(t->err_log, "ERROR in guf_track_realloc (name '%s' id %u): old_size < 0 or new_size < 0\n", t->name ? t->name : "unnamed", t->id);
|
|
}
|
|
}
|
|
|
|
if (guf_saturating_sub_ptrdiff_t(t->allocated_bytes, old_size, &t->allocated_bytes)) {
|
|
success = false;
|
|
if (t->err_log) {
|
|
fprintf(t->err_log, "ERROR in guf_track_realloc (name '%s' id %u): allocated_bytes - old_size under/overflows\n", t->name ? t->name : "unnamed", t->id);
|
|
}
|
|
}
|
|
if (t->allocated_bytes < 0) {
|
|
success = false;
|
|
fprintf(t->err_log, "ERROR in guf_track_realloc (name '%s' id %u): allocated_bytes < 0 after subtracting old_size\n", t->name ? t->name : "unnamed", t->id);
|
|
}
|
|
|
|
if (guf_saturating_add_ptrdiff_t(t->allocated_bytes, new_size, &t->allocated_bytes)) {
|
|
success = false;
|
|
if (t->err_log) {
|
|
fprintf(t->err_log, "ERROR in guf_track_realloc (name '%s' id %u): allocated_bytes overflow \n", t->name ? t->name : "unnamed", t->id);
|
|
}
|
|
}
|
|
if (t->allocated_bytes < 0) {
|
|
success = false;
|
|
fprintf(t->err_log, "ERROR in guf_track_realloc (name '%s' id %u): allocated_bytes < 0 after adding new_size\n", t->name ? t->name : "unnamed", t->id);
|
|
}
|
|
|
|
if (t->log) {
|
|
fprintf(t->log, "guf_alloc_tracker (name '%s' id %u): realloc (from %td to %td bytes) %s\n", t->name ? t->name : "unnamed", t->id, old_size, new_size, (success ? "SUCCESS" : "FAILURE"));
|
|
}
|
|
|
|
return success;
|
|
}
|
|
|
|
GUF_ALLOC_TRACKER_KWRDS bool guf_track_free(guf_alloc_tracker *t, ptrdiff_t size)
|
|
{
|
|
GUF_ASSERT(t);
|
|
GUF_ASSERT(size >= 0);
|
|
bool success = true;
|
|
|
|
if (guf_saturating_add_size_t(t->free_count, 1, &t->free_count) && t->err_log) {
|
|
fprintf(t->err_log, "WARNING in guf_track_free (name '%s' id %u): free_count reached SIZE_MAX\n", t->name ? t->name : "unnamed", t->id);
|
|
}
|
|
|
|
if (size < 0) {
|
|
success = false;
|
|
if (t->err_log) {
|
|
fprintf(t->err_log, "ERROR in guf_track_free (name '%s' id %u): size < 0\n", t->name ? t->name : "unnamed", t->id);
|
|
}
|
|
}
|
|
|
|
if (t->allocated_bytes < size) {
|
|
success = false;
|
|
if (t->err_log) {
|
|
fprintf(t->err_log, "ERROR in guf_track_free (name '%s' id %u): freed more bytes than allocated\n", t->name ? t->name : "unnamed", t->id);
|
|
}
|
|
}
|
|
if (guf_saturating_sub_ptrdiff_t(t->allocated_bytes, size, &t->allocated_bytes)) {
|
|
success = false;
|
|
if (t->err_log) {
|
|
fprintf(t->err_log, "ERROR in guf_track_free (name '%s' id %u): allocated_bytes - size under/overflows\n", t->name ? t->name : "unnamed", t->id);
|
|
}
|
|
}
|
|
|
|
if (t->log) {
|
|
fprintf(t->log, "guf_alloc_tracker (name '%s' id %u): free (%td bytes) %s\n", t->name ? t->name : "unnamed", t->id, size, (success ? "SUCCESS" : "FAILURE"));
|
|
}
|
|
|
|
return success;
|
|
}
|
|
|
|
#endif /* End impl */
|
|
|
|
#endif /* End header-guard */
|
|
|
|
#undef GUF_ALLOC_TRACKER_KWRDS
|
|
#undef GUF_ALLOC_TRACKER_IMPL
|
|
#undef GUF_ALLOC_TRACKER_IMPL_STATIC
|