Add memory allocation checking to the list module

The list module lacks memory allocation checking, and
consequently can coredump on list_create() or
list_add_item().
This commit is contained in:
matt335672 2023-02-08 11:16:03 +00:00
parent a27440c237
commit 5aa5624551
2 changed files with 166 additions and 57 deletions

View File

@ -22,23 +22,53 @@
#include <config_ac.h> #include <config_ac.h>
#endif #endif
#include <stdlib.h>
#include "arch.h" #include "arch.h"
#include "os_calls.h" #include "os_calls.h"
#include "string_calls.h" #include "string_calls.h"
#include "list.h" #include "list.h"
#include "log.h" #include "log.h"
enum
{
DEFAULT_LIST_SIZE = 10,
DEFAULT_GROW_BY_SIZE = 10
};
/*****************************************************************************/
struct list *
list_create_sized(unsigned int size)
{
struct list *self;
if (size < DEFAULT_LIST_SIZE)
{
size = DEFAULT_LIST_SIZE;
}
self = (struct list *)calloc(sizeof(struct list), 1);
if (self != NULL)
{
self->items = (tbus *)malloc(sizeof(tbus) * size);
if (self->items == NULL)
{
free(self);
self = NULL;
}
else
{
self->grow_by = DEFAULT_GROW_BY_SIZE;
self->alloc_size = size;
}
}
return self;
}
/*****************************************************************************/ /*****************************************************************************/
struct list * struct list *
list_create(void) list_create(void)
{ {
struct list *self; return list_create_sized(DEFAULT_LIST_SIZE);
self = (struct list *)g_malloc(sizeof(struct list), 1);
self->grow_by = 10;
self->alloc_size = 10;
self->items = (tbus *)g_malloc(sizeof(tbus) * 10, 1);
return self;
} }
/*****************************************************************************/ /*****************************************************************************/
@ -56,34 +86,46 @@ list_delete(struct list *self)
{ {
for (i = 0; i < self->count; i++) for (i = 0; i < self->count; i++)
{ {
g_free((void *)self->items[i]); free((void *)self->items[i]);
self->items[i] = 0; self->items[i] = 0;
} }
} }
g_free(self->items); free(self->items);
g_free(self); free(self);
} }
/*****************************************************************************/ /*****************************************************************************/
void static int
grow_list(struct list *self)
{
int rv = 1;
unsigned int new_alloc_size = self->alloc_size + self->grow_by;
tbus *p = (tbus *)realloc(self->items, sizeof(tbus) * new_alloc_size);
if (p == NULL)
{
rv = 0;
}
else
{
self->alloc_size = new_alloc_size;
self->items = p;
}
return rv;
}
/*****************************************************************************/
int
list_add_item(struct list *self, tbus item) list_add_item(struct list *self, tbus item)
{ {
tbus *p; if (self->count == self->alloc_size && !grow_list(self))
int i;
if (self->count >= self->alloc_size)
{ {
i = self->alloc_size; return 0;
self->alloc_size += self->grow_by;
p = (tbus *)g_malloc(sizeof(tbus) * self->alloc_size, 1);
g_memcpy(p, self->items, sizeof(tbus) * i);
g_free(self->items);
self->items = p;
} }
self->items[self->count] = item; self->items[self->count] = item;
self->count++; self->count++;
return 1;
} }
/*****************************************************************************/ /*****************************************************************************/
@ -108,16 +150,15 @@ list_clear(struct list *self)
{ {
for (i = 0; i < self->count; i++) for (i = 0; i < self->count; i++)
{ {
g_free((void *)self->items[i]); free((void *)self->items[i]);
self->items[i] = 0; self->items[i] = 0;
} }
} }
g_free(self->items);
self->count = 0; self->count = 0;
self->grow_by = 10; self->grow_by = DEFAULT_GROW_BY_SIZE;
self->alloc_size = 10; self->alloc_size = DEFAULT_LIST_SIZE;
self->items = (tbus *)g_malloc(sizeof(tbus) * 10, 1); self->items = (tbus *)realloc(self->items, sizeof(tbus) * self->alloc_size);
} }
/*****************************************************************************/ /*****************************************************************************/
@ -147,7 +188,7 @@ list_remove_item(struct list *self, int index)
{ {
if (self->auto_free) if (self->auto_free)
{ {
g_free((void *)self->items[index]); free((void *)self->items[index]);
self->items[index] = 0; self->items[index] = 0;
} }
@ -161,57 +202,84 @@ list_remove_item(struct list *self, int index)
} }
/*****************************************************************************/ /*****************************************************************************/
void int
list_insert_item(struct list *self, int index, tbus item) list_insert_item(struct list *self, int index, tbus item)
{ {
tbus *p;
int i;
if (index == self->count) if (index > self->count)
{ {
list_add_item(self, item); index = self->count;
return; }
else if (index < 0)
{
index = 0;
} }
if (index >= 0 && index < self->count) if (self->count == self->alloc_size && !grow_list(self))
{ {
self->count++; return 0;
}
if (self->count > self->alloc_size) self->count++;
{ if (self->count >= 2)
i = self->alloc_size; {
self->alloc_size += self->grow_by; unsigned int i;
p = (tbus *)g_malloc(sizeof(tbus) * self->alloc_size, 1); for (i = (self->count - 2); i >= (unsigned int)index; i--)
g_memcpy(p, self->items, sizeof(tbus) * i);
g_free(self->items);
self->items = p;
}
for (i = (self->count - 2); i >= index; i--)
{ {
self->items[i + 1] = self->items[i]; self->items[i + 1] = self->items[i];
} }
self->items[index] = item;
} }
self->items[index] = item;
return 1;
} }
/*****************************************************************************/ /*****************************************************************************/
/* append one list to another using strdup for each item in the list */ /* append one list to another using strdup for each item in the list */
/* begins copy at start_index, a zero based index on the source list */ /* begins copy at start_index, a zero based index on the source list */
void int
list_append_list_strdup(struct list *self, struct list *dest, int start_index) list_append_list_strdup(struct list *self, struct list *dest, int start_index)
{ {
int index; int index;
tbus item; int rv = 1;
char *dup; int entry_dest_count = dest->count;
for (index = start_index; index < self->count; index++) for (index = start_index; index < self->count; index++)
{ {
item = list_get_item(self, index); const char *item = (const char *)list_get_item(self, index);
dup = g_strdup((char *)item); char *dup;
list_add_item(dest, (tbus)dup); if (item == NULL)
{
// This shouldn't really happen, but if it does we'll
// copy the item anyway.
dup = NULL;
}
else
{
dup = g_strdup(item);
if (dup == NULL)
{
rv = 0;
break;
}
}
if (!list_add_item(dest, (tbus)dup))
{
rv = 0;
break;
}
} }
if (rv == 0)
{
// Remove the additional items we added
while (dest->count > entry_dest_count)
{
list_remove_item(dest, dest->count - 1);
}
}
return rv;
} }
/*****************************************************************************/ /*****************************************************************************/

View File

@ -35,9 +35,27 @@ struct list
struct list * struct list *
list_create(void); list_create(void);
/**
* Creates a list with at least the specified number of items
* reserved
* @param size Number of items to reserve
* @return list, or NULL if no memory
*/
struct list *
list_create_sized(unsigned int size);
void void
list_delete(struct list *self); list_delete(struct list *self);
void /**
* Adds an item to a list
* @param self The list
* @param item The item to add
* @result 0 if a memory allocation failure occurred. In this
* case the item is not added
*
* Memory allocation failures will not occur if the list is
* sized appropriately when created.
*/
int
list_add_item(struct list *self, tintptr item); list_add_item(struct list *self, tintptr item);
tintptr tintptr
list_get_item(const struct list *self, int index); list_get_item(const struct list *self, int index);
@ -47,9 +65,32 @@ int
list_index_of(struct list *self, tintptr item); list_index_of(struct list *self, tintptr item);
void void
list_remove_item(struct list *self, int index); list_remove_item(struct list *self, int index);
void /**
* Inserts an item into a list
* @param self The list
* @param index The location to insert the item before
* @param item The item to add
* @result 0 if a memory allocation failure occurred. In this
* case the item is not added
*
* Memory allocation failures will not occur if the list is
* sized appropriately when created.
*/
int
list_insert_item(struct list *self, int index, tintptr item); list_insert_item(struct list *self, int index, tintptr item);
void /**
* Adds strings to a list from another list
* @param self The source list
* @param dest Destination list
* @param start_index Index to start on the source list (zero based)
*
* @result 0 if a memory allocation failure occurred. In this
* case the destination list is unaltered.
*
* Strings from the source list are copied with strdup()
* The dest list should have auto_free set, or memory leaks will occur
*/
int
list_append_list_strdup(struct list *self, struct list *dest, int start_index); list_append_list_strdup(struct list *self, struct list *dest, int start_index);
void void
list_dump_items(struct list *self); list_dump_items(struct list *self);