From 07cadcc13f540021c5a209b93f89ae8cda6d3950 Mon Sep 17 00:00:00 2001 From: Marian Buschsieweke Date: Wed, 15 Apr 2026 23:03:29 +0200 Subject: [PATCH 1/2] dist/tools/coccinelle: add patch to fix asserts with side-effects This adds a semantic patch to replace ```C assert(do_something() == 0); ``` with ```C typeof(do_something()) tmp = do_something(); (void)tmp; assert(tmp == 0); ``` The reasoning that `do_something()` likely has side-effects and compilation with `-DNDEBUG` results in incorrect behavior. A list of some 50 pure functions that safely can be used in `assert()` and are used in `assert()` has been added to disable all current false positives. --- .../force/assert_no_function_call.cocci | 115 ++++++++++++++++++ 1 file changed, 115 insertions(+) create mode 100644 dist/tools/coccinelle/force/assert_no_function_call.cocci diff --git a/dist/tools/coccinelle/force/assert_no_function_call.cocci b/dist/tools/coccinelle/force/assert_no_function_call.cocci new file mode 100644 index 000000000000..f06dca36d599 --- /dev/null +++ b/dist/tools/coccinelle/force/assert_no_function_call.cocci @@ -0,0 +1,115 @@ +// One might be tempted to write `assert(do_something() == 0);` if one expects +// that `do_something()` does succeed and wants to panic if not. However, with +// `-DNDEBUG` both the check of the return value but also the function call get +// optimized out. +// +// Something like `assert(self_test() == 0);` does make sense if and only if +// `self_test()` is a pure (as in `__attribute__((pure))`) function. We can +// exclude pure functions from this list, as not too many different pure +// functions end up in an `assert()` anyway. +// +// SPDX-FileCopyrightText: 2026 ML!PA Consulting GmbH +// SPDX-License-Identifier: LGPL-2.1-only +// Confidence: Moderate +// Options: + +@@ +identifier f != { + ARRAY_SIZE, + atomic_load_kernel_pid, + bitarithm_bits_set, + block_get_enc_msg_len, + clist_count, + CMU_ClockFreqGet, + dev, + DEV, + _does_handle_ack, + dtls_get_app_data, + _get_nud_state, + __get_PRIMASK, + gnrc_pktbuf_contains, + gnrc_sixlowpan_frag_rb_entry_empty, + _gpio_init_mode_check, + gpio_is_equal, + gpio_is_valid, + GPIO_PORT_PIN_NUMOF, + gpio_port_unpack_addr, + HAS_ALIGNMENT_OF, + ieee802154_radio_has_irq_ack_timeout, + ipv6_addr_is_link_local, + ipv6_hdr_is, + irq_is_in, + IS_ACTIVE, + is_gpio_port_num_valid, + _is_set, + IS_USED, + KHZ, + kw41zrf_is_dsm, + MHZ, + msg_bus_get_sender_pid, + msp430_auxiliary_clock_freq, + netif_iter, + _nib_onl_get_if, + PARAMS, + pid_is_valid, + PWM_DEV, + sixlowpan_sfr_is, + soft_spi_bus_is_valid, + soft_spi_mode_is_valid, + SPI_DEV, + strcmp, + strncmp, + thread_getpid, + unicoap_message_is_request, + _valid_offset, + ztimer_is_set +}; +expression list args; +expression value; +@@ + +( +- assert(f(args) == value); ++ /* TODO: replace C23 typeof() with type by hand for portability */ ++ typeof(f(args)) tmp = f(args); ++ (void)tmp; ++ assert(tmp == value); +| +- assert(value == f(args)); ++ /* TODO: replace C23 typeof() with type by hand for portability */ ++ typeof(f(args)) tmp = f(args); ++ (void)tmp; ++ assert(tmp == value); +| +- assert(f(args)); ++ bool tmp = f(args); ++ (void)tmp; ++ assert(tmp); +| +- assert(!f(args)); ++ bool tmp = f(args); ++ (void)tmp; ++ assert(!tmp); +| +- assume(f(args) == value); ++ /* TODO: replace C23 typeof() with type by hand for portability */ ++ typeof(f(args)) tmp = f(args); ++ (void)tmp; ++ assume(tmp == value); +| +- assume(value == f(args)); ++ /* TODO: replace C23 typeof() with type by hand for portability */ ++ typeof(f(args)) tmp = f(args); ++ (void)tmp; ++ assume(tmp == value); +| +- assume(f(args)); ++ bool tmp = f(args); ++ (void)tmp; ++ assume(tmp); +| +- assume(!f(args)); ++ bool tmp = f(args); ++ (void)tmp; ++ assume(!tmp); +) From 473513df08767a7da4fb472269fa70c67e7c474f Mon Sep 17 00:00:00 2001 From: Marian Buschsieweke Date: Mon, 20 Apr 2026 14:37:57 +0200 Subject: [PATCH 2/2] squash! dist/tools/coccinelle: add patch to fix asserts with side-effects Co-authored-by: Karl Fessel --- .../force/assert_no_function_call.cocci | 22 ------------------- 1 file changed, 22 deletions(-) diff --git a/dist/tools/coccinelle/force/assert_no_function_call.cocci b/dist/tools/coccinelle/force/assert_no_function_call.cocci index f06dca36d599..ba2f34308726 100644 --- a/dist/tools/coccinelle/force/assert_no_function_call.cocci +++ b/dist/tools/coccinelle/force/assert_no_function_call.cocci @@ -90,26 +90,4 @@ expression value; + bool tmp = f(args); + (void)tmp; + assert(!tmp); -| -- assume(f(args) == value); -+ /* TODO: replace C23 typeof() with type by hand for portability */ -+ typeof(f(args)) tmp = f(args); -+ (void)tmp; -+ assume(tmp == value); -| -- assume(value == f(args)); -+ /* TODO: replace C23 typeof() with type by hand for portability */ -+ typeof(f(args)) tmp = f(args); -+ (void)tmp; -+ assume(tmp == value); -| -- assume(f(args)); -+ bool tmp = f(args); -+ (void)tmp; -+ assume(tmp); -| -- assume(!f(args)); -+ bool tmp = f(args); -+ (void)tmp; -+ assume(!tmp); )