I am trying to write a custom lib in c for a personal project. The lib includes some common data structures. I am allocating the list on the heap and I think I am cleaning up properly, but that is not the case. On running leaks --atExit --list -- ./main
(mac m1), I am getting a total of 4 leaks in the following code.
leaks Report Version: 3.0
Process 18747: 221 nodes malloced for 17 KB
Process 18747: 4 leaks for 96 total leaked bytes.
Stack trace is as follows:
Leak: 0x14e7040f0 size=16 zone: MallocStackLoggingLiteZone_0x102a40000 malloc in main C main
Call stack: 0x180c6be50 (dyld) start | 0x1028475a8 (main) main main.c:38 | 0x180dffd00 (libsystem_malloc.dylib) _malloc_zone_malloc_instrumented_or_legacy
Leak: 0x14e704100 size=16 zone: MallocStackLoggingLiteZone_0x102a40000 malloc in main C main
Call stack: 0x180c6be50 (dyld) start | 0x1028475c4 (main) main main.c:41 | 0x180dffd00 (libsystem_malloc.dylib) _malloc_zone_malloc_instrumented_or_legacy
Leak: 0x14e704180 size=32 zone: MallocStackLoggingLiteZone_0x102a40000 malloc in node_init C main
Call stack: 0x180c6be50 (dyld) start | 0x10284761c (main) main main.c:48 | 0x102847a30 (main) owl_sll_binsert singly_linked_list.c:88 | 0x102847ab8 (main) node_init singly_linked_list.c:60 | 0x180dffd00 (libsystem_malloc.dylib) _malloc_zone_malloc_instrumented_or_legacy
Leak: 0x14e7041a0 size=32 zone: MallocStackLoggingLiteZone_0x102a40000 malloc in node_init C main
Call stack: 0x180c6be50 (dyld) start | 0x10284761c (main) main main.c:48 | 0x102847a30 (main) owl_sll_binsert singly_linked_list.c:88 | 0x102847ac4 (main) node_init singly_linked_list.c:61 | 0x180dffd00 (libsystem_malloc.dylib) _malloc_zone_malloc_instrumented_or_legacy
singly_linked_list.c
#include "singly_linked_list.h"
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
/* Opaque type */
typedef struct SinglyLinkedList
{
owl_sll_node_t *head;
owl_sll_node_t *tail;
u_long length;
size_t size;
void (*elfree)(void *item);
} owl_sll_t;
//
owl_sll_t *owl_sll_init(size_t size, void (*elfree)(void *item))
{
owl_sll_t *list = malloc(sizeof(owl_sll_t));
list->head = NULL;
list->tail = NULL;
list->length = 0;
list->size = size;
list->elfree = elfree;
return list;
}
void owl_sll_free(owl_sll_t *list)
{
if (!list->length)
{
free(list);
return;
}
owl_sll_node_t *cursor = list->head;
while (cursor)
{
if (list->elfree)
list->elfree(cursor->data);
else
free(cursor->data);
free(cursor);
cursor = cursor->next;
}
free(list);
}
static owl_sll_node_t *node_init(void *data, size_t size)
{
static unsigned int id = 0;
owl_sll_node_t *node = malloc(sizeof(owl_sll_node_t));
node->data = malloc(size);
// copy the content of the data
for (int i = 0; i < size; i )
*(char *)(node->data i) = *(char *)(data i);
node->next = NULL;
node->id = id ;
return node;
}
static void node_free(owl_sll_t *list, owl_sll_node_t *node)
{
if (!node) return;
// break any link if exist
node->next = NULL;
if (list->elfree)
list->elfree(node->data);
else
free(node->data);
free(node);
}
void owl_sll_binsert(owl_sll_t *list, void *data)
{
owl_sll_node_t *node = node_init(data, list->size);
if (!list->head)
{
list->head = node;
list->tail = node;
}
else
{
list->tail->next = node;
list->tail = node;
}
list->length ;
}
void *owl_sll_bremove(owl_sll_t *list)
{
if (!list->length) return NULL;
owl_sll_node_t *cursor = list->head;
while (cursor->next && cursor->next->next)
{
cursor = cursor->next;
}
void *data = cursor->data;
node_free(list, cursor->next);
list->tail = cursor;
list->tail->next = NULL;
list->length--;
if (list->length == 0)
{
list->head = NULL;
list->tail = NULL;
}
return data;
}
void owl_sll_finsert(owl_sll_t *list, void *data)
{
owl_sll_node_t *node = node_init(data, list->size);
if (!list->head)
{
list->head = node;
list->tail = node;
}
else
{
node->next = list->head;
list->head = node;
}
list->length ;
}
void *owl_sll_fremove(owl_sll_t *list)
{
if (!list->length) return NULL;
void *data = list->head->data;
owl_sll_node_t *node_to_free = list->head;
list->head = list->head->next;
node_free(list, node_to_free);
list->length--;
if (list->length == 0)
{
list->head = NULL;
list->tail = NULL;
}
return data;
}
void owl_sll_print(owl_sll_t *list, void (*format)(void *data), char *connection_sym)
{
if (!list->length)
{
printf("EMPTY\n");
return;
}
owl_sll_node_t *cursor = list->head;
char *conn_sym = connection_sym ? connection_sym : "->";
while (cursor)
{
format(cursor->data);
printf(" %s ", conn_sym);
cursor = cursor->next;
}
printf("END\n");
}
// Getters
owl_sll_node_t *owl_sll_head(owl_sll_t *list)
{
return list->head;
}
owl_sll_node_t *owl_sll_tail(owl_sll_t *list)
{
return list->tail;
}
unsigned long int owl_sll_length(owl_sll_t *list)
{
return list->length;
}
singly_linked_list.h
#ifndef linked_list_h
#define linked_list_h
#include <stdlib.h>
typedef struct Node
{
unsigned int id;
void *data;
struct Node *next;
} owl_sll_node_t;
typedef struct SinglyLinkedList owl_sll_t;
owl_sll_t *owl_sll_init(size_t size, void (*elfree)(void *item));
void owl_sll_free(owl_sll_t *list);
void owl_sll_binsert(owl_sll_t *list, void *data);
void *owl_sll_bremove(owl_sll_t *list);
void owl_sll_finsert(owl_sll_t *list, void *data);
void *owl_sll_fremove(owl_sll_t *list);
void owl_sll_print(owl_sll_t *list, void (*format)(void *data), char *connector_symbol);
// Getters
owl_sll_node_t *owl_sll_head(owl_sll_t *list);
owl_sll_node_t *owl_sll_tail(owl_sll_t *list);
unsigned long int owl_sll_length(owl_sll_t *list);
#endif /* linked_list_h */
main.c
#include "data_structure/singly_linked_list.h"
#include <stdio.h>
typedef struct a
{
int id;
} a_t;
typedef struct b
{
int id;
a_t *a;
} b_t;
void elfree(void *item)
{
b_t *b = item;
free(b->a);
free(b);
}
int main(int argc, const char *argv[])
{
printf("OWL