Skip to content

Commit faeefc5

Browse files
committed
Fixed mutex assert in armcc fopen and related memory leak
armcc fopen allocated a mutex using the retargeted system-level _mutex_initialize function. Interestingly, malloc also uses this same _mutex_initialization function, which prevents a full solution relying on malloc. The solution previously implemented involved using the rtx mutex pool for the first 8 mutexes, then falling back on malloc. The previous implementation relied on osMutexNew returning an error on out-of-memory. An unrelated change causes osMutexNew to instead assert (except for release mode). This meant if you exceed 8 system- level mutexes in armcc you will hit an assert. Since the filesystem code can call fopen an unlimited number of times, this is a problem. Solution is to keep track of which static mutexes we've allocated, so we know before calling osMutexNew if we need to call malloc. Also _mutex_free never deallocated the malloced mutexes, which would cause fopen to leak memory.
1 parent 20d93bf commit faeefc5

File tree

1 file changed

+41
-3
lines changed

1 file changed

+41
-3
lines changed

rtos/TARGET_CORTEX/mbed_boot.c

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,7 @@
168168
#include "cmsis_os2.h"
169169
#include "mbed_toolchain.h"
170170
#include "mbed_error.h"
171+
#include "mbed_critical.h"
171172
#if defined(__IAR_SYSTEMS_ICC__ ) && (__VER__ >= 8000000)
172173
#include <DLib_Threads.h>
173174
#endif
@@ -423,6 +424,7 @@ void __rt_entry (void) {
423424
}
424425

425426
typedef void *mutex;
427+
mutex _static_mutexes[OS_MUTEX_NUM] = {NULL};
426428

427429
/* ARM toolchain requires dynamically created mutexes to enforce thread safety. There's
428430
up to 8 static mutexes, protecting atexit, signalinit, stdin, stdout, stderr, stream_list,
@@ -441,9 +443,23 @@ int _mutex_initialize(mutex *m)
441443
attr.name = "ARM toolchain mutex";
442444
attr.attr_bits = osMutexRecursive | osMutexPrioInherit | osMutexRobust;
443445

444-
*m = osMutexNew(&attr);
445-
if (*m != NULL) {
446-
return 1;
446+
mutex *slot = NULL;
447+
core_util_critical_section_enter();
448+
for (int i = 0; i < OS_MUTEX_NUM; i++) {
449+
if (_static_mutexes[i] == NULL) {
450+
_static_mutexes[i] = (mutex)-1; // dummy value to reserve slot
451+
slot = &_static_mutexes[i];
452+
break;
453+
}
454+
}
455+
core_util_critical_section_exit();
456+
457+
if (slot != NULL) {
458+
*m = osMutexNew(&attr);
459+
*slot = *m;
460+
if (*m != NULL) {
461+
return 1;
462+
}
447463
}
448464

449465
/* Mutex pool exhausted, try using HEAP */
@@ -463,6 +479,28 @@ int _mutex_initialize(mutex *m)
463479
return 1;
464480
}
465481

482+
void _mutex_free(mutex *m) {
483+
mutex *slot = NULL;
484+
core_util_critical_section_enter();
485+
for (int i = 0; i < OS_MUTEX_NUM; i++) {
486+
if (_static_mutexes[i] == *m) {
487+
slot = &_static_mutexes[i];
488+
break;
489+
}
490+
}
491+
core_util_critical_section_exit();
492+
493+
osMutexDelete(*m);
494+
495+
// if no slot reserved for mutex, must have been dynamically allocated
496+
if (!slot) {
497+
free(m);
498+
} else {
499+
*slot = NULL;
500+
}
501+
502+
}
503+
466504
#endif /* ARMC */
467505
#elif defined (__GNUC__) /******************** GCC ********************/
468506

0 commit comments

Comments
 (0)