#include "lwip/opt.h"
#include "lwip/mem.h"
#include "lwip/def.h"
#include "lwip/sys.h"
#include "lwip/stats.h"
#include "lwip/err.h"
#include <string.h>
#if MEM_LIBC_MALLOC
#include <stdlib.h>
#endif
#ifndef LWIP_MEM_ILLEGAL_FREE
#define LWIP_MEM_ILLEGAL_FREE(msg) LWIP_ASSERT(msg, 0)
#endif
#define MEM_STATS_INC_LOCKED(x) SYS_ARCH_LOCKED(MEM_STATS_INC(x))
#define MEM_STATS_INC_USED_LOCKED(x, y) SYS_ARCH_LOCKED(MEM_STATS_INC_USED(x, y))
#define MEM_STATS_DEC_USED_LOCKED(x, y) SYS_ARCH_LOCKED(MEM_STATS_DEC_USED(x, y))
#if MEM_OVERFLOW_CHECK
#define MEM_SANITY_OFFSET MEM_SANITY_REGION_BEFORE_ALIGNED
#define MEM_SANITY_OVERHEAD (MEM_SANITY_REGION_BEFORE_ALIGNED + MEM_SANITY_REGION_AFTER_ALIGNED)
#else
#define MEM_SANITY_OFFSET 0
#define MEM_SANITY_OVERHEAD 0
#endif
#if MEM_OVERFLOW_CHECK || MEMP_OVERFLOW_CHECK
void
mem_overflow_check_raw(void *p, size_t size, const char *descr1, const char *descr2)
{
#if MEM_SANITY_REGION_AFTER_ALIGNED || MEM_SANITY_REGION_BEFORE_ALIGNED
u16_t k;
u8_t *m;
#if MEM_SANITY_REGION_AFTER_ALIGNED > 0
m = (u8_t *)p + size;
for (k = 0; k < MEM_SANITY_REGION_AFTER_ALIGNED; k++) {
if (m[k] != 0xcd) {
char errstr[128];
snprintf(errstr, sizeof(errstr), "detected mem overflow in %s%s", descr1, descr2);
LWIP_ASSERT(errstr, 0);
}
}
#endif
#if MEM_SANITY_REGION_BEFORE_ALIGNED > 0
m = (u8_t *)p - MEM_SANITY_REGION_BEFORE_ALIGNED;
for (k = 0; k < MEM_SANITY_REGION_BEFORE_ALIGNED; k++) {
if (m[k] != 0xcd) {
char errstr[128];
snprintf(errstr, sizeof(errstr), "detected mem underflow in %s%s", descr1, descr2);
LWIP_ASSERT(errstr, 0);
}
}
#endif
#else
LWIP_UNUSED_ARG(p);
LWIP_UNUSED_ARG(desc);
LWIP_UNUSED_ARG(descr);
#endif
}
void
mem_overflow_init_raw(void *p, size_t size)
{
#if MEM_SANITY_REGION_BEFORE_ALIGNED > 0 || MEM_SANITY_REGION_AFTER_ALIGNED > 0
u8_t *m;
#if MEM_SANITY_REGION_BEFORE_ALIGNED > 0
m = (u8_t *)p - MEM_SANITY_REGION_BEFORE_ALIGNED;
memset(m, 0xcd, MEM_SANITY_REGION_BEFORE_ALIGNED);
#endif
#if MEM_SANITY_REGION_AFTER_ALIGNED > 0
m = (u8_t *)p + size;
memset(m, 0xcd, MEM_SANITY_REGION_AFTER_ALIGNED);
#endif
#else
LWIP_UNUSED_ARG(p);
LWIP_UNUSED_ARG(desc);
#endif
}
#endif
#if MEM_LIBC_MALLOC || MEM_USE_POOLS
void
mem_init(void)
{
}
void *
mem_trim(void *mem, mem_size_t size)
{
LWIP_UNUSED_ARG(size);
return mem;
}
#endif
#if MEM_LIBC_MALLOC
#ifndef mem_clib_free
#define mem_clib_free free
#endif
#ifndef mem_clib_malloc
#define mem_clib_malloc malloc
#endif
#ifndef mem_clib_calloc
#define mem_clib_calloc calloc
#endif
#if LWIP_STATS && MEM_STATS
#define MEM_LIBC_STATSHELPER_SIZE LWIP_MEM_ALIGN_SIZE(sizeof(mem_size_t))
#else
#define MEM_LIBC_STATSHELPER_SIZE 0
#endif
void *
mem_malloc(mem_size_t size)
{
void *ret = mem_clib_malloc(size + MEM_LIBC_STATSHELPER_SIZE);
if (ret == NULL) {
MEM_STATS_INC_LOCKED(err);
} else {
LWIP_ASSERT("malloc() must return aligned memory", LWIP_MEM_ALIGN(ret) == ret);
#if LWIP_STATS && MEM_STATS
*(mem_size_t *)ret = size;
ret = (u8_t *)ret + MEM_LIBC_STATSHELPER_SIZE;
MEM_STATS_INC_USED_LOCKED(used, size);
#endif
}
return ret;
}
void
mem_free(void *rmem)
{
LWIP_ASSERT("rmem != NULL", (rmem != NULL));
LWIP_ASSERT("rmem == MEM_ALIGN(rmem)", (rmem == LWIP_MEM_ALIGN(rmem)));
#if LWIP_STATS && MEM_STATS
rmem = (u8_t *)rmem - MEM_LIBC_STATSHELPER_SIZE;
MEM_STATS_DEC_USED_LOCKED(used, *(mem_size_t *)rmem);
#endif
mem_clib_free(rmem);
}
#elif MEM_USE_POOLS
void *
mem_malloc(mem_size_t size)
{
void *ret;
struct memp_malloc_helper *element = NULL;
memp_t poolnr;
mem_size_t required_size = size + LWIP_MEM_ALIGN_SIZE(sizeof(struct memp_malloc_helper));
for (poolnr = MEMP_POOL_FIRST; poolnr <= MEMP_POOL_LAST; poolnr = (memp_t)(poolnr + 1)) {
if (required_size <= memp_pools[poolnr]->size) {
element = (struct memp_malloc_helper *)memp_malloc(poolnr);
if (element == NULL) {
#if MEM_USE_POOLS_TRY_BIGGER_POOL
if (poolnr < MEMP_POOL_LAST) {
continue;
}
#endif
MEM_STATS_INC_LOCKED(err);
return NULL;
}
break;
}
}
if (poolnr > MEMP_POOL_LAST) {
LWIP_ASSERT("mem_malloc(): no pool is that big!", 0);
MEM_STATS_INC_LOCKED(err);
return NULL;
}
element->poolnr = poolnr;
ret = (u8_t *)element + LWIP_MEM_ALIGN_SIZE(sizeof(struct memp_malloc_helper));
#if MEMP_OVERFLOW_CHECK || (LWIP_STATS && MEM_STATS)
element->size = (u16_t)size;
MEM_STATS_INC_USED_LOCKED(used, element->size);
#endif
#if MEMP_OVERFLOW_CHECK
memset((u8_t *)ret + size, 0xcd, memp_pools[poolnr]->size - size);
#endif
return ret;
}
void
mem_free(void *rmem)
{
struct memp_malloc_helper *hmem;
LWIP_ASSERT("rmem != NULL", (rmem != NULL));
LWIP_ASSERT("rmem == MEM_ALIGN(rmem)", (rmem == LWIP_MEM_ALIGN(rmem)));
hmem = (struct memp_malloc_helper *)(void *)((u8_t *)rmem - LWIP_MEM_ALIGN_SIZE(sizeof(struct memp_malloc_helper)));
LWIP_ASSERT("hmem != NULL", (hmem != NULL));
LWIP_ASSERT("hmem == MEM_ALIGN(hmem)", (hmem == LWIP_MEM_ALIGN(hmem)));
LWIP_ASSERT("hmem->poolnr < MEMP_MAX", (hmem->poolnr < MEMP_MAX));
MEM_STATS_DEC_USED_LOCKED(used, hmem->size);
#if MEMP_OVERFLOW_CHECK
{
u16_t i;
LWIP_ASSERT("MEM_USE_POOLS: invalid chunk size",
hmem->size <= memp_pools[hmem->poolnr]->size);
for (i = hmem->size; i < memp_pools[hmem->poolnr]->size; i++) {
u8_t data = *((u8_t *)rmem + i);
LWIP_ASSERT("MEM_USE_POOLS: mem overflow detected", data == 0xcd);
}
}
#endif
memp_free(hmem->poolnr, hmem);
}
#else
struct mem {
mem_size_t next;
mem_size_t prev;
u8_t used;
#if MEM_OVERFLOW_CHECK
mem_size_t user_size;
#endif
};
#ifndef MIN_SIZE
#define MIN_SIZE 12
#endif
#define MIN_SIZE_ALIGNED LWIP_MEM_ALIGN_SIZE(MIN_SIZE)
#define SIZEOF_STRUCT_MEM LWIP_MEM_ALIGN_SIZE(sizeof(struct mem))
#define MEM_SIZE_ALIGNED LWIP_MEM_ALIGN_SIZE(MEM_SIZE)
#ifndef LWIP_RAM_HEAP_POINTER
LWIP_DECLARE_MEMORY_ALIGNED(ram_heap, MEM_SIZE_ALIGNED + (2U * SIZEOF_STRUCT_MEM));
#define LWIP_RAM_HEAP_POINTER ram_heap
#endif
static u8_t *ram;
static struct mem *ram_end;
#if !NO_SYS
static sys_mutex_t mem_mutex;
#endif
#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
static volatile u8_t mem_free_count;
#define LWIP_MEM_FREE_DECL_PROTECT() SYS_ARCH_DECL_PROTECT(lev_free)
#define LWIP_MEM_FREE_PROTECT() SYS_ARCH_PROTECT(lev_free)
#define LWIP_MEM_FREE_UNPROTECT() SYS_ARCH_UNPROTECT(lev_free)
#define LWIP_MEM_ALLOC_DECL_PROTECT() SYS_ARCH_DECL_PROTECT(lev_alloc)
#define LWIP_MEM_ALLOC_PROTECT() SYS_ARCH_PROTECT(lev_alloc)
#define LWIP_MEM_ALLOC_UNPROTECT() SYS_ARCH_UNPROTECT(lev_alloc)
#define LWIP_MEM_LFREE_VOLATILE volatile
#else
#define LWIP_MEM_FREE_DECL_PROTECT()
#define LWIP_MEM_FREE_PROTECT() sys_mutex_lock(&mem_mutex)
#define LWIP_MEM_FREE_UNPROTECT() sys_mutex_unlock(&mem_mutex)
#define LWIP_MEM_ALLOC_DECL_PROTECT()
#define LWIP_MEM_ALLOC_PROTECT()
#define LWIP_MEM_ALLOC_UNPROTECT()
#define LWIP_MEM_LFREE_VOLATILE
#endif
static struct mem * LWIP_MEM_LFREE_VOLATILE lfree;
#if MEM_SANITY_CHECK
static void mem_sanity(void);
#define MEM_SANITY() mem_sanity()
#else
#define MEM_SANITY()
#endif
#if MEM_OVERFLOW_CHECK
static void
mem_overflow_init_element(struct mem *mem, mem_size_t user_size)
{
void *p = (u8_t *)mem + SIZEOF_STRUCT_MEM + MEM_SANITY_OFFSET;
mem->user_size = user_size;
mem_overflow_init_raw(p, user_size);
}
static void
mem_overflow_check_element(struct mem *mem)
{
void *p = (u8_t *)mem + SIZEOF_STRUCT_MEM + MEM_SANITY_OFFSET;
mem_overflow_check_raw(p, mem->user_size, "heap", "");
}
#else
#define mem_overflow_init_element(mem, size)
#define mem_overflow_check_element(mem)
#endif
static struct mem *
ptr_to_mem(mem_size_t ptr)
{
return (struct mem *)(void *)&ram[ptr];
}
static mem_size_t
mem_to_ptr(void *mem)
{
return (mem_size_t)((u8_t *)mem - ram);
}
static void
plug_holes(struct mem *mem)
{
struct mem *nmem;
struct mem *pmem;
LWIP_ASSERT("plug_holes: mem >= ram", (u8_t *)mem >= ram);
LWIP_ASSERT("plug_holes: mem < ram_end", (u8_t *)mem < (u8_t *)ram_end);
LWIP_ASSERT("plug_holes: mem->used == 0", mem->used == 0);
LWIP_ASSERT("plug_holes: mem->next <= MEM_SIZE_ALIGNED", mem->next <= MEM_SIZE_ALIGNED);
nmem = ptr_to_mem(mem->next);
if (mem != nmem && nmem->used == 0 && (u8_t *)nmem != (u8_t *)ram_end) {
if (lfree == nmem) {
lfree = mem;
}
mem->next = nmem->next;
if (nmem->next != MEM_SIZE_ALIGNED) {
ptr_to_mem(nmem->next)->prev = mem_to_ptr(mem);
}
}
pmem = ptr_to_mem(mem->prev);
if (pmem != mem && pmem->used == 0) {
if (lfree == mem) {
lfree = pmem;
}
pmem->next = mem->next;
if (mem->next != MEM_SIZE_ALIGNED) {
ptr_to_mem(mem->next)->prev = mem_to_ptr(pmem);
}
}
}
void
mem_init(void)
{
struct mem *mem;
LWIP_ASSERT("Sanity check alignment",
(SIZEOF_STRUCT_MEM & (MEM_ALIGNMENT - 1)) == 0);
ram = (u8_t *)LWIP_MEM_ALIGN(LWIP_RAM_HEAP_POINTER);
mem = (struct mem *)(void *)ram;
mem->next = MEM_SIZE_ALIGNED;
mem->prev = 0;
mem->used = 0;
ram_end = ptr_to_mem(MEM_SIZE_ALIGNED);
ram_end->used = 1;
ram_end->next = MEM_SIZE_ALIGNED;
ram_end->prev = MEM_SIZE_ALIGNED;
MEM_SANITY();
lfree = (struct mem *)(void *)ram;
MEM_STATS_AVAIL(avail, MEM_SIZE_ALIGNED);
if (sys_mutex_new(&mem_mutex) != ERR_OK) {
LWIP_ASSERT("failed to create mem_mutex", 0);
}
}
static int
mem_link_valid(struct mem *mem)
{
struct mem *nmem, *pmem;
mem_size_t rmem_idx;
rmem_idx = mem_to_ptr(mem);
nmem = ptr_to_mem(mem->next);
pmem = ptr_to_mem(mem->prev);
if ((mem->next > MEM_SIZE_ALIGNED) || (mem->prev > MEM_SIZE_ALIGNED) ||
((mem->prev != rmem_idx) && (pmem->next != rmem_idx)) ||
((nmem != ram_end) && (nmem->prev != rmem_idx))) {
return 0;
}
return 1;
}
#if MEM_SANITY_CHECK
static void
mem_sanity(void)
{
struct mem *mem;
u8_t last_used;
mem = (struct mem *)ram;
LWIP_ASSERT("heap element used valid", (mem->used == 0) || (mem->used == 1));
last_used = mem->used;
LWIP_ASSERT("heap element prev ptr valid", mem->prev == 0);
LWIP_ASSERT("heap element next ptr valid", mem->next <= MEM_SIZE_ALIGNED);
LWIP_ASSERT("heap element next ptr aligned", LWIP_MEM_ALIGN(ptr_to_mem(mem->next) == ptr_to_mem(mem->next)));
for (mem = ptr_to_mem(mem->next);
((u8_t *)mem > ram) && (mem < ram_end);
mem = ptr_to_mem(mem->next)) {
LWIP_ASSERT("heap element aligned", LWIP_MEM_ALIGN(mem) == mem);
LWIP_ASSERT("heap element prev ptr valid", mem->prev <= MEM_SIZE_ALIGNED);
LWIP_ASSERT("heap element next ptr valid", mem->next <= MEM_SIZE_ALIGNED);
LWIP_ASSERT("heap element prev ptr aligned", LWIP_MEM_ALIGN(ptr_to_mem(mem->prev) == ptr_to_mem(mem->prev)));
LWIP_ASSERT("heap element next ptr aligned", LWIP_MEM_ALIGN(ptr_to_mem(mem->next) == ptr_to_mem(mem->next)));
if (last_used == 0) {
LWIP_ASSERT("heap element unused?", mem->used == 1);
} else {
LWIP_ASSERT("heap element unused member", (mem->used == 0) || (mem->used == 1));
}
LWIP_ASSERT("heap element link valid", mem_link_valid(mem));
last_used = mem->used;
}
LWIP_ASSERT("heap end ptr sanity", mem == ptr_to_mem(MEM_SIZE_ALIGNED));
LWIP_ASSERT("heap element used valid", mem->used == 1);
LWIP_ASSERT("heap element prev ptr valid", mem->prev == MEM_SIZE_ALIGNED);
LWIP_ASSERT("heap element next ptr valid", mem->next == MEM_SIZE_ALIGNED);
}
#endif
void
mem_free(void *rmem)
{
struct mem *mem;
LWIP_MEM_FREE_DECL_PROTECT();
if (rmem == NULL) {
LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("mem_free(p == NULL) was called.\n"));
return;
}
if ((((mem_ptr_t)rmem) & (MEM_ALIGNMENT - 1)) != 0) {
LWIP_MEM_ILLEGAL_FREE("mem_free: sanity check alignment");
LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_LEVEL_SEVERE, ("mem_free: sanity check alignment\n"));
MEM_STATS_INC_LOCKED(illegal);
return;
}
mem = (struct mem *)(void *)((u8_t *)rmem - (SIZEOF_STRUCT_MEM + MEM_SANITY_OFFSET));
if ((u8_t *)mem < ram || (u8_t *)rmem + MIN_SIZE_ALIGNED > (u8_t *)ram_end) {
LWIP_MEM_ILLEGAL_FREE("mem_free: illegal memory");
LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_LEVEL_SEVERE, ("mem_free: illegal memory\n"));
MEM_STATS_INC_LOCKED(illegal);
return;
}
#if MEM_OVERFLOW_CHECK
mem_overflow_check_element(mem);
#endif
LWIP_MEM_FREE_PROTECT();
if (!mem->used) {
LWIP_MEM_ILLEGAL_FREE("mem_free: illegal memory: double free");
LWIP_MEM_FREE_UNPROTECT();
LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_LEVEL_SEVERE, ("mem_free: illegal memory: double free?\n"));
MEM_STATS_INC_LOCKED(illegal);
return;
}
if (!mem_link_valid(mem)) {
LWIP_MEM_ILLEGAL_FREE("mem_free: illegal memory: non-linked: double free");
LWIP_MEM_FREE_UNPROTECT();
LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_LEVEL_SEVERE, ("mem_free: illegal memory: non-linked: double free?\n"));
MEM_STATS_INC_LOCKED(illegal);
return;
}
mem->used = 0;
if (mem < lfree) {
lfree = mem;
}
MEM_STATS_DEC_USED(used, mem->next - (mem_size_t)(((u8_t *)mem - ram)));
plug_holes(mem);
MEM_SANITY();
#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
mem_free_count = 1;
#endif
LWIP_MEM_FREE_UNPROTECT();
}
void *
mem_trim(void *rmem, mem_size_t new_size)
{
mem_size_t size, newsize;
mem_size_t ptr, ptr2;
struct mem *mem, *mem2;
LWIP_MEM_FREE_DECL_PROTECT();
newsize = (mem_size_t)LWIP_MEM_ALIGN_SIZE(new_size);
if (newsize < MIN_SIZE_ALIGNED) {
newsize = MIN_SIZE_ALIGNED;
}
#if MEM_OVERFLOW_CHECK
newsize += MEM_SANITY_REGION_BEFORE_ALIGNED + MEM_SANITY_REGION_AFTER_ALIGNED;
#endif
if ((newsize > MEM_SIZE_ALIGNED) || (newsize < new_size)) {
return NULL;
}
LWIP_ASSERT("mem_trim: legal memory", (u8_t *)rmem >= (u8_t *)ram &&
(u8_t *)rmem < (u8_t *)ram_end);
if ((u8_t *)rmem < (u8_t *)ram || (u8_t *)rmem >= (u8_t *)ram_end) {
LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_LEVEL_SEVERE, ("mem_trim: illegal memory\n"));
MEM_STATS_INC_LOCKED(illegal);
return rmem;
}
mem = (struct mem *)(void *)((u8_t *)rmem - (SIZEOF_STRUCT_MEM + MEM_SANITY_OFFSET));
#if MEM_OVERFLOW_CHECK
mem_overflow_check_element(mem);
#endif
ptr = mem_to_ptr(mem);
size = (mem_size_t)((mem_size_t)(mem->next - ptr) - (SIZEOF_STRUCT_MEM + MEM_SANITY_OVERHEAD));
LWIP_ASSERT("mem_trim can only shrink memory", newsize <= size);
if (newsize > size) {
return NULL;
}
if (newsize == size) {
return rmem;
}
LWIP_MEM_FREE_PROTECT();
mem2 = ptr_to_mem(mem->next);
if (mem2->used == 0) {
mem_size_t next;
LWIP_ASSERT("invalid next ptr", mem->next != MEM_SIZE_ALIGNED);
next = mem2->next;
ptr2 = (mem_size_t)(ptr + SIZEOF_STRUCT_MEM + newsize);
if (lfree == mem2) {
lfree = ptr_to_mem(ptr2);
}
mem2 = ptr_to_mem(ptr2);
mem2->used = 0;
mem2->next = next;
mem2->prev = ptr;
mem->next = ptr2;
if (mem2->next != MEM_SIZE_ALIGNED) {
ptr_to_mem(mem2->next)->prev = ptr2;
}
MEM_STATS_DEC_USED(used, (size - newsize));
} else if (newsize + SIZEOF_STRUCT_MEM + MIN_SIZE_ALIGNED <= size) {
ptr2 = (mem_size_t)(ptr + SIZEOF_STRUCT_MEM + newsize);
LWIP_ASSERT("invalid next ptr", mem->next != MEM_SIZE_ALIGNED);
mem2 = ptr_to_mem(ptr2);
if (mem2 < lfree) {
lfree = mem2;
}
mem2->used = 0;
mem2->next = mem->next;
mem2->prev = ptr;
mem->next = ptr2;
if (mem2->next != MEM_SIZE_ALIGNED) {
ptr_to_mem(mem2->next)->prev = ptr2;
}
MEM_STATS_DEC_USED(used, (size - newsize));
}
#if MEM_OVERFLOW_CHECK
mem_overflow_init_element(mem, new_size);
#endif
MEM_SANITY();
#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
mem_free_count = 1;
#endif
LWIP_MEM_FREE_UNPROTECT();
return rmem;
}
void *
mem_malloc(mem_size_t size_in)
{
mem_size_t ptr, ptr2, size;
struct mem *mem, *mem2;
#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
u8_t local_mem_free_count = 0;
#endif
LWIP_MEM_ALLOC_DECL_PROTECT();
if (size_in == 0) {
return NULL;
}
size = (mem_size_t)LWIP_MEM_ALIGN_SIZE(size_in);
if (size < MIN_SIZE_ALIGNED) {
size = MIN_SIZE_ALIGNED;
}
#if MEM_OVERFLOW_CHECK
size += MEM_SANITY_REGION_BEFORE_ALIGNED + MEM_SANITY_REGION_AFTER_ALIGNED;
#endif
if ((size > MEM_SIZE_ALIGNED) || (size < size_in)) {
return NULL;
}
sys_mutex_lock(&mem_mutex);
LWIP_MEM_ALLOC_PROTECT();
#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
do {
local_mem_free_count = 0;
#endif
for (ptr = mem_to_ptr(lfree); ptr < MEM_SIZE_ALIGNED - size;
ptr = ptr_to_mem(ptr)->next) {
mem = ptr_to_mem(ptr);
#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
mem_free_count = 0;
LWIP_MEM_ALLOC_UNPROTECT();
LWIP_MEM_ALLOC_PROTECT();
if (mem_free_count != 0) {
local_mem_free_count = 1;
break;
}
#endif
if ((!mem->used) &&
(mem->next - (ptr + SIZEOF_STRUCT_MEM)) >= size) {
if (mem->next - (ptr + SIZEOF_STRUCT_MEM) >= (size + SIZEOF_STRUCT_MEM + MIN_SIZE_ALIGNED)) {
ptr2 = (mem_size_t)(ptr + SIZEOF_STRUCT_MEM + size);
LWIP_ASSERT("invalid next ptr",ptr2 != MEM_SIZE_ALIGNED);
mem2 = ptr_to_mem(ptr2);
mem2->used = 0;
mem2->next = mem->next;
mem2->prev = ptr;
mem->next = ptr2;
mem->used = 1;
if (mem2->next != MEM_SIZE_ALIGNED) {
ptr_to_mem(mem2->next)->prev = ptr2;
}
MEM_STATS_INC_USED(used, (size + SIZEOF_STRUCT_MEM));
} else {
mem->used = 1;
MEM_STATS_INC_USED(used, mem->next - mem_to_ptr(mem));
}
#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
mem_malloc_adjust_lfree:
#endif
if (mem == lfree) {
struct mem *cur = lfree;
while (cur->used && cur != ram_end) {
#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
mem_free_count = 0;
LWIP_MEM_ALLOC_UNPROTECT();
LWIP_MEM_ALLOC_PROTECT();
if (mem_free_count != 0) {
goto mem_malloc_adjust_lfree;
}
#endif
cur = ptr_to_mem(cur->next);
}
lfree = cur;
LWIP_ASSERT("mem_malloc: !lfree->used", ((lfree == ram_end) || (!lfree->used)));
}
LWIP_MEM_ALLOC_UNPROTECT();
sys_mutex_unlock(&mem_mutex);
LWIP_ASSERT("mem_malloc: allocated memory not above ram_end.",
(mem_ptr_t)mem + SIZEOF_STRUCT_MEM + size <= (mem_ptr_t)ram_end);
LWIP_ASSERT("mem_malloc: allocated memory properly aligned.",
((mem_ptr_t)mem + SIZEOF_STRUCT_MEM) % MEM_ALIGNMENT == 0);
LWIP_ASSERT("mem_malloc: sanity check alignment",
(((mem_ptr_t)mem) & (MEM_ALIGNMENT - 1)) == 0);
#if MEM_OVERFLOW_CHECK
mem_overflow_init_element(mem, size_in);
#endif
MEM_SANITY();
return (u8_t *)mem + SIZEOF_STRUCT_MEM + MEM_SANITY_OFFSET;
}
}
#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
} while (local_mem_free_count != 0);
#endif
MEM_STATS_INC(err);
LWIP_MEM_ALLOC_UNPROTECT();
sys_mutex_unlock(&mem_mutex);
LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("mem_malloc: could not allocate %"S16_F" bytes\n", (s16_t)size));
return NULL;
}
#endif
#if MEM_LIBC_MALLOC && (!LWIP_STATS || !MEM_STATS)
void *
mem_calloc(mem_size_t count, mem_size_t size)
{
return mem_clib_calloc(count, size);
}
#else
void *
mem_calloc(mem_size_t count, mem_size_t size)
{
void *p;
size_t alloc_size = (size_t)count * (size_t)size;
if ((size_t)(mem_size_t)alloc_size != alloc_size) {
LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("mem_calloc: could not allocate %"SZT_F" bytes\n", alloc_size));
return NULL;
}
p = mem_malloc((mem_size_t)alloc_size);
if (p) {
memset(p, 0, alloc_size);
}
return p;
}
#endif