#include "guf_common.h" #include "guf_alloc.h" #include "math.h" typedef struct guf_alloc_tracker { FILE *log, *err_log; size_t alloc_count, realloc_count, free_count; ptrdiff_t allocated_bytes; uint32_t id; } guf_alloc_tracker; static bool guf_track_alloc(guf_alloc_tracker *t, ptrdiff_t size) { GUF_ASSERT(t); GUF_ASSERT(size >= 0); bool success = true; if (t->err_log && t->alloc_count == SIZE_MAX) { fprintf(t->err_log, "guf_alloc_track (id %" PRIu32 ") WARNING: alloc_count overflow\n", t->id); //success = false; } t->alloc_count = guf_add_saturated_size_t(t->alloc_count, 1); if (guf_add_is_overflow_ptrdiff(t->allocated_bytes, size)) { if (t->err_log) { fprintf(t->err_log, "guf_alloc_track (id %" PRIu32 ") ERROR: allocated_byte overflow\n", t->id); } success = false; } t->allocated_bytes = guf_add_saturated_ptrdiff(t->allocated_bytes, size); if (t->allocated_bytes < 0) { if (t->err_log) { fprintf(t->err_log, "guf_alloc_track (id %" PRIu32 ") ERROR: allocated_bytes < 0\n", t->id); } success = false; } if (t->log) { fprintf(t->log, "guf_alloc_track (id %" PRIu32 "): alloc (%td bytes) %s\n", t->id, size, success ? "SUCCESS" : "FAILURE"); } return success; } static 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 (t->err_log && t->realloc_count == SIZE_MAX) { fprintf(t->err_log, "guf_realloc_track (id %" PRIu32 ") WARNING: realloc_count overflow\n"); //success = false; } t->realloc_count = guf_add_saturated_size_t(t->realloc_count, 1); if (old_size < 0 || new_size < 0) { if (t->err_log) { fprintf(t->err_log, "guf_realloc_track (id %" PRIu32 ") ERROR: old_size < 0 or new_size < 0\n"); } success = false; } t->allocated_bytes = guf_sub_saturated_ptrdiff(t->allocated_bytes, old_size); if (t->allocated_bytes < 0) { success = false; fprintf(t->err_log, "guf_realloc_track (id %" PRIu32 ") ERROR: allocated_bytes < 0 after subtracting old_size\n", t->id); } if (guf_add_is_overflow_ptrdiff(t->allocated_bytes, new_size)) { success = false; if (t->err_log) { fprintf(t->err_log, "guf_realloc_track (id %" PRIu32 ") ERROR: allocated_bytes overflow \n"); } } t->allocated_bytes = guf_add_saturated_ptrdiff(t->allocated_bytes, new_size); if (t->allocated_bytes < 0) { success = false; fprintf(t->err_log, "guf_realloc_track (id %" PRIu32 ") ERROR: allocated_bytes < 0 after adding new_size\n", t->id); } if (t->log) { fprintf(t->log, "guf_realloc_track (id %" PRIu32 "): realloc (from %td to %td bytes) %s", t->id, old_size, new_size, (success ? "SUCCESS" : "FAILURE")); } return success; } static bool guf_track_free(guf_alloc_tracker *t, ptrdiff_t size) { GUF_ASSERT(t); GUF_ASSERT(size >= 0); if (t->err_log && t->free_count == SIZE_MAX) { fprintf(t->err_log, "guf_track_free (id %" PRIu32 ") WARNING: free_count overflow\n"); } bool success = true; if (size < 0) { success = false; if (t->err_log) { fprintf(t->err_log, "guf_track_free (id %" PRIu32 ") ERROR: size < 0\n"); } } if (t->allocated_bytes < size) { success = false; if (t->err_log) { fprintf(t->err_log, "guf_track_free (id %" PRIu32 ") ERROR: freed more bytes than allocated\n"); } } t->allocated_bytes = guf_sub_saturated_ptrdiff(t->allocated_bytes, size); return success; }