Skip to content

Commit 4438615

Browse files
authored
Merge pull request #10453 from LinuxJedi/fix-memtrack
Fix mem_track.h compile failure on multi-threaded non-Linux builds
2 parents a2b054e + 7b89d82 commit 4438615

9 files changed

Lines changed: 291 additions & 15 deletions

File tree

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
name: FreeRTOS mem_track.h compile regression
2+
3+
# START OF COMMON SECTION
4+
on:
5+
push:
6+
branches: [ 'master', 'main', 'release/**' ]
7+
pull_request:
8+
branches: [ '*' ]
9+
10+
concurrency:
11+
group: ${{ github.workflow }}-${{ github.ref }}
12+
cancel-in-progress: true
13+
# END OF COMMON SECTION
14+
15+
# Regression test for the memLock / pthread.h guard misalignment in
16+
# wolfssl/wolfcrypt/mem_track.h that previously broke multi-threaded
17+
# FreeRTOS-class builds with WOLFSSL_TRACK_MEMORY + USE_WOLFSSL_MEMORY
18+
# + !WOLFSSL_STATIC_MEMORY. The bug was preprocessor-only, so the test
19+
# simulates a non-Linux/Mac/Zephyr target by suppressing the host
20+
# platform autodefines (-U__linux__ -U__MACH__ -U__ZEPHYR__) and using
21+
# the clean-room FreeRTOS.h / semphr.h stubs under
22+
# tests/freertos-mem-track-repro/. No cross compiler needed.
23+
24+
jobs:
25+
freertos_mem_track:
26+
name: mem_track.h non-Linux multi-threaded compile
27+
if: github.repository_owner == 'wolfssl'
28+
runs-on: ubuntu-24.04
29+
timeout-minutes: 5
30+
steps:
31+
- name: Checkout wolfSSL
32+
uses: actions/checkout@v4
33+
34+
- name: Run mem_track.h FreeRTOS reproducer
35+
run: sh tests/freertos-mem-track-repro/run.sh
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/* FreeRTOS.h
2+
*
3+
* Copyright (C) 2006-2026 wolfSSL Inc.
4+
*
5+
* This file is part of wolfSSL.
6+
*
7+
* wolfSSL is free software; you can redistribute it and/or modify
8+
* it under the terms of the GNU General Public License as published by
9+
* the Free Software Foundation; either version 3 of the License, or
10+
* (at your option) any later version.
11+
*
12+
* wolfSSL is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
* GNU General Public License for more details.
16+
*
17+
* You should have received a copy of the GNU General Public License
18+
* along with this program; if not, write to the Free Software
19+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
20+
*/
21+
22+
/* Stub FreeRTOS.h for the mem_track.h reproducer.
23+
*
24+
* Provides the minimum typedefs the wolfSSL header chain needs while
25+
* pretending to be a non-Linux multi-threaded FreeRTOS target. */
26+
#ifndef WOLFSSL_REPRO_FREERTOS_H
27+
#define WOLFSSL_REPRO_FREERTOS_H
28+
29+
typedef void *SemaphoreHandle_t;
30+
typedef void *xSemaphoreHandle;
31+
typedef void *TaskHandle_t;
32+
33+
/* mem_track.h calls these directly under #ifdef FREERTOS. Declarations
34+
* only; the test compiles -c and never links. */
35+
extern void *pvPortMalloc(unsigned long size);
36+
extern void vPortFree(void *ptr);
37+
38+
#endif
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/* repro.c
2+
*
3+
* Copyright (C) 2006-2026 wolfSSL Inc.
4+
*
5+
* This file is part of wolfSSL.
6+
*
7+
* wolfSSL is free software; you can redistribute it and/or modify
8+
* it under the terms of the GNU General Public License as published by
9+
* the Free Software Foundation; either version 3 of the License, or
10+
* (at your option) any later version.
11+
*
12+
* wolfSSL is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
* GNU General Public License for more details.
16+
*
17+
* You should have received a copy of the GNU General Public License
18+
* along with this program; if not, write to the Free Software
19+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
20+
*/
21+
22+
/* Reproduces the memLock / pthread.h compile failure reported by the
23+
* FreeRTOS/Xtensa customer in wolfSSL 5.9.1. The bug is preprocessor-only
24+
* so it triggers on any host once __linux__/__MACH__/__ZEPHYR__ are
25+
* suppressed via -U flags. WOLFSSL_USER_SETTINGS is supplied by run.sh. */
26+
#include "user_settings.h"
27+
#include "wolfssl/wolfcrypt/settings.h"
28+
#include "wolfssl/wolfcrypt/mem_track.h"
29+
30+
int main(void) { return 0; }
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
#!/bin/sh
2+
# run.sh
3+
#
4+
# Copyright (C) 2006-2026 wolfSSL Inc.
5+
#
6+
# This file is part of wolfSSL.
7+
#
8+
# wolfSSL is free software; you can redistribute it and/or modify
9+
# it under the terms of the GNU General Public License as published by
10+
# the Free Software Foundation; either version 3 of the License, or
11+
# (at your option) any later version.
12+
#
13+
# wolfSSL is distributed in the hope that it will be useful,
14+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
15+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16+
# GNU General Public License for more details.
17+
#
18+
# You should have received a copy of the GNU General Public License
19+
# along with this program; if not, write to the Free Software
20+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
21+
22+
# Regression test for the mem_track.h memLock guard misalignment that
23+
# previously broke multi-threaded FreeRTOS-class builds with
24+
# WOLFSSL_TRACK_MEMORY + USE_WOLFSSL_MEMORY + !WOLFSSL_STATIC_MEMORY.
25+
#
26+
# The bug is preprocessor-only, so the test runs on a stock Linux host:
27+
# -U__linux__ -U__MACH__ -U__ZEPHYR__ suppresses the host autodefines
28+
# that would otherwise hide it. Stub FreeRTOS.h / semphr.h satisfy the
29+
# wc_port.h FREERTOS_TCP mutex typedef without needing a real RTOS.
30+
#
31+
# Exit 0 = mem_track.h still compiles in the non-Linux multi-threaded
32+
# config, i.e. the fix is in place. Exit non-zero = the misalignment is
33+
# back. Run from the wolfssl repo root.
34+
set -u
35+
cc -DWOLFSSL_USER_SETTINGS \
36+
-U__linux__ -U__MACH__ -U__ZEPHYR__ \
37+
-I tests/freertos-mem-track-repro \
38+
-I . \
39+
-c tests/freertos-mem-track-repro/repro.c \
40+
-o /dev/null
41+
status=$?
42+
if [ $status -eq 0 ]; then
43+
echo "OK: mem_track.h compiles for non-Linux multi-threaded config."
44+
else
45+
echo "FAIL: mem_track.h compile broken for non-Linux multi-threaded" >&2
46+
echo " config - the memLock guard misalignment may be back." >&2
47+
fi
48+
exit $status
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/* semphr.h
2+
*
3+
* Copyright (C) 2006-2026 wolfSSL Inc.
4+
*
5+
* This file is part of wolfSSL.
6+
*
7+
* wolfSSL is free software; you can redistribute it and/or modify
8+
* it under the terms of the GNU General Public License as published by
9+
* the Free Software Foundation; either version 3 of the License, or
10+
* (at your option) any later version.
11+
*
12+
* wolfSSL is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
* GNU General Public License for more details.
16+
*
17+
* You should have received a copy of the GNU General Public License
18+
* along with this program; if not, write to the Free Software
19+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
20+
*/
21+
22+
/* Stub semphr.h for the mem_track.h reproducer. SemaphoreHandle_t is
23+
* declared in the stub FreeRTOS.h. */
24+
#ifndef WOLFSSL_REPRO_SEMPHR_H
25+
#define WOLFSSL_REPRO_SEMPHR_H
26+
#endif
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/* task.h
2+
*
3+
* Copyright (C) 2006-2026 wolfSSL Inc.
4+
*
5+
* This file is part of wolfSSL.
6+
*
7+
* wolfSSL is free software; you can redistribute it and/or modify
8+
* it under the terms of the GNU General Public License as published by
9+
* the Free Software Foundation; either version 3 of the License, or
10+
* (at your option) any later version.
11+
*
12+
* wolfSSL is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
* GNU General Public License for more details.
16+
*
17+
* You should have received a copy of the GNU General Public License
18+
* along with this program; if not, write to the Free Software
19+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
20+
*/
21+
22+
/* Stub task.h for the mem_track.h reproducer. The wolfSSL header chain
23+
* includes this when FREERTOS is defined; we don't need any of the real
24+
* task API to reach the mem_track.h code under test. */
25+
#ifndef WOLFSSL_REPRO_TASK_H
26+
#define WOLFSSL_REPRO_TASK_H
27+
#endif
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/* user_settings.h
2+
*
3+
* Copyright (C) 2006-2026 wolfSSL Inc.
4+
*
5+
* This file is part of wolfSSL.
6+
*
7+
* wolfSSL is free software; you can redistribute it and/or modify
8+
* it under the terms of the GNU General Public License as published by
9+
* the Free Software Foundation; either version 3 of the License, or
10+
* (at your option) any later version.
11+
*
12+
* wolfSSL is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
* GNU General Public License for more details.
16+
*
17+
* You should have received a copy of the GNU General Public License
18+
* along with this program; if not, write to the Free Software
19+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
20+
*/
21+
22+
/* Minimal user_settings.h reproducing the bug state. */
23+
#ifndef WOLFSSL_FREERTOS_MEM_TRACK_REPRO_USER_SETTINGS_H
24+
#define WOLFSSL_FREERTOS_MEM_TRACK_REPRO_USER_SETTINGS_H
25+
26+
#define FREERTOS
27+
#define FREERTOS_TCP
28+
#define NO_FILESYSTEM
29+
#define WOLFSSL_NO_SOCK
30+
#define USE_WOLFSSL_MEMORY
31+
#define WOLFSSL_TRACK_MEMORY
32+
#define WOLFSSL_DEBUG_MEMORY
33+
#define WOLFSSL_DEBUG_MEMORY_PRINT
34+
#define DEBUG_WOLFSSL
35+
36+
/* Intentionally NOT defined: SINGLE_THREADED, WOLFSSL_STATIC_MEMORY */
37+
38+
#endif

tests/include.am

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,5 +88,11 @@ EXTRA_DIST += tests/unit.h \
8888
tests/emnet/IP/IP.h \
8989
tests/emnet/emnet_shim.c \
9090
tests/emnet/emnet_nonblock_test.c \
91-
tests/emnet/Makefile
91+
tests/emnet/Makefile \
92+
tests/freertos-mem-track-repro/user_settings.h \
93+
tests/freertos-mem-track-repro/repro.c \
94+
tests/freertos-mem-track-repro/FreeRTOS.h \
95+
tests/freertos-mem-track-repro/semphr.h \
96+
tests/freertos-mem-track-repro/task.h \
97+
tests/freertos-mem-track-repro/run.sh
9298
DISTCLEANFILES+= tests/.libs/unit.test

wolfssl/wolfcrypt/mem_track.h

Lines changed: 42 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -142,9 +142,12 @@ static memoryStats ourMemStats;
142142
WOLFSSL_API extern memoryStats *wc_MemStats_Ptr;
143143

144144
#ifdef DO_MEM_LIST
145-
#include <pthread.h>
146145
static memoryList ourMemList;
147-
static pthread_mutex_t memLock = PTHREAD_MUTEX_INITIALIZER;
146+
#endif
147+
148+
#if !defined(SINGLE_THREADED) && (defined(DO_MEM_LIST) || defined(DO_MEM_STATS))
149+
static wolfSSL_Mutex memLock;
150+
static int memLockInit = 0;
148151
#endif
149152

150153
#ifdef WOLFSSL_DEBUG_MEMORY
@@ -182,7 +185,7 @@ static WC_INLINE void* TrackMalloc(size_t sz)
182185
#endif
183186
#endif
184187
#if !defined(SINGLE_THREADED) && (defined(DO_MEM_LIST) || defined(DO_MEM_STATS))
185-
if (pthread_mutex_lock(&memLock) == 0)
188+
if (wc_LockMutex(&memLock) == 0)
186189
{
187190
#endif
188191

@@ -228,9 +231,9 @@ static WC_INLINE void* TrackMalloc(size_t sz)
228231
ourMemList.count++;
229232
#endif
230233
#if !defined(SINGLE_THREADED) && (defined(DO_MEM_LIST) || defined(DO_MEM_STATS))
231-
pthread_mutex_unlock(&memLock);
234+
wc_UnLockMutex(&memLock);
232235
}
233-
#endif /* DO_MEM_LIST */
236+
#endif /* !SINGLE_THREADED && (DO_MEM_LIST || DO_MEM_STATS) */
234237

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

257260
#if !defined(SINGLE_THREADED) && (defined(DO_MEM_LIST) || defined(DO_MEM_STATS))
258-
if (pthread_mutex_lock(&memLock) == 0)
261+
if (wc_LockMutex(&memLock) == 0)
259262
{
260263
#endif
261264

@@ -289,7 +292,7 @@ static WC_INLINE void TrackFree(void* ptr)
289292
#endif
290293

291294
#if !defined(SINGLE_THREADED) && (defined(DO_MEM_LIST) || defined(DO_MEM_STATS))
292-
pthread_mutex_unlock(&memLock);
295+
wc_UnLockMutex(&memLock);
293296
}
294297
#endif
295298

@@ -362,14 +365,27 @@ static WC_INLINE int InitMemoryTracker(void)
362365
if (ret < 0) {
363366
wc_mem_printf("wolfSSL GetAllocators failed to get the defaults\n");
364367
}
368+
369+
#if !defined(SINGLE_THREADED) && (defined(DO_MEM_LIST) || defined(DO_MEM_STATS))
370+
/* Init the mutex before installing the tracking allocators, so the
371+
* mutex is ready as soon as another thread can enter TrackMalloc. */
372+
if (!memLockInit) {
373+
if (wc_InitMutex(&memLock) != 0) {
374+
wc_mem_printf("wc_InitMutex failed for track memory\n");
375+
return -1;
376+
}
377+
memLockInit = 1;
378+
}
379+
#endif
380+
365381
ret = wolfSSL_SetAllocators(TrackMalloc, TrackFree, TrackRealloc);
366382
if (ret < 0) {
367383
wc_mem_printf("wolfSSL SetAllocators failed for track memory\n");
368384
return ret;
369385
}
370386

371-
#ifdef DO_MEM_LIST
372-
if (pthread_mutex_lock(&memLock) == 0)
387+
#if !defined(SINGLE_THREADED) && (defined(DO_MEM_LIST) || defined(DO_MEM_STATS))
388+
if (wc_LockMutex(&memLock) == 0)
373389
#endif
374390
{
375391
#ifdef DO_MEM_STATS
@@ -387,8 +403,11 @@ static WC_INLINE int InitMemoryTracker(void)
387403
#ifdef DO_MEM_LIST
388404
XMEMSET(&ourMemList, 0, sizeof(ourMemList));
389405
ourMemStats.memList = &ourMemList;
406+
#endif
390407

391-
pthread_mutex_unlock(&memLock);
408+
#if !defined(SINGLE_THREADED) && \
409+
(defined(DO_MEM_LIST) || defined(DO_MEM_STATS))
410+
wc_UnLockMutex(&memLock);
392411
#endif
393412
}
394413

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

400419
static WC_INLINE void ShowMemoryTracker(void)
401420
{
402-
#ifdef DO_MEM_LIST
403-
if (pthread_mutex_lock(&memLock) == 0)
421+
#if !defined(SINGLE_THREADED) && (defined(DO_MEM_LIST) || defined(DO_MEM_STATS))
422+
if (wc_LockMutex(&memLock) == 0)
404423
#endif
405424
{
406425
#ifdef DO_MEM_STATS
@@ -429,16 +448,25 @@ static WC_INLINE void ShowMemoryTracker(void)
429448
#endif
430449
}
431450
}
451+
#endif
432452

433-
pthread_mutex_unlock(&memLock);
453+
#if !defined(SINGLE_THREADED) && \
454+
(defined(DO_MEM_LIST) || defined(DO_MEM_STATS))
455+
wc_UnLockMutex(&memLock);
434456
#endif
435457
}
436458
}
437459

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

0 commit comments

Comments
 (0)