Skip to content

Commit 51bad75

Browse files
authored
Merge pull request #10 from tsaiiuo/fix/null-check-queue
queue: Improve null-pointer safety
2 parents 243b36a + 308ca6d commit 51bad75

File tree

3 files changed

+20
-9
lines changed

3 files changed

+20
-9
lines changed

include/lib/list.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ static inline list_node_t *list_pushback(list_t *list, void *data)
8282

8383
node->data = data;
8484
node->next = list->tail;
85-
list->tail->data = NULL; /* tail sentinel never holds data */
85+
list->tail->data = NULL; /* head and tail sentinels never hold data */
8686
list->head->data = NULL;
8787

8888
/* Insert before tail sentinel */

include/lib/queue.h

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#pragma once
1212

1313
#include <lib/libc.h>
14+
#include "private/utils.h"
1415

1516
/* State is managed entirely by head/tail indices. The capacity is always
1617
* a power of two to allow for efficient bitwise masking instead of a more
@@ -28,7 +29,7 @@ typedef struct {
2829
} queue_t;
2930

3031
/* Creates and initializes a new queue.
31-
* @capacity The desired minimum capacity. The actual capacity will be rounded
32+
* @capacity: The desired minimum capacity. The actual capacity will be rounded
3233
* up to the next power of two.
3334
* Return A pointer to the newly created queue, or NULL on failure.
3435
*/
@@ -37,7 +38,7 @@ queue_t *queue_create(int32_t capacity);
3738
/* Destroys a queue and frees its resources.
3839
* This operation will fail if the queue is not empty, preventing memory
3940
* leaks of the items contained within the queue.
40-
* @q The queue to destroy.
41+
* @q: The queue to destroy.
4142
*
4243
* Return 0 on success, or a negative error code on failure.
4344
*/
@@ -46,19 +47,27 @@ int32_t queue_destroy(queue_t *q);
4647
/* Checks if the queue is empty. */
4748
static inline bool queue_is_empty(const queue_t *q)
4849
{
49-
return q->head == q->tail;
50+
return !q || q->head == q->tail;
5051
}
5152

52-
/* Returns the number of elements currently in the queue. */
53+
/* Returns the number of elements currently in the queue.
54+
*
55+
* If the queue pointer is NULL, it is treated as an empty queue
56+
* and this function returns 0. This ensures safe behavior even
57+
* when invalid pointers are passed.
58+
*/
5359
static inline uint32_t queue_count(const queue_t *q)
5460
{
61+
/* Treat NULL queue as empty to prevent undefined behavior */
62+
if (unlikely(!q))
63+
return 0u;
5564
return (q->tail - q->head + q->size) & q->mask;
5665
}
5766

5867
/* Checks if the queue is full. */
5968
static inline bool queue_is_full(const queue_t *q)
6069
{
61-
return ((q->tail + 1) & q->mask) == q->head;
70+
return q && (((q->tail + 1) & q->mask) == q->head);
6271
}
6372

6473
/* Adds an element to the tail of the queue (FIFO). */

lib/queue.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ queue_t *queue_create(int32_t capacity)
3737
int32_t queue_destroy(queue_t *q)
3838
{
3939
/* Refuse to destroy a non-empty queue. */
40-
if (!q || !queue_is_empty(q))
40+
if (!queue_is_empty(q))
4141
return ERR_FAIL;
4242

4343
free(q->buf);
@@ -48,8 +48,10 @@ int32_t queue_destroy(queue_t *q)
4848
/* Adds an element to the tail of the queue. */
4949
int32_t queue_enqueue(queue_t *q, void *ptr)
5050
{
51-
/* The queue can only store up to 'size - 1' items. */
52-
if (queue_is_full(q))
51+
/* Reject null pointer or enqueue into a full queue.
52+
* The queue can only store up to 'size - 1' items.
53+
*/
54+
if (!q || queue_is_full(q))
5355
return ERR_FAIL;
5456

5557
q->buf[q->tail] = ptr;

0 commit comments

Comments
 (0)