diff --git a/examples/da_remove.c b/examples/da_remove.c new file mode 100644 index 0000000..818f5a9 --- /dev/null +++ b/examples/da_remove.c @@ -0,0 +1,21 @@ +#include +#define LAZY_IMPL +#include "../lazy.h" + +int main() { + int arr[] = {0,1,2,3,4}; + Lz_DA(int) da = {0}; + lz_da_fill_from_array(&da, arr); + + lz_da_foreach(int, x, da) { + printf("%d\n", *x); + } + + lz_da_remove(da, 2); + + lz_da_foreach(int, x, da) { + printf("%d\n", *x); + } + + return 0; +} diff --git a/examples/leak.c b/examples/leak.c new file mode 100644 index 0000000..08da7a3 --- /dev/null +++ b/examples/leak.c @@ -0,0 +1,34 @@ +#include +#define LZ_MEM_ANALYZER +#define LAZY_IMPL +#include "../lazy.h" + +typedef struct { + int payload; + void *next; +} LLNode; + +int main () { + LLNode *root = malloc(sizeof(LLNode)); + + LLNode *curr = root; + int prevX = 0; + for (int i = 0; i < 10; ++i) { + LLNode *new = malloc(sizeof(LLNode)); + curr->next = new; + new->payload = ++prevX; + curr = new; + } + + curr = root; + while (curr->next) { + void *next = curr->next; + printf("%d\n", curr->payload); + free(curr); + curr = next; + } + free(curr); + + lz_mem_debug(); + return 0; +} diff --git a/lazy.h b/lazy.h index 3a37530..a205552 100644 --- a/lazy.h +++ b/lazy.h @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -27,6 +28,17 @@ typedef struct { size_t cnt; size_t cap; } Lz_SB; + +#endif + +#ifndef LZ_ALLOC_DATA_DEF +#define LZ_ALLOC_DATA_DEF +typedef struct { + size_t size; + void *ptr; + char file[256]; + int line; +} Lz_Alloc_Data; #endif void lz_slc_trim_left_typ(Lz_Slc *src, int (*classfunc)(int)); @@ -116,6 +128,16 @@ long long lz_slc_atoll(Lz_Slc *src); } while(0) #endif +#ifndef lz_da_remove +#define lz_da_remove(da, idx) do {\ + if ((da).cnt <= (idx)) {\ + assert(0 && "Removal index out of bounds");\ + }\ + --(da).cnt;\ + memmove((da).data+idx,(da).data+idx+1,((da).cnt-idx)*sizeof(*(da.data)));\ +} while(0) +#endif + #ifndef lz_da_destroy #define lz_da_destroy(da) do { free((da).data); } while (0); #endif @@ -284,6 +306,8 @@ long long lz_sb_atoll(Lz_SB *src); #ifdef LAZY_IMPL #undef LAZY_IMPL +Lz_DA(Lz_Alloc_Data) _lz_allocations = {0}; + size_t lz_hm_hash_raw_bytes(size_t cap, void *key, size_t k_s) { size_t hash = 0; for (size_t i = 0; i < k_s; ++i) { @@ -523,4 +547,56 @@ long long lz_sb_atoll(Lz_SB *src) { free(cstr); return x; } + +void *lz_tracking_malloc(size_t size, const char* file, int line) { + void *ptr = malloc(size); + Lz_Alloc_Data dat = (Lz_Alloc_Data){ + .size = size, + .ptr = ptr, + .line = line + }; + strncpy(dat.file, file, 256); + lz_da_append(_lz_allocations, dat); + return ptr; +} + +void lz_tracking_free(void *ptr, const char *file, int line) { + for (int i = 0; i < _lz_allocations.cnt; ++i) { + if (_lz_allocations.data[i].ptr == ptr) { + lz_da_remove(_lz_allocations, i); + free(ptr); + return; + } + } + printf("[LZ_MEM_ANALYZER] Freeing unallocated memory @ %x, %s, line %d", + ptr, file, line); + exit(1); +} + +void lz_mem_analyzer_debug(const char *file, int line) { + printf("[LZ_MEM_ANALYZER] Memory report from %s, line %d\n", file, line); + if (_lz_allocations.cnt == 0) { + printf("All tests passed :)\n"); + return; + } + printf("Found %d unfreed chunks of memory\n", _lz_allocations.cnt); + for (int i = 0; i < _lz_allocations.cnt; ++i) { + Lz_Alloc_Data dat = _lz_allocations.data[i]; + printf("Non-freed memory found: %x\n", dat.ptr); + printf(" size: %d bytes\n", dat.size); + printf(" allocated at:\n"); + printf(" %s, line %d\n", dat.file, dat.line); + } +} +#endif + +#ifdef LZ_MEM_ANALYZER +#undef LZ_MEM_ANALYZER +// TODO: implement the other memory functions (calloc and some others) +#define malloc(size) lz_tracking_malloc(size, __FILE__, __LINE__) +#define free(ptr) lz_tracking_free(ptr, __FILE__, __LINE__) +#define lz_mem_debug() lz_mem_analyzer_debug(__FILE__, __LINE__) + +#else +#define lz_mem_debug() #endif