From f419dcafdc47c6c91e138990bab726f0807608ac Mon Sep 17 00:00:00 2001 From: KosmX <kosmx.mc@gmail.com> Date: Tue, 1 Dec 2020 19:29:16 +0100 Subject: [PATCH] snek is now a snake --- debugmalloc | Bin 0 -> 56904 bytes map1.txt | 3 +- snake.c | 32 ++- tests/debugdebugmalloc | Bin 0 -> 31184 bytes tests/debugdebugmalloc.c | 17 ++ tests/debugmalloc.h | 503 +++++++++++++++++++++++++++++++++++++++ 6 files changed, 543 insertions(+), 12 deletions(-) create mode 100755 debugmalloc create mode 100755 tests/debugdebugmalloc create mode 100644 tests/debugdebugmalloc.c create mode 100644 tests/debugmalloc.h diff --git a/debugmalloc b/debugmalloc new file mode 100755 index 0000000000000000000000000000000000000000..7e4d17007d4499f55b03577ba50f79a29d0e82ad GIT binary patch literal 56904 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ᤎ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 bFUUTK41^TKp?@am>LvyTh72?fXj}#W&XWW> literal 0 HcmV?d00001 diff --git a/map1.txt b/map1.txt index d9fefdc..8c34865 100644 --- a/map1.txt +++ b/map1.txt @@ -19,5 +19,4 @@ ║ ║ ║ ║ ║ ║ -╚═════════════════════════════════╝ - +╚═════════════════════════════════╝ \ No newline at end of file diff --git a/snake.c b/snake.c index d02acc9..53a4148 100644 --- a/snake.c +++ b/snake.c @@ -1,7 +1,8 @@ -#include "debugmalloc.h" #include<stdio.h> #include<stdlib.h> #include<string.h> +#include "debugmalloc.h" + #include<locale.h> #include<ctype.h> #include<time.h> @@ -386,7 +387,7 @@ void updateFood(Matrix *map, int *foodTick, int feedAmount, snakeChain *firstSna map->matrix[pos.x][pos.y].isFood = 1; map->matrix[pos.x][pos.y].data.FRand = rand(); c.data.chars[0].bytes.c[0] = 'X'; - c.data.chars[0].bytes.c[0] = 'X'; + c.data.chars[1].bytes.c[0] = 'X'; printf(green); print(c, pos, scrDat, map->width, map->height); printf("\e[0m"); @@ -439,9 +440,14 @@ int updateSnake(Matrix *map, screenData *scrDat, Direction d, snakeChain *head, if(isNotWall(map->matrix[pos.x][pos.y])){ int isFood = map->matrix[pos.x][pos.y].isFood; - head->pos = pos; + if(isFood){ + map->matrix[pos.x][pos.y].isFood = false; + map->matrix[pos.x][pos.y].data.chars[0].bytes.c[0] = ' '; + map->matrix[pos.x][pos.y].data.chars[1].bytes.c[0] = ' '; + } snakeChain *snake = head; Pos tmp_pos1 = head->pos, tmp_pos2; + head->pos = pos; while (snake->next != 0) { snake = snake->next; @@ -449,13 +455,15 @@ int updateSnake(Matrix *map, screenData *scrDat, Direction d, snakeChain *head, if(snake != head && snake->pos.x == head->pos.x && snake->pos.y == head->pos.y){ if(snake->next != NULL){ if(canBite){ - snakeChain *current = snake, *tmp_snek = snake; - tmp_snek = tmp_snek->next; + snakeChain *current = snake, *tmp_snek = snake->next; current->next = NULL; while (tmp_snek != NULL) { current = tmp_snek; tmp_snek = tmp_snek->next; + c.data.chars[0].bytes.c[0] = ' '; + c.data.chars[1].bytes.c[0] = ' '; + print(c, current->pos, scrDat, map->width, map->height); free(current); } } @@ -478,13 +486,12 @@ int updateSnake(Matrix *map, screenData *scrDat, Direction d, snakeChain *head, c.data.chars[1].bytes.c[0] = '<'; if(snake->next == NULL && isFood){ isFood = false; - snake->next = malloc(sizeof(snake)); + snake->next = malloc(sizeof(snakeChain)); if(snake->next == NULL){ return EOF; } snake->next->next = NULL; - snake->pos.x = -1; - snake->pos.y = -1; + snake->next->pos = tmp_pos1; } if(snake->pos.x == -1){ continue; //don't render snake part with initial position @@ -580,6 +587,8 @@ int tick(Matrix *map, screenData *scrDat, snakeChain *snake, Direction *d, int f if(scrDat->commands[0] != NONE){ *d = scrDat->commands[0]; } + scrDat->commands[0] = scrDat->commands[1]; + scrDat->commands[1] = NONE; updateScreen(map, scrDat, snake, *d); if(*d == NONE){ chunk c; @@ -591,7 +600,10 @@ int tick(Matrix *map, screenData *scrDat, snakeChain *snake, Direction *d, int f return 0; // waiting for user input. } updateFood(map, &foodTick, feedAmount, snake, scrDat); - updateSnake(map, scrDat, *d, snake, canBite); + if(updateSnake(map, scrDat, *d, snake, canBite)){ + *d = NONE; + //TODO Game over or remove 1 hp or ... + } //printf("\e[0;0H\n"); //Update the terminal (mostly on Unix based systems) fflush(stdout); return 0; @@ -732,7 +744,7 @@ int core(int argc, char const *argv[]) rmMatrix(&map); - + return 0; } diff --git a/tests/debugdebugmalloc b/tests/debugdebugmalloc new file mode 100755 index 0000000000000000000000000000000000000000..3c1a23fed6398bae5dc61c5561bcf37701e99c8d GIT binary patch literal 31184 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 literal 0 HcmV?d00001 diff --git a/tests/debugdebugmalloc.c b/tests/debugdebugmalloc.c new file mode 100644 index 0000000..8f11d77 --- /dev/null +++ b/tests/debugdebugmalloc.c @@ -0,0 +1,17 @@ +#include "debugmalloc.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +int main(void) { + char txt[] = "hello"; + + char *p = malloc((strlen(txt) + 1) * sizeof(char)); + strcpy(p, txt); + printf("TXT: %s\n", p); + debugmalloc_dump(); + free(p); + + return 0; +} \ No newline at end of file diff --git a/tests/debugmalloc.h b/tests/debugmalloc.h new file mode 100644 index 0000000..74a9725 --- /dev/null +++ b/tests/debugmalloc.h @@ -0,0 +1,503 @@ +#ifndef DEBUGMALLOC_H +#define DEBUGMALLOC_H + +#include <stdbool.h> +#include <stddef.h> +#include <stdlib.h> +#include <stdio.h> +#include <ctype.h> +#include <string.h> +#include <stdarg.h> + + +enum { + /* size of canary in bytes. should be multiple of largest alignment + * required by any data type (usually 8 or 16) */ + debugmalloc_canary_size = 64, + + /* canary byte */ + debugmalloc_canary_char = 'K', + + /* hash table size for allocated entries */ + debugmalloc_tablesize = 256, + + /* max block size for allocation, can be modified with debugmalloc_max_block_size() */ + debugmalloc_max_block_size_default = 1048576 +}; + + +/* make getpid and putenv "crossplatform". deprecated on windows but they work just fine, + * however not declared. */ +#ifdef _WIN32 + /* windows */ + #include <process.h> + #ifdef _MSC_VER + /* visual studio, getenv/getpid deprecated warning */ + #pragma warning(disable: 4996) + #else + /* other windows. the declaration is unfortunately hidden + * in mingw header files by ifdefs. */ + int putenv(const char *); + #endif +#else + /* posix */ + #include <unistd.h> +#endif + + +/* linked list entry for allocated blocks */ +typedef struct DebugmallocEntry { + void *real_mem; /* the address of the real allocation */ + void *user_mem; /* address shown to the user */ + size_t size; /* size of block requested by user */ + + char file[64]; /* malloc called in this file */ + unsigned line; /* malloc called at this line in file */ + char func[32]; /* allocation function called (malloc, calloc, realloc) */ + char expr[128]; /* expression calculating the size of allocation */ + + struct DebugmallocEntry *prev, *next; /* for doubly linked list */ +} DebugmallocEntry; + + +/* debugmalloc singleton, storing all state */ +typedef struct DebugmallocData { + char logfile[256]; /* log file name or empty string */ + long max_block_size; /* max size of a single block allocated */ + long alloc_count; /* currently allocated; decreased with free */ + long long alloc_bytes; + long all_alloc_count; /* all allocations, never decreased */ + long long all_alloc_bytes; + DebugmallocEntry head[debugmalloc_tablesize], tail[debugmalloc_tablesize]; /* head and tail elements of allocation lists */ +} DebugmallocData; + + +/* this forward declaration is required by the singleton manager function */ +static DebugmallocData * debugmalloc_create(void); + + +/* creates singleton instance. as this function is static included to different + * translation units, multiple instances of the static variables are created. + * to make sure it is really a singleton, these instances must know each other + * somethow. an environment variable is used for that purpose, ie. the address + * of the singleton allocated is stored by the operating system. + * this implementation is not thread-safe. */ +static DebugmallocData * debugmalloc_singleton(void) { + static char envstr[100]; + static void *instance = NULL; + + /* if we do not know the address of the singleton: + * - maybe we are the one to create it (env variable also does not exist) + * - or it is already created, and stored in the env variable. */ + if (instance == NULL) { + char envvarname[100] = ""; + sprintf(envvarname, "%s%d", "debugmallocsingleton", (int) getpid()); + char *envptr = getenv(envvarname); + if (envptr == NULL) { + /* no env variable: create singleton. */ + instance = debugmalloc_create(); + sprintf(envstr, "%s=%p", envvarname, instance); + putenv(envstr); + } else { + /* another copy of this function already created it. */ + int ok = sscanf(envptr, "%p", &instance); + if (ok != 1) { + fprintf(stderr, "debugmalloc: nem lehet ertelmezni: %s!\n", envptr); + abort(); + } + } + } + + return (DebugmallocData *) instance; +} + + +/* better version of strncpy, always terminates string with \0. */ +static void debugmalloc_strlcpy(char *dest, char const *src, size_t destsize) { + strncpy(dest, src, destsize); + dest[destsize - 1] = '\0'; +} + + +/* set the name of the log file for debugmalloc. empty filename + * means logging to stderr. */ +static void debugmalloc_log_file(char const *logfilename) { + if (logfilename == NULL) + logfilename = ""; + DebugmallocData *instance = debugmalloc_singleton(); + debugmalloc_strlcpy(instance->logfile, logfilename, sizeof(instance->logfile)); +} + + +/* set the maximum size of one block. useful for debugging purposes. */ +static void debugmalloc_max_block_size(long max_block_size) { + DebugmallocData *instance = debugmalloc_singleton(); + instance->max_block_size = max_block_size; +} + + + +/* printf to the log file, or stderr. */ +static void debugmalloc_log(char const *format, ...) { + DebugmallocData *instance = debugmalloc_singleton(); + FILE *f = stderr; + if (instance->logfile[0] != '\0') { + f = fopen(instance->logfile, "at"); + if (f == NULL) { + f = stderr; + fprintf(stderr, "debugmalloc: nem tudom megnyitni a %s fajlt irasra!\n", instance->logfile); + debugmalloc_strlcpy(instance->logfile, "", sizeof(instance->logfile)); + } + } + + va_list ap; + va_start(ap, format); + vfprintf(f, format, ap); + va_end(ap); + + if (f != stderr) + fclose(f); +} + + +/* initialize a memory block allocated for the user. the start and the end + * of the block is initialized with the canary characters. if 'zero' is + * true, the user memory area is zero-initialized, otherwise it is also + * filled with the canary character to simulate garbage in memory. */ +static void debugmalloc_memory_init(DebugmallocEntry *elem, bool zero) { + unsigned char *real_mem = (unsigned char *) elem->real_mem; + unsigned char *user_mem = (unsigned char *) elem->user_mem; + unsigned char *canary1 = real_mem; + unsigned char *canary2 = real_mem + debugmalloc_canary_size + elem->size; + memset(canary1, debugmalloc_canary_char, debugmalloc_canary_size); + memset(canary2, debugmalloc_canary_char, debugmalloc_canary_size); + memset(user_mem, zero ? 0 : debugmalloc_canary_char, elem->size); +} + +/* check canary, return true if ok, false if corrupted. */ +static bool debugmalloc_canary_ok(DebugmallocEntry const *elem) { + unsigned char *real_mem = (unsigned char *) elem->real_mem; + unsigned char *canary1 = real_mem; + unsigned char *canary2 = real_mem + debugmalloc_canary_size + elem->size; + for (size_t i = 0; i < debugmalloc_canary_size; ++i) { + if (canary1[i] != debugmalloc_canary_char) + return false; + if (canary2[i] != debugmalloc_canary_char) + return false; + } + return true; +} + + +/* dump memory contents to log file. */ +static void debugmalloc_dump_memory(char const *mem, size_t size) { + for (unsigned y = 0; y < (size + 15) / 16; y++) { + char line[80]; + int pos = 0; + pos += sprintf(line + pos, " %04x ", y * 16); + for (unsigned x = 0; x < 16; x++) { + if (y * 16 + x < size) + pos += sprintf(line + pos, "%02x ", mem[y * 16 + x]); + else + pos += sprintf(line + pos, " "); + } + pos += sprintf(line + pos, " "); + for (unsigned x = 0; x < 16; x++) { + if (y * 16 + x < size) { + unsigned char c = mem[y * 16 + x]; + pos += sprintf(line + pos, "%c", isprint(c) ? c : '.'); + } + else { + pos += sprintf(line + pos, " "); + } + } + debugmalloc_log("%s\n", line); + } +} + + +/* dump data of allocated memory block. + * if the canary is corrupted, it is also written to the log. */ +static void debugmalloc_dump_elem(DebugmallocEntry const *elem) { + bool canary_ok = debugmalloc_canary_ok(elem); + + debugmalloc_log(" %p, %u bajt, kanari: %s\n" + " %s:%u, %s(%s)\n", + elem->user_mem, (unsigned) elem->size, canary_ok ? "ok" : "**SERULT**", + elem->file, elem->line, + elem->func, elem->expr); + + if (!canary_ok) { + debugmalloc_log(" ELOTTE kanari: \n"); + debugmalloc_dump_memory((char const *) elem->real_mem, debugmalloc_canary_size); + } + + debugmalloc_dump_memory((char const *) elem->user_mem, elem->size > 64 ? 64 : elem->size); + + if (!canary_ok) { + debugmalloc_log(" UTANA kanari: \n"); + debugmalloc_dump_memory((char const *) elem->real_mem + debugmalloc_canary_size + elem->size, debugmalloc_canary_size); + } +} + + +/* dump data of all memory blocks allocated. */ +static void debugmalloc_dump(void) { + DebugmallocData *instance = debugmalloc_singleton(); + debugmalloc_log("** DEBUGMALLOC DUMP ************************************\n"); + int cnt = 0; + for (size_t i = 0; i < debugmalloc_tablesize; i++) { + DebugmallocEntry *head = &instance->head[i]; + for (DebugmallocEntry *iter = head->next; iter->next != NULL; iter = iter->next) { + ++cnt; + debugmalloc_log("** %d/%d. rekord:\n", cnt, instance->alloc_count); + debugmalloc_dump_elem(iter); + } + } + debugmalloc_log("** DEBUGMALLOC DUMP VEGE *******************************\n"); +} + + +/* called at program exit to dump data if there is a leak, + * ie. allocated block remained. */ +static void debugmalloc_atexit_dump(void) { + DebugmallocData *instance = debugmalloc_singleton(); + + if (instance->alloc_count > 0) { + debugmalloc_log("\n" + "********************************************************\n" + "* MEMORIASZIVARGAS VAN A PROGRAMBAN!!!\n" + "********************************************************\n" + "\n"); + debugmalloc_dump(); + } else { + debugmalloc_log("****************************************************\n" + "* Debugmalloc: nincs memoriaszivargas a programban.\n" + "* Osszes foglalas: %d blokk, %d bajt.\n" + "****************************************************\n", + instance->all_alloc_count, instance->all_alloc_bytes); + } +} + + +/* hash function for bucket hash. */ +static size_t debugmalloc_hash(void *address) { + /* the last few bits are ignored, as they are usually zero for + * alignment purposes. all tested architectures used 16 byte allocation. */ + size_t cut = (size_t)address >> 4; + return cut % debugmalloc_tablesize; +} + + +/* insert element to hash table. */ +static void debugmalloc_insert(DebugmallocEntry *entry) { + DebugmallocData *instance = debugmalloc_singleton(); + size_t idx = debugmalloc_hash(entry->user_mem); + DebugmallocEntry *head = &instance->head[idx]; + entry->prev = head; + entry->next = head->next; + head->next->prev = entry; + head->next = entry; + instance->alloc_count += 1; + instance->alloc_bytes += entry->size; + instance->all_alloc_count += 1; + instance->all_alloc_bytes += entry->size; +} + + +/* remove element from hash table */ +static void debugmalloc_remove(DebugmallocEntry *entry) { + DebugmallocData *instance = debugmalloc_singleton(); + entry->next->prev = entry->prev; + entry->prev->next = entry->next; + instance->alloc_count -= 1; + instance->alloc_bytes -= entry->size; +} + + +/* find element in hash table, given with the memory address that the user sees. + * @return the linked list entry, or null if not found. */ +static DebugmallocEntry *debugmalloc_find(void *mem) { + DebugmallocData *instance = debugmalloc_singleton(); + size_t idx = debugmalloc_hash(mem); + DebugmallocEntry *head = &instance->head[idx]; + for (DebugmallocEntry *iter = head->next; iter->next != NULL; iter = iter->next) + if (iter->user_mem == mem) + return iter; + return NULL; +} + + +/* allocate memory. this function is called via the macro. */ +static void *debugmalloc_malloc_full(size_t size, char const *func, char const *expr, char const *file, unsigned line, bool zero) { + /* imitate standard malloc: return null if size is zero */ + if (size == 0) + return NULL; + + /* check max size */ + DebugmallocData *instance = debugmalloc_singleton(); + if (size > instance->max_block_size) { + debugmalloc_log("debugmalloc: %s @ %s:%u: a blokk merete tul nagy, %u bajt; debugmalloc_max_block_size() fuggvennyel novelheto.\n", func, file, line, (unsigned) size); + abort(); + } + + /* allocate more memory, make room for canary */ + void *real_mem = malloc(size + 2 * debugmalloc_canary_size); + if (real_mem == NULL) { + debugmalloc_log("debugmalloc: %s @ %s:%u: nem sikerult %u meretu memoriat foglalni!\n", func, file, line, (unsigned) size); + return NULL; + } + + /* allocate memory for linked list element */ + DebugmallocEntry *newentry = (DebugmallocEntry *) malloc(sizeof(DebugmallocEntry)); + if (newentry == NULL) { + free(real_mem); + debugmalloc_log("debugmalloc: %s @ %s:%u: le tudtam foglalni %u memoriat, de utana a sajatnak nem, sry\n", func, file, line, (unsigned) size); + abort(); + } + + /* metadata of allocation: caller function, code line etc. */ + debugmalloc_strlcpy(newentry->func, func, sizeof(newentry->func)); + debugmalloc_strlcpy(newentry->expr, expr, sizeof(newentry->expr)); + debugmalloc_strlcpy(newentry->file, file, sizeof(newentry->file)); + newentry->line = line; + + /* address of allocated memory chunk */ + newentry->real_mem = real_mem; + newentry->user_mem = (unsigned char *) real_mem + debugmalloc_canary_size; + newentry->size = size; + debugmalloc_memory_init(newentry, zero); + + /* store in list and return pointer to user area */ + debugmalloc_insert(newentry); + return newentry->user_mem; +} + + +/* free memory and remove list item. before deleting, the chuck is filled with + * the canary byte to make sure that the user will see garbage if the memory + * is accessed after freeing. */ +static void debugmalloc_free_inner(DebugmallocEntry *deleted) { + debugmalloc_remove(deleted); + + /* fill with garbage, then remove from linked list */ + memset(deleted->real_mem, debugmalloc_canary_char, deleted->size + 2 * debugmalloc_canary_size); + free(deleted->real_mem); + free(deleted); +} + + +/* free memory - called via the macro. + * as all allocations are tracked in the list, this function can terminate the program + * if a block is freed twice or the free function is called with an invalid address. */ +static void debugmalloc_free_full(void *mem, char const *func, char const *file, unsigned line) { + /* imitate standard free function: if ptr is null, no operation is performed */ + if (mem == NULL) + return; + + /* find allocation, abort if not found */ + DebugmallocEntry *deleted = debugmalloc_find(mem); + if (deleted == NULL) { + debugmalloc_log("debugmalloc: %s @ %s:%u: olyan teruletet probalsz felszabaditani, ami nincs lefoglalva!\n", func, file, line); + abort(); + } + + /* check canary and then free memory */ + if (!debugmalloc_canary_ok(deleted)) { + debugmalloc_log("debugmalloc: %s @ %s:%u: a %p memoriateruletet tulindexelted!\n", func, file, line, mem); + debugmalloc_dump_elem(deleted); + } + debugmalloc_free_inner(deleted); +} + + +/* realloc-like function. */ +static void *debugmalloc_realloc_full(void *oldmem, size_t newsize, char const *func, char const *expr, char const *file, unsigned line) { + /* imitate standard realloc: equivalent to free if size is null. */ + if (newsize == 0) { + debugmalloc_free_full(oldmem, func, file, line); + return NULL; + } + /* imitate standard realloc: equivalent to malloc if first param is NULL */ + if (oldmem == NULL) + return debugmalloc_malloc_full(newsize, func, expr, file, line, 0); + + /* find old allocation. abort if not found. */ + DebugmallocEntry *oldentry = debugmalloc_find(oldmem); + if (oldentry == NULL) { + debugmalloc_log("debugmalloc: %s @ %s:%u: olyan teruletet probalsz atmeretezni, ami nincs lefoglalva!\n", func, file, line); + abort(); + } + + /* create new allocation, copy & free old data */ + void *newmem = debugmalloc_malloc_full(newsize, func, expr, file, line, false); + if (newmem == NULL) { + debugmalloc_log("debugmalloc: %s @ %s:%u: nem sikerult uj memoriat foglalni az atmeretezeshez!\n", func, file, line); + /* imitate standard realloc: original block is untouched, but return NULL */ + return NULL; + } + size_t smaller = oldentry->size < newsize ? oldentry->size : newsize; + memcpy(newmem, oldmem, smaller); + debugmalloc_free_inner(oldentry); + + return newmem; +} + + +/* initialize debugmalloc singleton. returns the newly allocated instance */ +static DebugmallocData * debugmalloc_create(void) { + /* config check */ + if (debugmalloc_canary_size % 16 != 0) { + debugmalloc_log("debugmalloc: a kanari merete legyen 16-tal oszthato\n"); + abort(); + } + if (debugmalloc_canary_char == 0) { + debugmalloc_log("debugmalloc: a kanari legyen 0-tol kulonbozo\n"); + abort(); + } + /* avoid compiler warning if these functions are not used */ + (void) debugmalloc_realloc_full; + (void) debugmalloc_log_file; + (void) debugmalloc_max_block_size; + + /* create and initialize instance */ + DebugmallocData *instance = (DebugmallocData *) malloc(sizeof(DebugmallocData)); + if (instance == NULL) { + debugmalloc_log("debugmalloc: nem sikerult elinditani a memoriakezelest\n"); + abort(); + } + debugmalloc_strlcpy(instance->logfile, "", sizeof(instance->logfile)); + instance->max_block_size = debugmalloc_max_block_size_default; + instance->alloc_count = 0; + instance->alloc_bytes = 0; + instance->all_alloc_count = 0; + instance->all_alloc_bytes = 0; + for (size_t i = 0; i < debugmalloc_tablesize; i++) { + instance->head[i].prev = NULL; + instance->head[i].next = &instance->tail[i]; + instance->tail[i].next = NULL; + instance->tail[i].prev = &instance->head[i]; + } + + atexit(debugmalloc_atexit_dump); + return instance; +} + + +/* These macro-like functions forward all allocation/free + * calls to debugmalloc. Usage is the same, malloc(size) + * gives the address of a new memory block, free(ptr) + * deallocates etc. + * + * If you use this file, make sure that you include this + * in *ALL* translation units (*.c) of your source. The + * builtin free() function cannot deallocate a memory block + * that was allocated via debugmalloc, yet the name of + * the function is the same! */ + +#define malloc(S) debugmalloc_malloc_full((S), "malloc", #S, __FILE__, __LINE__, false) +#define calloc(N,S) debugmalloc_malloc_full((N)*(S), "calloc", #N ", " #S, __FILE__, __LINE__, true) +#define realloc(P,S) debugmalloc_realloc_full((P), (S), "realloc", #S, __FILE__, __LINE__) +#define free(P) debugmalloc_free_full((P), "free", __FILE__, __LINE__) + +#endif -- GitLab