Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions .github/workflows/freertos-mem-track.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
name: FreeRTOS mem_track.h compile regression

# START OF COMMON SECTION
on:
push:
branches: [ 'master', 'main', 'release/**' ]
pull_request:
branches: [ '*' ]

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
# END OF COMMON SECTION

# Regression test for the memLock / pthread.h guard misalignment in
# wolfssl/wolfcrypt/mem_track.h that previously broke multi-threaded
# FreeRTOS-class builds with WOLFSSL_TRACK_MEMORY + USE_WOLFSSL_MEMORY
# + !WOLFSSL_STATIC_MEMORY. The bug was preprocessor-only, so the test
# simulates a non-Linux/Mac/Zephyr target by suppressing the host
# platform autodefines (-U__linux__ -U__MACH__ -U__ZEPHYR__) and using
# the clean-room FreeRTOS.h / semphr.h stubs under
# tests/freertos-mem-track-repro/. No cross compiler needed.

jobs:
freertos_mem_track:
name: mem_track.h non-Linux multi-threaded compile
if: github.repository_owner == 'wolfssl'
runs-on: ubuntu-24.04
timeout-minutes: 5
steps:
- name: Checkout wolfSSL
uses: actions/checkout@v4

- name: Run mem_track.h FreeRTOS reproducer
run: sh tests/freertos-mem-track-repro/run.sh
38 changes: 38 additions & 0 deletions tests/freertos-mem-track-repro/FreeRTOS.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/* FreeRTOS.h
*
* Copyright (C) 2006-2026 wolfSSL Inc.
*
* This file is part of wolfSSL.
*
* wolfSSL is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* wolfSSL is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
*/

/* Stub FreeRTOS.h for the mem_track.h reproducer.
*
* Provides the minimum typedefs the wolfSSL header chain needs while
* pretending to be a non-Linux multi-threaded FreeRTOS target. */
#ifndef WOLFSSL_REPRO_FREERTOS_H
#define WOLFSSL_REPRO_FREERTOS_H

typedef void *SemaphoreHandle_t;
typedef void *xSemaphoreHandle;
typedef void *TaskHandle_t;

/* mem_track.h calls these directly under #ifdef FREERTOS. Declarations
* only; the test compiles -c and never links. */
extern void *pvPortMalloc(unsigned long size);
extern void vPortFree(void *ptr);

#endif
30 changes: 30 additions & 0 deletions tests/freertos-mem-track-repro/repro.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/* repro.c
*
* Copyright (C) 2006-2026 wolfSSL Inc.
*
* This file is part of wolfSSL.
*
* wolfSSL is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* wolfSSL is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
*/

/* Reproduces the memLock / pthread.h compile failure reported by the
* FreeRTOS/Xtensa customer in wolfSSL 5.9.1. The bug is preprocessor-only
* so it triggers on any host once __linux__/__MACH__/__ZEPHYR__ are
* suppressed via -U flags. WOLFSSL_USER_SETTINGS is supplied by run.sh. */
#include "user_settings.h"
#include "wolfssl/wolfcrypt/settings.h"
#include "wolfssl/wolfcrypt/mem_track.h"

int main(void) { return 0; }
48 changes: 48 additions & 0 deletions tests/freertos-mem-track-repro/run.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#!/bin/sh
# run.sh
#
# Copyright (C) 2006-2026 wolfSSL Inc.
#
# This file is part of wolfSSL.
#
# wolfSSL is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# wolfSSL is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA

# Regression test for the mem_track.h memLock guard misalignment that
# previously broke multi-threaded FreeRTOS-class builds with
# WOLFSSL_TRACK_MEMORY + USE_WOLFSSL_MEMORY + !WOLFSSL_STATIC_MEMORY.
#
# The bug is preprocessor-only, so the test runs on a stock Linux host:
# -U__linux__ -U__MACH__ -U__ZEPHYR__ suppresses the host autodefines
# that would otherwise hide it. Stub FreeRTOS.h / semphr.h satisfy the
# wc_port.h FREERTOS_TCP mutex typedef without needing a real RTOS.
#
# Exit 0 = mem_track.h still compiles in the non-Linux multi-threaded
# config, i.e. the fix is in place. Exit non-zero = the misalignment is
# back. Run from the wolfssl repo root.
set -u
cc -DWOLFSSL_USER_SETTINGS \
-U__linux__ -U__MACH__ -U__ZEPHYR__ \
-I tests/freertos-mem-track-repro \
-I . \
-c tests/freertos-mem-track-repro/repro.c \
-o /dev/null
status=$?
if [ $status -eq 0 ]; then
echo "OK: mem_track.h compiles for non-Linux multi-threaded config."
else
echo "FAIL: mem_track.h compile broken for non-Linux multi-threaded" >&2
echo " config - the memLock guard misalignment may be back." >&2
fi
exit $status
26 changes: 26 additions & 0 deletions tests/freertos-mem-track-repro/semphr.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/* semphr.h
*
* Copyright (C) 2006-2026 wolfSSL Inc.
*
* This file is part of wolfSSL.
*
* wolfSSL is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* wolfSSL is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
*/

/* Stub semphr.h for the mem_track.h reproducer. SemaphoreHandle_t is
* declared in the stub FreeRTOS.h. */
#ifndef WOLFSSL_REPRO_SEMPHR_H
#define WOLFSSL_REPRO_SEMPHR_H
#endif
27 changes: 27 additions & 0 deletions tests/freertos-mem-track-repro/task.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/* task.h
*
* Copyright (C) 2006-2026 wolfSSL Inc.
*
* This file is part of wolfSSL.
*
* wolfSSL is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* wolfSSL is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
*/

/* Stub task.h for the mem_track.h reproducer. The wolfSSL header chain
* includes this when FREERTOS is defined; we don't need any of the real
* task API to reach the mem_track.h code under test. */
#ifndef WOLFSSL_REPRO_TASK_H
#define WOLFSSL_REPRO_TASK_H
#endif
38 changes: 38 additions & 0 deletions tests/freertos-mem-track-repro/user_settings.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/* user_settings.h
*
* Copyright (C) 2006-2026 wolfSSL Inc.
*
* This file is part of wolfSSL.
*
* wolfSSL is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* wolfSSL is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
*/

/* Minimal user_settings.h reproducing the bug state. */
#ifndef WOLFSSL_FREERTOS_MEM_TRACK_REPRO_USER_SETTINGS_H
#define WOLFSSL_FREERTOS_MEM_TRACK_REPRO_USER_SETTINGS_H

#define FREERTOS
#define FREERTOS_TCP
#define NO_FILESYSTEM
#define WOLFSSL_NO_SOCK
#define USE_WOLFSSL_MEMORY
#define WOLFSSL_TRACK_MEMORY
#define WOLFSSL_DEBUG_MEMORY
#define WOLFSSL_DEBUG_MEMORY_PRINT
#define DEBUG_WOLFSSL

/* Intentionally NOT defined: SINGLE_THREADED, WOLFSSL_STATIC_MEMORY */

#endif
8 changes: 7 additions & 1 deletion tests/include.am
Original file line number Diff line number Diff line change
Expand Up @@ -88,5 +88,11 @@ EXTRA_DIST += tests/unit.h \
tests/emnet/IP/IP.h \
tests/emnet/emnet_shim.c \
tests/emnet/emnet_nonblock_test.c \
tests/emnet/Makefile
tests/emnet/Makefile \
tests/freertos-mem-track-repro/user_settings.h \
tests/freertos-mem-track-repro/repro.c \
tests/freertos-mem-track-repro/FreeRTOS.h \
tests/freertos-mem-track-repro/semphr.h \
tests/freertos-mem-track-repro/task.h \
tests/freertos-mem-track-repro/run.sh
DISTCLEANFILES+= tests/.libs/unit.test
56 changes: 42 additions & 14 deletions wolfssl/wolfcrypt/mem_track.h
Original file line number Diff line number Diff line change
Expand Up @@ -142,9 +142,12 @@ static memoryStats ourMemStats;
WOLFSSL_API extern memoryStats *wc_MemStats_Ptr;

#ifdef DO_MEM_LIST
#include <pthread.h>
static memoryList ourMemList;
static pthread_mutex_t memLock = PTHREAD_MUTEX_INITIALIZER;
#endif

#if !defined(SINGLE_THREADED) && (defined(DO_MEM_LIST) || defined(DO_MEM_STATS))
static wolfSSL_Mutex memLock;
static int memLockInit = 0;
#endif

#ifdef WOLFSSL_DEBUG_MEMORY
Expand Down Expand Up @@ -182,7 +185,7 @@ static WC_INLINE void* TrackMalloc(size_t sz)
#endif
#endif
#if !defined(SINGLE_THREADED) && (defined(DO_MEM_LIST) || defined(DO_MEM_STATS))
if (pthread_mutex_lock(&memLock) == 0)
if (wc_LockMutex(&memLock) == 0)
{
#endif

Expand Down Expand Up @@ -228,9 +231,9 @@ static WC_INLINE void* TrackMalloc(size_t sz)
ourMemList.count++;
#endif
#if !defined(SINGLE_THREADED) && (defined(DO_MEM_LIST) || defined(DO_MEM_STATS))
pthread_mutex_unlock(&memLock);
wc_UnLockMutex(&memLock);
}
#endif /* DO_MEM_LIST */
#endif /* !SINGLE_THREADED && (DO_MEM_LIST || DO_MEM_STATS) */

return header->thisMemory;
}
Expand All @@ -255,7 +258,7 @@ static WC_INLINE void TrackFree(void* ptr)
sz = header->thisSize;

#if !defined(SINGLE_THREADED) && (defined(DO_MEM_LIST) || defined(DO_MEM_STATS))
if (pthread_mutex_lock(&memLock) == 0)
if (wc_LockMutex(&memLock) == 0)
{
#endif

Expand Down Expand Up @@ -289,7 +292,7 @@ static WC_INLINE void TrackFree(void* ptr)
#endif

#if !defined(SINGLE_THREADED) && (defined(DO_MEM_LIST) || defined(DO_MEM_STATS))
pthread_mutex_unlock(&memLock);
wc_UnLockMutex(&memLock);
}
#endif

Expand Down Expand Up @@ -362,14 +365,27 @@ static WC_INLINE int InitMemoryTracker(void)
if (ret < 0) {
wc_mem_printf("wolfSSL GetAllocators failed to get the defaults\n");
}

#if !defined(SINGLE_THREADED) && (defined(DO_MEM_LIST) || defined(DO_MEM_STATS))
/* Init the mutex before installing the tracking allocators, so the
* mutex is ready as soon as another thread can enter TrackMalloc. */
if (!memLockInit) {
if (wc_InitMutex(&memLock) != 0) {
wc_mem_printf("wc_InitMutex failed for track memory\n");
return -1;
}
memLockInit = 1;
}
#endif

ret = wolfSSL_SetAllocators(TrackMalloc, TrackFree, TrackRealloc);
if (ret < 0) {
wc_mem_printf("wolfSSL SetAllocators failed for track memory\n");
return ret;
}

#ifdef DO_MEM_LIST
if (pthread_mutex_lock(&memLock) == 0)
#if !defined(SINGLE_THREADED) && (defined(DO_MEM_LIST) || defined(DO_MEM_STATS))
if (wc_LockMutex(&memLock) == 0)
#endif
{
#ifdef DO_MEM_STATS
Expand All @@ -387,8 +403,11 @@ static WC_INLINE int InitMemoryTracker(void)
#ifdef DO_MEM_LIST
XMEMSET(&ourMemList, 0, sizeof(ourMemList));
ourMemStats.memList = &ourMemList;
#endif

pthread_mutex_unlock(&memLock);
#if !defined(SINGLE_THREADED) && \
(defined(DO_MEM_LIST) || defined(DO_MEM_STATS))
wc_UnLockMutex(&memLock);
#endif
}

Expand All @@ -399,8 +418,8 @@ static WC_INLINE int InitMemoryTracker(void)

static WC_INLINE void ShowMemoryTracker(void)
{
#ifdef DO_MEM_LIST
if (pthread_mutex_lock(&memLock) == 0)
#if !defined(SINGLE_THREADED) && (defined(DO_MEM_LIST) || defined(DO_MEM_STATS))
if (wc_LockMutex(&memLock) == 0)
#endif
{
#ifdef DO_MEM_STATS
Expand Down Expand Up @@ -429,16 +448,25 @@ static WC_INLINE void ShowMemoryTracker(void)
#endif
}
}
#endif

pthread_mutex_unlock(&memLock);
#if !defined(SINGLE_THREADED) && \
(defined(DO_MEM_LIST) || defined(DO_MEM_STATS))
wc_UnLockMutex(&memLock);
#endif
}
}

static WC_INLINE int CleanupMemoryTracker(void)
{
wc_MemStats_Ptr = NULL;
/* restore default allocators */
/* Restore default allocators. memLock is intentionally left
* initialized for process lifetime (matching the prior static
* PTHREAD_MUTEX_INITIALIZER behavior): SetAllocators stops new
* entries into TrackMalloc/TrackFree but does not synchronize
* with in-flight calls, so freeing the mutex here would be a
* use-after-free hazard. The memLockInit flag keeps re-Init
* idempotent across an Init/Cleanup/Init cycle. */
return wolfSSL_SetAllocators(mfDefault, ffDefault, rfDefault);
}
#endif /* WOLFSSL_TRACK_MEMORY && USE_WOLFSSL_MEMORY && \
Expand Down
Loading