#define DBG 1 #define ARG 0 #include "frmwrk/inc/main.h" /* --------------------------------------------------------------------- */ #line 0 /* sma.c */ #include "include/list.h" #include "include/sma.h" #include #include /* macros ============================================================== */ #define SUP_SIZE (sizeof(int)) /* constants =========================================================== */ /* types =============================================================== */ /* structures ========================================================== */ typedef struct { void *start; void *real_start; void *end; void *real_end; size_t size; const char *file; int line; int reg; long checksum; } obj_s; /* private variables =================================================== */ static FILE *stream = NULL; static list_s *list = NULL; /* private functions =================================================== */ static void ALLOC_WARNING (const char *format, ...) { if (format) { if (stream) { va_list va; va_start (va, format); fprintf (stream, "\tWarning : "); vfprintf (stream, format, va); va_end (va); } } } static void test_flow (obj_s *obj) { if (obj) { char *tmp_p; for (tmp_p = obj->real_start; tmp_p < (char *)obj->start; tmp_p++) { if (*tmp_p) { ALLOC_WARNING ("Underflow a %p[%d]\n", (char *)obj->start, tmp_p-(char *)obj->start); } } for (tmp_p = obj->end; tmp_p < (char *)obj->real_end; tmp_p++) { if (*tmp_p) { ALLOC_WARNING ("Overflow a %p[%d]\n", (char *)obj->start, tmp_p-(char *)obj->start); } } } } static void print_obj (void *data, void *user_data) { obj_s *obj = (obj_s *)data; if (obj) { fprintf (stream, "|%s| %6d | %p | %6d | %30s |\n", (obj->reg)?" ":"*", obj->size, obj->start, obj->line, obj->file); } (void)user_data; } static void ALLOC_ERROR (const char *format, ...) { if (format) { if (stream) { va_list va; va_start (va, format); fprintf (stream, "\tError : "); vfprintf (stream, format, va); va_end (va); } exit (EXIT_FAILURE); } } static void ALLOC_INFO (const char *format, ...) { if (format) { if (stream) { va_list va; va_start (va, format); vfprintf (stream, format, va); va_end (va); } } } static long obj_checksum (obj_s *obj) { long cs = 0; (void)*obj; return cs; } static obj_s *obj_add (int reg, void *p, size_t size, const char *file, int line) { obj_s *obj = NULL; obj = malloc (sizeof (*obj)); if (obj) { if (reg) { obj->real_start = p; obj->start = (char *)p + SUP_SIZE; obj->end = (char *)p + size - SUP_SIZE; obj->real_end = (char *)p + size; obj->size = size - 2 * SUP_SIZE; } else { obj->real_start = NULL; obj->start = p; obj->end = (char *)p + size; obj->real_end = NULL; obj->size = size; } obj->reg = reg; obj->file = file; obj->line = line; obj->checksum = obj_checksum (obj); list = list_append (list, obj); } return obj; } static void obj_remove (obj_s *obj) { if (obj) { list = list_remove (list, obj); } } static obj_s *obj_exist (void *p) { obj_s *ret = NULL; if (p) { obj_s *obj = NULL; list_s *old = NULL; old = list = list_first (list); while (list) { obj = (obj_s *)list->data; if (obj && obj->start == p) { ret = obj; break; } list = list_next (list); } list = old; } return ret; } static void obj_foreach (void (*func) (void *, void *)) { list_foreach (list, func, NULL); } static void free_leaks (void *data, void *user_data) { obj_s *obj = (obj_s *)data; if (obj) { fprintf (stream, "Free %p\n", obj->real_start); obj_remove (obj); free (obj), obj = NULL; } (void)user_data; } /* public variables ==================================================== */ /* internal public functions =========================================== */ /* entry points ======================================================== */ void sma_init_ (const char *file) { if (file) { stream = fopen (file, "w"); } if (!stream) { stream = stderr; } } void sma_end_ (const char *file, int line) { if (list_size (list) != 0) { fprintf (stream, "===== Fuites memoire =====\n"); sma_profil_ (file, line); obj_foreach (free_leaks); fprintf (stream, "Fuites reparees\n"); } else { fprintf (stream, "Aucune fuite detectee\n"); } if (stream && stream != stderr) { fclose (stream), stream = NULL; } } void *sma_malloc_ (size_t size, const char *file, int line) { void *ret = NULL; void *real_p = NULL; obj_s *obj = NULL; size_t real_size = size + SUP_SIZE * 2; ALLOC_INFO ("===== malloc (%d) dans %s:%d =====\n", size, file, line); real_p = malloc (real_size); if (real_p) { /* Initialisation de l'objet */ int i; for (i = 0; i < (int)real_size; i++) { ((char *)real_p)[i] = 0; } /* Enregistrement de l'objet */ obj = obj_add (1, real_p, real_size, file, line); if (obj) { ALLOC_INFO ("\t+ %d octects a %p\n", obj->size, obj->start); ret = obj->start; } else { ALLOC_ERROR ("Memoire insufisante\n"); } } else { ALLOC_ERROR ("Memoire insufisante\n"); } if (stream) { fprintf (stream, "\n"); } return ret; } void *sma_realloc_ (void *p, size_t size, const char *file, int line, const char *name) { ALLOC_INFO ("===== realloc (%s, %d) dans %s:%d =====\n", name, size, file, line); if (p) { obj_s *obj = NULL; obj = obj_exist (p); if (obj) { void *new_p = NULL; size_t real_size = size + SUP_SIZE * 2; test_flow (obj); ALLOC_INFO ("\t- %d octects a %p dans %s:%d\n", obj->size, obj->start, obj->file, obj->line); new_p = realloc (obj->real_start, real_size); obj_remove (obj); free (obj), obj = NULL; if (new_p) { int i; obj = obj_add (1, new_p, real_size, file, line); p = obj->start; for (i = 0; i < (int)SUP_SIZE; i++) { ((char *)obj->real_start)[i] = 0; } for (i = 0; i < (int)SUP_SIZE; i++) { ((char *)obj->end)[i] = 0; } ALLOC_INFO ("\t+ %d octects dans %p\n", obj->size, obj->start); } else { if (size > 0) { ALLOC_ERROR ("Memoire insufisante\n"); } } } else { ALLOC_ERROR ("Pointeur invalide : %p\n", p); } } else { p = sma_malloc_ (size, file, line); } if (stream) { fprintf (stream, "\n"); } return p; } void sma_register_ (void *p, const char *file, int line, const char *name) { if (p) { ALLOC_INFO ("===== Allocation externe \"%s\" dans %s:%d =====\n", name, file, line); if (!obj_exist (p)) { obj_add (0, p, 0, file, line); ALLOC_INFO ("\t%p\n", p); } else { ALLOC_WARNING ("%p est deja enregistre\n", p); } if (stream) { fprintf (stream, "\n"); } } } void sma_free_ (void *p, const char *file, int line, const char *name) { obj_s *obj = NULL; ALLOC_INFO ("===== free (%s) dans %s:%d =====\n", name, file, line); obj = obj_exist (p); if (obj) { long cs = 0; ALLOC_INFO ("\t- %d octects a %p alloue dans %s:%d\n", obj->size, obj->start, obj->file, obj->line); if (p) { cs = obj_checksum (obj); if (cs == obj->checksum) { p = NULL; if (obj->reg) { test_flow (obj); free (obj->real_start), obj->real_start = NULL; } else { free (obj->start), obj->start = NULL; } obj_remove (obj); free (obj), obj = NULL; } else { ALLOC_ERROR ("Donnees corompues\n"); } } else { ALLOC_INFO ("\tNULL\n"); } } else { ALLOC_WARNING ("Pointeur non enregistre %p\n", p); } if (stream) { fprintf (stream, "\n"); } } void sma_profil_ (const char *file, int line) { if (stream) { fprintf (stream, "|----------------------------------------------------------------|\n"); fprintf (stream, "| Profile memoire |\n"); fprintf (stream, "| %55s %6d |\n", file, line); fprintf (stream, "|----------------------------------------------------------------|\n"); fprintf (stream, "| | Taille | Addr | Ligne | Fichier |\n"); fprintf (stream, "|----------------------------------------------------------------|\n"); obj_foreach (print_obj); fprintf (stream, "|----------------------------------------------------------------|\n"); fprintf (stream, "\n"); } }