Files
xrdp/tests/memtest/libmem.c
T
matt335672 2f46ef27a2 Add support for cppcheck 2.17.0
cppcheck 2.17.0 adds checks that a NULL pointer returned from malloc() and
calloc() is not used.

We do this quite a lot.

I've addressed this by adding functions g_malloc_nofail() and
g_calloc_nofail() which either allocate memory or abort.
functions are now called in places where we are not making these
checks.

Many of these checks are in test programs or example programs.

I've modified the list16 module to handle out-of-memory conditions.
2025-02-27 15:04:11 +00:00

414 lines
10 KiB
C

#if defined(HAVE_CONFIG_H)
#include <config_ac.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "libmem.h"
#include "log.h"
#include "os_calls.h"
#define ALIGN_BY 32
#define ALIGN_BY_M1 (ALIGN_BY - 1)
#define ALIGN(_in) (((_in) + ALIGN_BY_M1) & (~ALIGN_BY_M1))
struct mem_item
{
unsigned int addr;
int bytes;
struct mem_item *next;
struct mem_item *prev;
};
struct mem_info
{
unsigned int addr;
int bytes;
int flags;
struct mem_item *free_head;
struct mem_item *free_tail;
struct mem_item *used_head;
struct mem_item *used_tail;
int total_bytes;
};
/*****************************************************************************/
static int
libmem_free_mem_item(struct mem_info *self, struct mem_item *mi)
{
if (self == 0 || mi == 0)
{
return 0;
}
if (mi->prev != 0)
{
mi->prev->next = mi->next;
}
if (mi->next != 0)
{
mi->next->prev = mi->prev;
}
if (mi == self->free_head)
{
self->free_head = mi->next;
}
if (mi == self->free_tail)
{
self->free_tail = mi->prev;
}
if (mi == self->used_head)
{
self->used_head = mi->next;
}
if (mi == self->used_tail)
{
self->used_tail = mi->prev;
}
free(mi);
return 0;
}
/*****************************************************************************/
void *
libmem_init(unsigned int addr, int bytes)
{
struct mem_info *self;
struct mem_item *mi;
self = (struct mem_info *)g_malloc_nofail(sizeof(struct mem_info));
memset(self, 0, sizeof(struct mem_info));
self->addr = addr;
self->bytes = bytes;
//self->flags = 1;
mi = (struct mem_item *)g_malloc_nofail(sizeof(struct mem_item));
memset(mi, 0, sizeof(struct mem_item));
mi->addr = addr;
mi->bytes = bytes;
self->free_head = mi;
self->free_tail = mi;
return self;
}
/*****************************************************************************/
void
libmem_deinit(void *aself)
{
struct mem_info *self;
self = (struct mem_info *)aself;
if (self == 0)
{
return;
}
while (self->free_head != 0)
{
libmem_free_mem_item(self, self->free_head);
}
while (self->used_head != 0)
{
libmem_free_mem_item(self, self->used_head);
}
free(self);
}
/****************************************************************************/
static int
libmem_add_used_item(struct mem_info *self, unsigned int addr, int bytes)
{
struct mem_item *mi;
struct mem_item *new_mi;
int added;
if (self == 0 || addr == 0)
{
return 1;
}
if (self->used_head == 0)
{
/* add first item */
new_mi = (struct mem_item *)g_malloc_nofail(sizeof(struct mem_item));
memset(new_mi, 0, sizeof(struct mem_item));
new_mi->addr = addr;
new_mi->bytes = bytes;
self->used_head = new_mi;
self->used_tail = new_mi;
return 0;
}
added = 0;
mi = self->used_head;
while (mi != 0)
{
if (mi->addr > addr)
{
/* add before */
new_mi = (struct mem_item *)g_malloc_nofail(sizeof(struct mem_item));
memset(new_mi, 0, sizeof(struct mem_item));
new_mi->addr = addr;
new_mi->bytes = bytes;
new_mi->prev = mi->prev;
new_mi->next = mi;
if (mi->prev != 0)
{
mi->prev->next = new_mi;
}
mi->prev = new_mi;
if (self->used_head == mi)
{
self->used_head = new_mi;
}
added = 1;
break;
}
mi = mi->next;
}
if (!added)
{
/* add last */
new_mi = (struct mem_item *)g_malloc_nofail(sizeof(struct mem_item));
memset(new_mi, 0, sizeof(struct mem_item));
new_mi->addr = addr;
new_mi->bytes = bytes;
self->used_tail->next = new_mi;
new_mi->prev = self->used_tail;
self->used_tail = new_mi;
}
return 0;
}
/****************************************************************************/
static int
libmem_add_free_item(struct mem_info *self, unsigned int addr, int bytes)
{
struct mem_item *mi;
struct mem_item *new_mi;
int added;
if (self == 0 || addr == 0)
{
return 1;
}
if (self->free_head == 0)
{
/* add first item */
new_mi = (struct mem_item *)g_malloc_nofail(sizeof(struct mem_item));
memset(new_mi, 0, sizeof(struct mem_item));
new_mi->addr = addr;
new_mi->bytes = bytes;
self->free_head = new_mi;
self->free_tail = new_mi;
return 0;
}
added = 0;
mi = self->free_head;
while (mi != 0)
{
if (mi->addr > addr)
{
if (mi->prev != 0)
{
if (mi->prev->addr + mi->prev->bytes == addr)
{
/* don't need to add, just make prev bigger */
mi->prev->bytes += bytes;
if (mi->prev->addr + mi->prev->bytes == mi->addr)
{
/* here we can remove one */
mi->prev->bytes += mi->bytes;
libmem_free_mem_item(self, mi);
}
return 0;
}
}
if (addr + bytes == mi->addr)
{
/* don't need to add here either */
mi->addr = addr;
mi->bytes += bytes;
return 0;
}
/* add before */
new_mi = (struct mem_item *)g_malloc_nofail(sizeof(struct mem_item));
memset(new_mi, 0, sizeof(struct mem_item));
new_mi->addr = addr;
new_mi->bytes = bytes;
new_mi->prev = mi->prev;
new_mi->next = mi;
if (mi->prev != 0)
{
mi->prev->next = new_mi;
}
mi->prev = new_mi;
if (self->free_head == mi)
{
self->free_head = new_mi;
}
added = 1;
break;
}
mi = mi->next;
}
if (!added)
{
/* add last */
new_mi = (struct mem_item *)g_malloc_nofail(sizeof(struct mem_item));
memset(new_mi, 0, sizeof(struct mem_item));
new_mi->addr = addr;
new_mi->bytes = bytes;
self->free_tail->next = new_mi;
new_mi->prev = self->free_tail;
self->free_tail = new_mi;
}
return 0;
}
/*****************************************************************************/
static int
libmem_print(struct mem_info *self)
{
struct mem_item *mi;
LOG_DEVEL(LOG_LEVEL_DEBUG, "libmem_print:");
LOG_DEVEL(LOG_LEVEL_DEBUG, " used_head %p", self->used_head);
LOG_DEVEL(LOG_LEVEL_DEBUG, " used_tail %p", self->used_tail);
mi = self->used_head;
if (mi != 0)
{
LOG_DEVEL(LOG_LEVEL_DEBUG, " used list");
while (mi != 0)
{
LOG_DEVEL(LOG_LEVEL_DEBUG, " ptr %p prev %p next %p addr 0x%8.8x bytes %d",
mi, mi->prev, mi->next, mi->addr, mi->bytes);
mi = mi->next;
}
}
LOG_DEVEL(LOG_LEVEL_DEBUG, " free_head %p", self->free_head);
LOG_DEVEL(LOG_LEVEL_DEBUG, " free_tail %p", self->free_tail);
mi = self->free_head;
if (mi != 0)
{
LOG_DEVEL(LOG_LEVEL_DEBUG, " free list");
while (mi != 0)
{
LOG_DEVEL(LOG_LEVEL_DEBUG, " ptr %p prev %p next %p addr 0x%8.8x bytes %d",
mi, mi->prev, mi->next, mi->addr, mi->bytes);
mi = mi->next;
}
}
return 0;
}
/*****************************************************************************/
unsigned int
libmem_alloc(void *obj, int bytes)
{
struct mem_info *self;
struct mem_item *mi;
unsigned int addr;
if (bytes < 1)
{
return 0;
}
bytes = ALIGN(bytes);
self = (struct mem_info *)obj;
addr = 0;
mi = self->free_head;
while (mi != 0)
{
if (bytes <= mi->bytes)
{
addr = mi->addr;
mi->bytes -= bytes;
mi->addr += bytes;
if (mi->bytes < 1)
{
libmem_free_mem_item(self, mi);
}
break;
}
mi = mi->next;
}
if (addr != 0)
{
self->total_bytes += bytes;
libmem_add_used_item(self, addr, bytes);
if (self->flags & 1)
{
libmem_print(self);
}
}
else
{
LOG_DEVEL(LOG_LEVEL_ERROR, "libmem_alloc: error");
}
return addr;
}
/*****************************************************************************/
int
libmem_free(void *obj, unsigned int addr)
{
struct mem_info *self;
struct mem_item *mi;
if (addr == 0)
{
return 0;
}
self = (struct mem_info *)obj;
mi = self->used_tail;
while (mi != 0)
{
if (mi->addr == addr)
{
self->total_bytes -= mi->bytes;
libmem_add_free_item(self, mi->addr, mi->bytes);
libmem_free_mem_item(self, mi);
if (self->flags & 1)
{
libmem_print(self);
}
return 0;
}
mi = mi->prev;
}
LOG_DEVEL(LOG_LEVEL_ERROR, "libmem_free: error");
return 1;
}
/*****************************************************************************/
int
libmem_set_flags(void *obj, int flags)
{
struct mem_info *self;
self = (struct mem_info *)obj;
self->flags |= flags;
return 0;
}
/*****************************************************************************/
int
libmem_clear_flags(void *obj, int flags)
{
struct mem_info *self;
self = (struct mem_info *)obj;
self->flags &= ~flags;
return 0;
}
/*****************************************************************************/
int
libmem_get_alloced_bytes(void *obj)
{
struct mem_info *self;
self = (struct mem_info *)obj;
return self->total_bytes;
}