From 160d0d11c1075fe700f91231ee37a57c9bd6259b Mon Sep 17 00:00:00 2001 From: Sameeh Jubran Date: Tue, 8 Sep 2026 12:28:08 +0300 Subject: [PATCH 1/2] memory: do not count a failed allocation under WOLFSSL_MEM_FAIL_COUNT wc_MemFailCount_AllocMem() increments mem_fail_allocs before the registered allocator runs. When a caller-installed failing allocator (via wolfSSL_SetAllocators(), used by several OOM unit tests) or a genuine out-of-memory returns NULL, the allocation is counted but no block exists to free. The mem-fail nightly then reports a spurious "Free/Alloc mismatch" (Total one higher than Frees), even in the baseline counting phase, which is why it repeats identically across shards. Undo the count when the allocator returns NULL so Total stays balanced with Frees. The injected-failure path returns before the allocator is called and so is unaffected. All changes are under WOLFSSL_MEM_FAIL_COUNT and do not affect production builds. Signed-off-by: Sameeh Jubran --- wolfcrypt/src/memory.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/wolfcrypt/src/memory.c b/wolfcrypt/src/memory.c index 4c02e3f2002..bba28087247 100644 --- a/wolfcrypt/src/memory.c +++ b/wolfcrypt/src/memory.c @@ -162,6 +162,19 @@ static int wc_MemFailCount_AllocMem(void) return ret; } +/* An allocation was counted by wc_MemFailCount_AllocMem() above, but the + * underlying allocator then returned NULL (a caller-installed failing + * allocator via wolfSSL_SetAllocators(), or a genuine out-of-memory). No + * block exists to be freed, so undo the count to keep Total (allocs) + * balanced with Frees. */ +static void wc_MemFailCount_AllocFailed(void) +{ + wc_LockMutex(&memFailMutex); + if (mem_fail_allocs > 0) { + mem_fail_allocs--; + } + wc_UnLockMutex(&memFailMutex); +} static void wc_MemFailCount_FreeMem(void) { wc_LockMutex(&memFailMutex); @@ -406,10 +419,19 @@ void* wolfSSL_Malloc(size_t size) free(res); /* native heap */ } gMemFailCount = gMemFailCountSeed; /* reset */ + #ifdef WOLFSSL_MEM_FAIL_COUNT + wc_MemFailCount_AllocFailed(); + #endif return NULL; } #endif +#ifdef WOLFSSL_MEM_FAIL_COUNT + if (res == NULL) { + wc_MemFailCount_AllocFailed(); + } +#endif + return res; } From a1dd273bc8c8c0c7e02130da7c8ed015b398dc19 Mon Sep 17 00:00:00 2001 From: Sameeh Jubran Date: Tue, 8 Sep 2026 12:29:34 +0300 Subject: [PATCH 2/2] tests: restore SSL-owned cert buffers in test_ProcessChainOCSPRequest_bounds The first test vector nulls ssl->buffers.certChain and ssl->buffers.certificate to drive the "chain == NULL" path of ProcessChainOCSPRequest(). The SSL owns the certificate DER copy that wolfSSL_new() allocated (weOwnCert), so clearing the pointer outright leaked 1536 bytes and the mem-fail nightly reported a Free/Alloc mismatch. Save the owned buffers, clear them for the call under test, then restore them so wolfSSL_free() releases them. Signed-off-by: Sameeh Jubran --- tests/api/test_tls_bounds.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tests/api/test_tls_bounds.c b/tests/api/test_tls_bounds.c index da3befb3784..7c0456ebaed 100644 --- a/tests/api/test_tls_bounds.c +++ b/tests/api/test_tls_bounds.c @@ -1466,6 +1466,8 @@ int test_ProcessChainOCSPRequest_bounds(void) ExpectNotNull(ssl = wolfSSL_new(ctx)); if (ssl != NULL) { TLSX* ext = NULL; + DerBuffer* savedCert = ssl->buffers.certificate; + DerBuffer* savedChain = ssl->buffers.certChain; ExpectIntEQ(TLSX_UseCertificateStatusRequest(&ssl->extensions, WOLFSSL_CSR_OCSP, 0, ssl, ssl->heap, ssl->devId), WOLFSSL_SUCCESS); @@ -1475,10 +1477,14 @@ int test_ProcessChainOCSPRequest_bounds(void) /* A certificate had to be loaded for wolfSSL_new() to succeed (see * test_tls_bounds_load_server_cert()); clear both buffers back to * NULL so ProcessChainOCSPRequest() sees exactly the "chain == - * NULL" state under test. */ + * NULL" state under test. The SSL owns these buffers (weOwnCert), + * so save and restore them - nulling them outright leaked the DER + * copy that wolfSSL_new() allocated. */ ssl->buffers.certChain = NULL; ssl->buffers.certificate = NULL; ExpectIntEQ(ProcessChainOCSPRequest(ssl), 0); + ssl->buffers.certificate = savedCert; + ssl->buffers.certChain = savedChain; } wolfSSL_free(ssl); ssl = NULL;