Merge pull request #7418 from ejohnstown/generic-pool

Generic Memory Pools
This commit is contained in:
Sean Parkinson
2024-05-01 08:53:56 +10:00
committed by GitHub
4 changed files with 236 additions and 144 deletions

View File

@@ -2572,9 +2572,7 @@ int wolfSSL_CTX_load_static_memory(WOLFSSL_CTX** ctx,
wolfSSL_method_func method, unsigned char* buf, unsigned int sz, int flag,
int maxSz)
{
WOLFSSL_HEAP* heap;
WOLFSSL_HEAP_HINT* hint;
word32 idx = 0;
WOLFSSL_HEAP_HINT* hint = NULL;
if (ctx == NULL || buf == NULL) {
return BAD_FUNC_ARG;
@@ -2584,42 +2582,23 @@ int wolfSSL_CTX_load_static_memory(WOLFSSL_CTX** ctx,
return BAD_FUNC_ARG;
}
if (*ctx == NULL || (*ctx)->heap == NULL) {
if (sizeof(WOLFSSL_HEAP) + sizeof(WOLFSSL_HEAP_HINT) > sz - idx) {
return BUFFER_E; /* not enough memory for structures */
/* If there is a heap already, capture it in hint. */
if (*ctx && (*ctx)->heap != NULL) {
hint = (*ctx)->heap;
}
heap = (WOLFSSL_HEAP*)buf;
idx += sizeof(WOLFSSL_HEAP);
if (wolfSSL_init_memory_heap(heap) != 0) {
if (wc_LoadStaticMemory(&hint, buf, sz, flag, maxSz)) {
WOLFSSL_MSG("Error loading static memory");
return WOLFSSL_FAILURE;
}
hint = (WOLFSSL_HEAP_HINT*)(buf + idx);
idx += sizeof(WOLFSSL_HEAP_HINT);
XMEMSET(hint, 0, sizeof(WOLFSSL_HEAP_HINT));
hint->memory = heap;
if (*ctx && (*ctx)->heap == NULL) {
if (*ctx) {
if ((*ctx)->heap == NULL) {
(*ctx)->heap = (void*)hint;
}
}
else {
#ifdef WOLFSSL_HEAP_TEST
/* do not load in memory if test has been set */
if ((*ctx)->heap == (void*)WOLFSSL_HEAP_TEST) {
return WOLFSSL_SUCCESS;
}
#endif
hint = (WOLFSSL_HEAP_HINT*)((*ctx)->heap);
heap = hint->memory;
}
if (wolfSSL_load_static_memory(buf + idx, sz - idx, flag, heap) != 1) {
WOLFSSL_MSG("Error partitioning memory");
return WOLFSSL_FAILURE;
}
/* create ctx if needed */
if (*ctx == NULL) {
*ctx = wolfSSL_CTX_new_ex(method(hint), hint);
if (*ctx == NULL) {
WOLFSSL_MSG("Error creating ctx");
@@ -2627,19 +2606,6 @@ int wolfSSL_CTX_load_static_memory(WOLFSSL_CTX** ctx,
}
}
/* determine what max applies too */
if (flag & WOLFMEM_IO_POOL || flag & WOLFMEM_IO_POOL_FIXED) {
heap->maxIO = maxSz;
}
else { /* general memory used in handshakes */
heap->maxHa = maxSz;
}
heap->flag |= flag;
(void)maxSz;
(void)method;
return WOLFSSL_SUCCESS;
}

View File

@@ -672,6 +672,93 @@ static int test_wolfCrypt_Cleanup(void)
return EXPECT_RESULT();
}
static int test_wc_LoadStaticMemory_ex(void)
{
EXPECT_DECLS;
#ifdef WOLFSSL_STATIC_MEMORY
byte staticMemory[440000];
word32 sizeList[WOLFMEM_DEF_BUCKETS] = { WOLFMEM_BUCKETS };
word32 distList[WOLFMEM_DEF_BUCKETS] = { WOLFMEM_DIST };
WOLFSSL_HEAP_HINT* heap;
/* Pass in zero everything. */
ExpectIntEQ(wc_LoadStaticMemory_ex(NULL, 0, NULL, NULL, NULL, 0, 0, 0),
BAD_FUNC_ARG);
/* Set the heap pointer to NULL. */
ExpectIntEQ(wc_LoadStaticMemory_ex(NULL,
WOLFMEM_DEF_BUCKETS, sizeList, distList,
staticMemory, (word32)sizeof(staticMemory),
0, 1),
BAD_FUNC_ARG);
/* Set other pointer values to NULL one at a time. */
heap = NULL;
ExpectIntEQ(wc_LoadStaticMemory_ex(&heap,
WOLFMEM_DEF_BUCKETS, NULL, distList,
staticMemory, (word32)sizeof(staticMemory),
0, 1),
BAD_FUNC_ARG);
heap = NULL;
ExpectIntEQ(wc_LoadStaticMemory_ex(&heap,
WOLFMEM_DEF_BUCKETS, sizeList, NULL,
staticMemory, (word32)sizeof(staticMemory),
0, 1),
BAD_FUNC_ARG);
heap = NULL;
ExpectIntEQ(wc_LoadStaticMemory_ex(&heap,
WOLFMEM_DEF_BUCKETS, sizeList, distList,
NULL, (word32)sizeof(staticMemory),
0, 1),
BAD_FUNC_ARG);
/* Set the size of the static buffer to 0. */
heap = NULL;
ExpectIntEQ(wc_LoadStaticMemory_ex(&heap,
WOLFMEM_DEF_BUCKETS, sizeList, distList,
staticMemory, 0,
0, 1),
BUFFER_E);
/* Set the size of the static buffer to one less than minimum allowed. */
heap = NULL;
ExpectIntEQ(wc_LoadStaticMemory_ex(&heap,
WOLFMEM_DEF_BUCKETS, sizeList, distList,
staticMemory,
(word32)(sizeof(WOLFSSL_HEAP) + sizeof(WOLFSSL_HEAP_HINT)) - 1,
0, 1),
BUFFER_E);
/* Set the number of buckets to 1 too many allowed. */
heap = NULL;
ExpectIntEQ(wc_LoadStaticMemory_ex(&heap,
WOLFMEM_MAX_BUCKETS+1, sizeList, distList,
staticMemory, (word32)sizeof(staticMemory),
0, 1),
BAD_FUNC_ARG);
/* Set the size of the static buffer to exactly the minimum size. */
heap = NULL;
ExpectIntEQ(wc_LoadStaticMemory_ex(&heap,
WOLFMEM_DEF_BUCKETS, sizeList, distList,
staticMemory,
(word32)(sizeof(WOLFSSL_HEAP) + sizeof(WOLFSSL_HEAP_HINT)),
0, 1),
0);
wc_UnloadStaticMemory(heap);
/* Success case. */
heap = NULL;
ExpectIntEQ(wc_LoadStaticMemory_ex(&heap,
WOLFMEM_DEF_BUCKETS, sizeList, distList,
staticMemory, (word32)sizeof(staticMemory),
0, 1),
0);
wc_UnloadStaticMemory(heap);
#endif /* WOLFSSL_STATIC_MEMORY */
return EXPECT_RESULT();
}
/*----------------------------------------------------------------------------*
| Platform dependent function test
*----------------------------------------------------------------------------*/
@@ -71571,6 +71658,8 @@ TEST_CASE testCases[] = {
TEST_DECL(test_wolfCrypt_Init),
TEST_DECL(test_wc_LoadStaticMemory_ex),
/* Locking with Compat Mutex */
TEST_DECL(test_wc_SetMutexCb),
TEST_DECL(test_wc_LockMutex_ex),

View File

@@ -521,7 +521,7 @@ struct wc_Memory {
/* returns amount of memory used on success. On error returns negative value
wc_Memory** list is the list that new buckets are prepended to
*/
static int create_memory_buckets(byte* buffer, word32 bufSz,
static int wc_create_memory_buckets(byte* buffer, word32 bufSz,
word32 buckSz, word32 buckNum, wc_Memory** list) {
word32 i;
byte* pt = buffer;
@@ -562,19 +562,79 @@ static int create_memory_buckets(byte* buffer, word32 bufSz,
return ret;
}
int wolfSSL_init_memory_heap(WOLFSSL_HEAP* heap)
static int wc_partition_static_memory(byte* buffer, word32 sz, int flag,
WOLFSSL_HEAP* heap)
{
word32 wc_MemSz[WOLFMEM_DEF_BUCKETS] = { WOLFMEM_BUCKETS };
word32 wc_Dist[WOLFMEM_DEF_BUCKETS] = { WOLFMEM_DIST };
word32 ava = sz;
byte* pt = buffer;
int ret = 0;
word32 memSz = (word32)sizeof(wc_Memory);
word32 padSz = -(int)memSz & (WOLFSSL_STATIC_ALIGN - 1);
if (heap == NULL) {
return BAD_FUNC_ARG;
WOLFSSL_ENTER("wc_partition_static_memory");
/* align pt */
while ((wc_ptr_t)pt % WOLFSSL_STATIC_ALIGN && pt < (buffer + sz)) {
*pt = 0x00;
pt++;
ava--;
}
#ifdef WOLFSSL_DEBUG_MEMORY
fprintf(stderr, "Allocated %d bytes for static memory @ %p\n", ava, pt);
#endif
/* divide into chunks of memory and add them to available list */
while (ava >= (heap->sizeList[0] + padSz + memSz)) {
/* creating only IO buffers from memory passed in, max TLS is 16k */
if (flag & WOLFMEM_IO_POOL || flag & WOLFMEM_IO_POOL_FIXED) {
if ((ret = wc_create_memory_buckets(pt, ava,
WOLFMEM_IO_SZ, 1, &(heap->io))) < 0) {
WOLFSSL_LEAVE("wc_partition_static_memory", ret);
return ret;
}
/* check if no more room left for creating IO buffers */
if (ret == 0) {
break;
}
/* advance pointer in buffer for next buckets and keep track
of how much memory is left available */
pt += ret;
ava -= ret;
}
else {
int i;
/* start at largest and move to smaller buckets */
for (i = (WOLFMEM_MAX_BUCKETS - 1); i >= 0; i--) {
if ((heap->sizeList[i] + padSz + memSz) <= ava) {
if ((ret = wc_create_memory_buckets(pt, ava,
heap->sizeList[i], heap->distList[i],
&(heap->ava[i]))) < 0) {
WOLFSSL_LEAVE("wc_partition_static_memory", ret);
return ret;
}
/* advance pointer in buffer for next buckets and keep track
of how much memory is left available */
pt += ret;
ava -= ret;
}
}
}
}
return 1;
}
static int wc_init_memory_heap(WOLFSSL_HEAP* heap, unsigned int listSz,
const unsigned int* sizeList, const unsigned int* distList)
{
XMEMSET(heap, 0, sizeof(WOLFSSL_HEAP));
XMEMCPY(heap->sizeList, wc_MemSz, sizeof(wc_MemSz));
XMEMCPY(heap->distList, wc_Dist, sizeof(wc_Dist));
XMEMCPY(heap->sizeList, sizeList, listSz * sizeof(sizeList[0]));
XMEMCPY(heap->distList, distList, listSz * sizeof(distList[0]));
if (wc_InitMutex(&(heap->memory_mutex)) != 0) {
WOLFSSL_MSG("Error creating heap memory mutex");
@@ -584,19 +644,25 @@ int wolfSSL_init_memory_heap(WOLFSSL_HEAP* heap)
return 0;
}
int wc_LoadStaticMemory(WOLFSSL_HEAP_HINT** pHint,
unsigned char* buf, unsigned int sz, int flag, int maxSz)
int wc_LoadStaticMemory_ex(WOLFSSL_HEAP_HINT** pHint,
unsigned int listSz, const unsigned int* sizeList,
const unsigned int* distList, unsigned char* buf,
unsigned int sz, int flag, int maxSz)
{
int ret;
WOLFSSL_HEAP* heap;
WOLFSSL_HEAP_HINT* hint;
WOLFSSL_HEAP* heap = NULL;
WOLFSSL_HEAP_HINT* hint = NULL;
word32 idx = 0;
int ret;
if (pHint == NULL || buf == NULL) {
WOLFSSL_ENTER("wc_LoadStaticMemory_ex");
if (pHint == NULL || buf == NULL || listSz > WOLFMEM_MAX_BUCKETS
|| sizeList == NULL || distList == NULL) {
return BAD_FUNC_ARG;
}
if ((sizeof(WOLFSSL_HEAP) + sizeof(WOLFSSL_HEAP_HINT)) > sz - idx) {
WOLFSSL_MSG("Not enough memory for partition tracking");
return BUFFER_E; /* not enough memory for structures */
}
@@ -607,7 +673,7 @@ int wc_LoadStaticMemory(WOLFSSL_HEAP_HINT** pHint,
hint = (WOLFSSL_HEAP_HINT*)(buf + idx);
idx += sizeof(WOLFSSL_HEAP_HINT);
ret = wolfSSL_init_memory_heap(heap);
ret = wc_init_memory_heap(heap, listSz, sizeList, distList);
if (ret != 0) {
return ret;
}
@@ -627,10 +693,10 @@ int wc_LoadStaticMemory(WOLFSSL_HEAP_HINT** pHint,
heap = hint->memory;
}
ret = wolfSSL_load_static_memory(buf + idx, sz - idx, flag, heap);
ret = wc_partition_static_memory(buf + idx, sz - idx, flag, heap);
if (ret != 1) {
WOLFSSL_MSG("Error partitioning memory");
return -1;
return MEMORY_E;
}
/* determine what max applies too */
@@ -644,78 +710,31 @@ int wc_LoadStaticMemory(WOLFSSL_HEAP_HINT** pHint,
heap->flag |= flag;
*pHint = hint;
(void)maxSz;
return 0;
}
int wolfSSL_load_static_memory(byte* buffer, word32 sz, int flag,
WOLFSSL_HEAP* heap)
int wc_LoadStaticMemory(WOLFSSL_HEAP_HINT** pHint,
unsigned char* buf, unsigned int sz, int flag, int maxSz)
{
word32 ava = sz;
byte* pt = buffer;
word32 sizeList[WOLFMEM_DEF_BUCKETS] = { WOLFMEM_BUCKETS };
word32 distList[WOLFMEM_DEF_BUCKETS] = { WOLFMEM_DIST };
int ret = 0;
word32 memSz = (word32)sizeof(wc_Memory);
word32 padSz = -(int)memSz & (WOLFSSL_STATIC_ALIGN - 1);
WOLFSSL_ENTER("wolfSSL_load_static_memory");
if (buffer == NULL) {
return BAD_FUNC_ARG;
}
/* align pt */
while ((wc_ptr_t)pt % WOLFSSL_STATIC_ALIGN && pt < (buffer + sz)) {
*pt = 0x00;
pt++;
ava--;
}
#ifdef WOLFSSL_DEBUG_MEMORY
fprintf(stderr, "Allocated %d bytes for static memory @ %p\n", ava, pt);
#endif
/* divide into chunks of memory and add them to available list */
while (ava >= (heap->sizeList[0] + padSz + memSz)) {
/* creating only IO buffers from memory passed in, max TLS is 16k */
if (flag & WOLFMEM_IO_POOL || flag & WOLFMEM_IO_POOL_FIXED) {
if ((ret = create_memory_buckets(pt, ava,
WOLFMEM_IO_SZ, 1, &(heap->io))) < 0) {
WOLFSSL_LEAVE("wolfSSL_load_static_memory", ret);
WOLFSSL_ENTER("wc_LoadStaticMemory");
ret = wc_LoadStaticMemory_ex(pHint,
WOLFMEM_DEF_BUCKETS, sizeList, distList,
buf, sz, flag, maxSz);
WOLFSSL_LEAVE("wc_LoadStaticMemory", ret);
return ret;
}
/* check if no more room left for creating IO buffers */
if (ret == 0) {
break;
}
/* advance pointer in buffer for next buckets and keep track
of how much memory is left available */
pt += ret;
ava -= ret;
void wc_UnloadStaticMemory(WOLFSSL_HEAP_HINT* heap)
{
WOLFSSL_ENTER("wc_UnloadStaticMemory");
if (heap != NULL && heap->memory != NULL) {
wc_FreeMutex(&heap->memory->memory_mutex);
}
else {
int i;
/* start at largest and move to smaller buckets */
for (i = (WOLFMEM_MAX_BUCKETS - 1); i >= 0; i--) {
if ((heap->sizeList[i] + padSz + memSz) <= ava) {
if ((ret = create_memory_buckets(pt, ava, heap->sizeList[i],
heap->distList[i], &(heap->ava[i]))) < 0) {
WOLFSSL_LEAVE("wolfSSL_load_static_memory", ret);
return ret;
}
/* advance pointer in buffer for next buckets and keep track
of how much memory is left available */
pt += ret;
ava -= ret;
}
}
}
}
return 1;
}
@@ -731,19 +750,19 @@ int wolfSSL_MemoryPaddingSz(void)
/* Used to calculate memory size for optimum use with buckets.
returns the suggested size rounded down to the nearest bucket. */
int wolfSSL_StaticBufferSz(byte* buffer, word32 sz, int flag)
int wolfSSL_StaticBufferSz_ex(unsigned int listSz,
const unsigned int *sizeList, const unsigned int *distList,
byte* buffer, word32 sz, int flag)
{
word32 bucketSz[WOLFMEM_MAX_BUCKETS] = {WOLFMEM_BUCKETS};
word32 distList[WOLFMEM_MAX_BUCKETS] = {WOLFMEM_DIST};
word32 ava = sz;
byte* pt = buffer;
word32 memSz = (word32)sizeof(wc_Memory);
word32 padSz = -(int)memSz & (WOLFSSL_STATIC_ALIGN - 1);
WOLFSSL_ENTER("wolfSSL_static_size");
WOLFSSL_ENTER("wolfSSL_StaticBufferSz_ex");
if (buffer == NULL) {
if (buffer == NULL || listSz > WOLFMEM_MAX_BUCKETS
|| sizeList == NULL || distList == NULL) {
return BAD_FUNC_ARG;
}
@@ -764,26 +783,39 @@ int wolfSSL_StaticBufferSz(byte* buffer, word32 sz, int flag)
else {
int i, k;
if (ava < (bucketSz[0] + padSz + memSz)) {
if (ava < (sizeList[0] + padSz + memSz)) {
return 0; /* not enough room for even one bucket */
}
while ((ava >= (bucketSz[0] + padSz + memSz)) && (ava > 0)) {
while ((ava >= (sizeList[0] + padSz + memSz)) && (ava > 0)) {
/* start at largest and move to smaller buckets */
for (i = (WOLFMEM_MAX_BUCKETS - 1); i >= 0; i--) {
for (i = (listSz - 1); i >= 0; i--) {
for (k = distList[i]; k > 0; k--) {
if ((bucketSz[i] + padSz + memSz) <= ava) {
ava -= bucketSz[i] + padSz + memSz;
if ((sizeList[i] + padSz + memSz) <= ava) {
ava -= sizeList[i] + padSz + memSz;
}
}
}
}
}
WOLFSSL_LEAVE("wolfSSL_StaticBufferSz_ex", sz - ava);
return sz - ava; /* round down */
}
/* Calls wolfSSL_StaticBufferSz_ex with the static memory pool config
* used by wolfSSL by default. */
int wolfSSL_StaticBufferSz(byte* buffer, word32 sz, int flag)
{
word32 bucketSz[WOLFMEM_DEF_BUCKETS] = {WOLFMEM_BUCKETS};
word32 distList[WOLFMEM_DEF_BUCKETS] = {WOLFMEM_DIST};
return wolfSSL_StaticBufferSz_ex(WOLFMEM_DEF_BUCKETS, bucketSz, distList,
buffer, sz, flag);
}
int FreeFixedIO(WOLFSSL_HEAP* heap, wc_Memory** io)
{
WOLFSSL_MSG("Freeing fixed IO buffer");

View File

@@ -216,17 +216,22 @@ WOLFSSL_API int wolfSSL_GetAllocators(wolfSSL_Malloc_cb* mf,
byte haFlag; /* flag used for checking handshake count */
} WOLFSSL_HEAP_HINT;
WOLFSSL_API int wc_LoadStaticMemory_ex(WOLFSSL_HEAP_HINT** pHint,
unsigned int listSz, const unsigned int *sizeList,
const unsigned int *distList, unsigned char* buf, unsigned int sz,
int flag, int max);
WOLFSSL_API int wc_LoadStaticMemory(WOLFSSL_HEAP_HINT** pHint,
unsigned char* buf, unsigned int sz, int flag, int max);
WOLFSSL_API void wc_UnloadStaticMemory(WOLFSSL_HEAP_HINT* heap);
WOLFSSL_LOCAL int wolfSSL_init_memory_heap(WOLFSSL_HEAP* heap);
WOLFSSL_LOCAL int wolfSSL_load_static_memory(byte* buffer, word32 sz,
int flag, WOLFSSL_HEAP* heap);
WOLFSSL_LOCAL int wolfSSL_GetMemStats(WOLFSSL_HEAP* heap,
WOLFSSL_API int wolfSSL_GetMemStats(WOLFSSL_HEAP* heap,
WOLFSSL_MEM_STATS* stats);
WOLFSSL_LOCAL int SetFixedIO(WOLFSSL_HEAP* heap, wc_Memory** io);
WOLFSSL_LOCAL int FreeFixedIO(WOLFSSL_HEAP* heap, wc_Memory** io);
WOLFSSL_API int wolfSSL_StaticBufferSz_ex(unsigned int listSz,
const unsigned int *sizeList, const unsigned int *distList,
byte* buffer, word32 sz, int flag);
WOLFSSL_API int wolfSSL_StaticBufferSz(byte* buffer, word32 sz, int flag);
WOLFSSL_API int wolfSSL_MemoryPaddingSz(void);
#endif /* WOLFSSL_STATIC_MEMORY */