Skip to content

Commit 60d5521

Browse files
committed
Fix memory leak
This commit adds proper cleanup on allocation failure and iterator safety by saving next pointer before callback execution. In addition, unlikely() branch prediction hints are added for better performance.
1 parent 51bad75 commit 60d5521

File tree

1 file changed

+25
-19
lines changed

1 file changed

+25
-19
lines changed

include/lib/list.h

Lines changed: 25 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,17 @@
11
/* Singly-linked list
22
* – Two sentinel nodes (head and tail) eliminate edge-case tests.
33
* – The list stores generic data pointers ('void *').
4-
* – All primitives are defined `static inline` so they can live entirely
4+
* – All primitives are defined 'static inline' so they can live entirely
55
* in the header without multiple-definition issues.
6-
* – Comments follow C style and use concise American English.
76
*/
87

98
#pragma once
109

1110
#include <lib/libc.h>
1211
#include <lib/malloc.h>
1312

13+
#include "private/utils.h"
14+
1415
/* List node */
1516
typedef struct list_node {
1617
struct list_node *next;
@@ -26,12 +27,18 @@ typedef struct {
2627

2728
static inline list_t *list_create(void)
2829
{
29-
list_t *list = malloc(sizeof(list_t));
30-
list_node_t *head = malloc(sizeof(list_node_t));
31-
list_node_t *tail = malloc(sizeof(list_node_t));
30+
list_t *list = malloc(sizeof(*list));
31+
if (unlikely(!list))
32+
return NULL;
33+
34+
list_node_t *head = malloc(sizeof(*head));
35+
if (unlikely(!head)) {
36+
free(list);
37+
return NULL;
38+
}
3239

33-
if (!list || !head || !tail) { /* cleanup on failure */
34-
free(tail);
40+
list_node_t *tail = malloc(sizeof(*tail));
41+
if (unlikely(!tail)) {
3542
free(head);
3643
free(list);
3744
return NULL;
@@ -64,7 +71,7 @@ static inline list_node_t *list_next(const list_node_t *node)
6471
static inline list_node_t *list_cnext(const list_t *list,
6572
const list_node_t *node)
6673
{
67-
if (!list || !node)
74+
if (unlikely(!list || !node))
6875
return NULL;
6976
return (node->next == list->tail) ? list->head->next : node->next;
7077
}
@@ -73,17 +80,15 @@ static inline list_node_t *list_cnext(const list_t *list,
7380

7481
static inline list_node_t *list_pushback(list_t *list, void *data)
7582
{
76-
if (!list)
83+
if (unlikely(!list))
7784
return NULL;
7885

79-
list_node_t *node = malloc(sizeof(list_node_t));
80-
if (!node)
86+
list_node_t *node = malloc(sizeof(*node));
87+
if (unlikely(!node))
8188
return NULL;
8289

8390
node->data = data;
8491
node->next = list->tail;
85-
list->tail->data = NULL; /* head and tail sentinels never hold data */
86-
list->head->data = NULL;
8792

8893
/* Insert before tail sentinel */
8994
list_node_t *prev = list->head;
@@ -97,7 +102,7 @@ static inline list_node_t *list_pushback(list_t *list, void *data)
97102

98103
static inline void *list_pop(list_t *list)
99104
{
100-
if (list_is_empty(list))
105+
if (unlikely(list_is_empty(list)))
101106
return NULL;
102107

103108
list_node_t *first = list->head->next;
@@ -112,14 +117,14 @@ static inline void *list_pop(list_t *list)
112117
/* Remove a specific node; returns its data */
113118
static inline void *list_remove(list_t *list, list_node_t *target)
114119
{
115-
if (!list || !target || list_is_empty(list))
120+
if (unlikely(!list || !target || list_is_empty(list)))
116121
return NULL;
117122

118123
list_node_t *prev = list->head;
119124
while (prev->next != list->tail && prev->next != target)
120125
prev = prev->next;
121126

122-
if (prev->next != target)
127+
if (unlikely(prev->next != target))
123128
return NULL; /* node not found */
124129

125130
prev->next = target->next;
@@ -137,15 +142,16 @@ static inline list_node_t *list_foreach(list_t *list,
137142
void *),
138143
void *arg)
139144
{
140-
if (!list || !cb)
145+
if (unlikely(!list || !cb))
141146
return NULL;
142147

143148
list_node_t *node = list->head->next;
144149
while (node != list->tail) {
150+
list_node_t *next = node->next; /* Save next before callback */
145151
list_node_t *res = cb(node, arg);
146152
if (res)
147153
return res;
148-
node = node->next;
154+
node = next;
149155
}
150156
return NULL;
151157
}
@@ -154,7 +160,7 @@ static inline list_node_t *list_foreach(list_t *list,
154160

155161
static inline void list_clear(list_t *list)
156162
{
157-
if (!list)
163+
if (unlikely(!list))
158164
return;
159165
while (!list_is_empty(list))
160166
list_pop(list);

0 commit comments

Comments
 (0)