Skip to content

Commit e26321e

Browse files
authored
Merge pull request #21438 from maribu/sys/newlib/fix-stdio
build system: use thread-safe stdio
2 parents a76186e + 4a84f6f commit e26321e

File tree

14 files changed

+114
-51
lines changed

14 files changed

+114
-51
lines changed

Makefile.include

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -423,6 +423,8 @@ include $(RIOTMAKE)/kconfig.mk
423423
FEATURES_REQUIRED += $(filter arch_%,$(FEATURES_PROVIDED))
424424
# always select CPU core features
425425
FEATURES_REQUIRED += $(filter cpu_core_%,$(FEATURES_PROVIDED))
426+
# always "select" bug affecting the current build
427+
FEATURES_REQUIRED += $(filter bug_%,$(FEATURES_PROVIDED))
426428

427429
# check if required features are provided and update $(FEATURES_USED)
428430
include $(RIOTMAKE)/features_check.inc.mk

core/lib/include/assert.h

Lines changed: 38 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ extern "C" {
4444
* CFLAGS += -DDEBUG_ASSERT_VERBOSE
4545
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4646
*/
47-
#define DEBUG_ASSERT_VERBOSE
47+
# define DEBUG_ASSERT_VERBOSE
4848

4949
/**
5050
* @brief Activate breakpoints for @ref assert() when defined
@@ -58,32 +58,39 @@ extern "C" {
5858
* execution is stopped directly in the debugger. Otherwise the execution stops
5959
* in an endless while loop.
6060
*/
61-
#define DEBUG_ASSERT_BREAKPOINT
61+
# define DEBUG_ASSERT_BREAKPOINT
6262
#else
6363
/* we should not include custom headers in standard headers */
64-
#define _likely(x) __builtin_expect((uintptr_t)(x), 1)
64+
# define _likely(x) __builtin_expect((uintptr_t)(x), 1)
6565
#endif
6666

67+
#ifndef __NORETURN
68+
# if defined(__GNUC__) || defined(DOXYGEN)
6769
/**
68-
* @def __NORETURN
69-
* @brief hidden (__) NORETURN definition
70+
* @brief Same as @ref NORETURN
7071
* @internal
7172
*
72-
* Duplicating the definitions of kernel_defines.h as these are unsuitable for
73-
* system header files like the assert.h.
74-
* kernel_defines.h would define symbols that are not reserved.
73+
* We are not using @ref NORETURN from `compiler_hints.h` here to avoid RIOT
74+
* dependencies for standard C headers
7575
*/
76-
#ifndef __NORETURN
77-
#ifdef __GNUC__
78-
#define __NORETURN __attribute__((noreturn))
79-
#else /*__GNUC__*/
80-
#define __NORETURN
81-
#endif /*__GNUC__*/
82-
#endif /*__NORETURN*/
76+
# define __NORETURN __attribute__((noreturn))
77+
# else
78+
# define __NORETURN
79+
# endif
80+
#endif
81+
82+
/**
83+
* @brief Internal function to trigger a panic with a failed assertion as
84+
* identifying cause
85+
* @internal
86+
* @warning This is an internal function. API changes may happen without regard
87+
* for out-of tree uses.
88+
*
89+
* The implementation will identify the cause of the panic as a blown assertion,
90+
* e.g. via a log output.
91+
*/
92+
__NORETURN void _assert_panic(void);
8393

84-
#ifdef NDEBUG
85-
#define assert(ignore)((void)0)
86-
#elif defined(DEBUG_ASSERT_VERBOSE)
8794
/**
8895
* @brief Function to handle failed assertion
8996
*
@@ -95,6 +102,10 @@ extern "C" {
95102
* @param[in] line The code line of @p file the assertion failed in
96103
*/
97104
__NORETURN void _assert_failure(const char *file, unsigned line);
105+
106+
#ifdef NDEBUG
107+
# define assert(ignore)((void)0)
108+
#elif defined(DEBUG_ASSERT_VERBOSE)
98109
/**
99110
* @brief abort the program if assertion is false
100111
*
@@ -132,27 +143,26 @@ __NORETURN void _assert_failure(const char *file, unsigned line);
132143
*
133144
* @see http://pubs.opengroup.org/onlinepubs/9699919799/functions/assert.html
134145
*/
135-
#define assert(cond) (_likely(cond) ? (void)0 : _assert_failure(__FILE__, __LINE__))
146+
# define assert(cond) (_likely(cond) ? (void)0 : _assert_failure(__FILE__, __LINE__))
136147
#else /* DEBUG_ASSERT_VERBOSE */
137-
__NORETURN void _assert_panic(void);
138-
#define assert(cond) (_likely(cond) ? (void)0 : _assert_panic())
148+
# define assert(cond) (_likely(cond) ? (void)0 : _assert_panic())
139149
#endif /* DEBUG_ASSERT_VERBOSE */
140150

141151
#if !defined __cplusplus
142-
#if __STDC_VERSION__ >= 201112L
152+
# if __STDC_VERSION__ >= 201112L
143153
/**
144154
* @brief c11 static_assert() macro
145155
*/
146-
#define static_assert(...) _Static_assert(__VA_ARGS__)
147-
#else
156+
# define static_assert(...) _Static_assert(__VA_ARGS__)
157+
# else
148158
/**
149159
* @brief static_assert for c-version < c11
150160
*
151161
* Generates a division by zero compile error when cond is false
152162
*/
153-
#define static_assert(cond, ...) \
154-
{ enum { static_assert_failed_on_div_by_0 = 1 / (!!(cond)) }; }
155-
#endif
163+
# define static_assert(cond, ...) \
164+
{ enum { static_assert_failed_on_div_by_0 = 1 / (!!(cond)) }; }
165+
# endif
156166
#endif
157167

158168
/**
@@ -161,7 +171,7 @@ __NORETURN void _assert_panic(void);
161171
* If the assertion failed in an interrupt, the system will still panic.
162172
*/
163173
#ifndef DEBUG_ASSERT_NO_PANIC
164-
#define DEBUG_ASSERT_NO_PANIC (1)
174+
# define DEBUG_ASSERT_NO_PANIC (1)
165175
#endif
166176

167177
#ifdef __cplusplus

cpu/cortexm_common/Makefile.features

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
FEATURES_PROVIDED += arch_32bit
22
FEATURES_PROVIDED += arch_arm
3+
FEATURES_PROVIDED += bug_newlib_broken_stdio
34
FEATURES_PROVIDED += cortexm_svc
45
FEATURES_PROVIDED += cpp
56
FEATURES_PROVIDED += cpu_check_address
@@ -9,8 +10,8 @@ FEATURES_PROVIDED += libstdcpp
910
FEATURES_PROVIDED += newlib
1011
FEATURES_PROVIDED += periph_flashpage_aux
1112
FEATURES_PROVIDED += periph_pm
12-
FEATURES_PROVIDED += puf_sram
1313
FEATURES_PROVIDED += picolibc
14+
FEATURES_PROVIDED += puf_sram
1415
FEATURES_PROVIDED += ssp
1516

1617
# cortex-m33, cortex-m4f and cortex-m7 provide FPU support

cpu/msp430/Makefile.features

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ endif
1414

1515
FEATURES_PROVIDED += arch_16bit
1616
FEATURES_PROVIDED += arch_msp430
17+
FEATURES_PROVIDED += bug_newlib_broken_stdio
1718
FEATURES_PROVIDED += cpu_$(CPU_FAM)
1819
FEATURES_PROVIDED += dbgpin
1920
FEATURES_PROVIDED += newlib

cpu/riscv_common/Makefile.features

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ endif
44

55
FEATURES_PROVIDED += arch_32bit
66
FEATURES_PROVIDED += arch_riscv
7+
FEATURES_PROVIDED += bug_newlib_broken_stdio
78
FEATURES_PROVIDED += cpp
89
FEATURES_PROVIDED += libstdcpp
910
FEATURES_PROVIDED += newlib

features.yaml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -922,3 +922,17 @@ groups:
922922
open and solder bridges SB4, SB5 and SB6 are closed instead, SPI2 is
923923
connected to the STMmod+/Pmod connector. Request this feature to use
924924
SPI2 with this board configuration.
925+
926+
- title: Bugs in hardware, toolchain, or binary blobs
927+
help: This allows modelling bugs found in boards, so that workarounds can
928+
be enabled for affected builds by inspecting "FEATURES_USED". Any
929+
feature prefixed with "bug_" provided in a build will always be used,
930+
regardless of build configuration.
931+
features:
932+
- name: bug_newlib_broken_stdio
933+
help: newlib's stdio is not inherently thread-safe, but depends on the
934+
reentrancy hooks to be provided for correct operation. When
935+
reentrancy is not enabled, using newlib's stdio is racy, causing
936+
random crashes at runtime. Use of this feature will cause an
937+
alternative stdio implementation to be used if (and only if) newlib
938+
is used as standard c lib.

makefiles/features_existing.inc.mk

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ FEATURES_EXISTING := \
4444
ble_phy_coded \
4545
board_bat_voltage \
4646
bootloader_stm32 \
47+
bug_newlib_broken_stdio \
4748
can_rx_mailbox \
4849
cortexm_fpu \
4950
cortexm_mpu \

makefiles/libc/newlib.mk

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,3 +100,7 @@ ifeq (1,$(USE_NEWLIB_NANO))
100100
INCLUDES := -isystem $(NEWLIB_NANO_INCLUDE_DIR) $(INCLUDES)
101101
endif
102102
endif
103+
104+
# In case externally compiled code gets linked in, it may use newlib's assert
105+
# implementation. We wrap that to RIOT's assert implementation for consistency.
106+
LINKFLAGS += -Wl,-wrap=__assert_func

pkg/mpaland-printf/Makefile.dep

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,12 @@
33
# is not compatible with AVR MCUs.
44
FEATURES_BLACKLIST += arch_avr8
55

6-
# On 32 bit and 64 bit systems support for long long is so cheap, that we
7-
# can enable it by default. Users can still disable it, though.
8-
ifneq (,$(filter arch_32bit arch_64bit,$(FEATURES_USED)))
9-
DEFAULT_MODULE += printf_long_long
6+
# On ESP it is not easily possible to replace newlib's stdio, as there is only
7+
# API compatibility and not ABI compatibility between mpaland-printf and newlib's
8+
# printf and the ESP SDK contains binary blobs.
9+
FEATURES_BLACKLIST += arch_esp
10+
11+
# On 64 bit systems, we depend on long long support to be able to support `%p`
12+
ifneq (,$(filter arch_64bit,$(FEATURES_USED)))
13+
USEMODULE += printf_long_long
1014
endif

pkg/mpaland-printf/Makefile.include

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ LINKFLAGS += -Wl,-wrap=puts
1919
# stdio, we will catch any instance of both mpaland-printf and newlib's stdio
2020
# being both linked in.
2121
LINKFLAGS += -Wl,-wrap=_printf_common
22+
LINKFLAGS += -Wl,-wrap=_fprintf_r
23+
LINKFLAGS += -Wl,-wrap=_printf_r
24+
LINKFLAGS += -Wl,-wrap=iprintf
25+
LINKFLAGS += -Wl,-wrap=fiprintf
2226

2327
# Workaround for bug in the newlib headers shipped with e.g. Ubuntu 24.04 LTS
2428
# not defining PRId64 / PRIu64 / PRIx64 / PRIo64 in <inttypes.h> due to an issue

0 commit comments

Comments
 (0)