Skip to content

Fix UTIL_SEQ_CONF_TASK_NBR overflow guard silently passing (#52)#112

Open
94xhn wants to merge 1 commit into
STMicroelectronics:mainfrom
94xhn:fix-util-seq-task-nbr-compile-time-assert
Open

Fix UTIL_SEQ_CONF_TASK_NBR overflow guard silently passing (#52)#112
94xhn wants to merge 1 commit into
STMicroelectronics:mainfrom
94xhn:fix-util-seq-task-nbr-compile-time-assert

Conversation

@94xhn

@94xhn 94xhn commented Jul 10, 2026

Copy link
Copy Markdown

Problem

Fixes #52.

UTIL_SEQ_CONF_TASK_NBR is commonly redefined in an application's utilities_conf.h to an enum sentinel value, e.g.:

#define UTIL_SEQ_CONF_TASK_NBR CFG_SEQ_Task_NBR

where CFG_SEQ_Task_Id_t is an enum whose last member (CFG_SEQ_Task_NBR) represents the task count (this exact pattern appears across many Projects/*/utilities_def.h files in this repo).

Per C99 §6.10.1p4, an identifier that is not a macro is replaced by 0 when it appears in a preprocessor #if expression — the preprocessor has no visibility into enum values. The existing guard in Utilities/sequencer/stm32_seq.c:

#if UTIL_SEQ_CONF_TASK_NBR > 32
#error "UTIL_SEQ_CONF_TASK_NBR must be less than or equal to 32"
#endif

therefore evaluates as 0 > 32, which is always false, so the #error never fires — even when an application defines more than 32 tasks. This matches the issue's own diagnosis (adding -Wundef shows the identifier is unresolved at preprocessing time).

This isn't just a diagnostic-quality issue: several call sites in this file compute a task's bit position via 1U << CurrentTaskIdx (used when building/testing the task bitmask). If the effective task count exceeds 32, an index >= 32 makes that shift amount >= the width of the shifted type, which is undefined behavior in C.

Fix

Replace the preprocessor guard with a compile-time assertion evaluated by the compiler proper during semantic analysis, which does see the real (macro-expanded) enum value:

typedef char UTIL_SEQ_CONF_TASK_NBR_Assert[(UTIL_SEQ_CONF_TASK_NBR <= 32) ? 1 : -1];

A classic negative-array-size assertion was used instead of _Static_assert/static_assert to avoid depending on C11 support — this project's MDK-ARM/EWARM project files still allow selecting pre-C11 dialects, and I wanted the fix to compile cleanly regardless of which toolchain/dialect a downstream application has configured.

Verification

I don't have hardware or the ST toolchains (Keil/IAR) set up in this environment, so I verified the logic with a standalone host-side reproduction mirroring the exact macro-to-enum indirection pattern (33-member enum, one over the limit), compiled with gcc -std=c89:

  • Before the fix: compiles cleanly, exit code 0 — confirming the original guard is silently bypassed for the 33-task case.
  • After the fix: fails to compile with error: size of array 'UTIL_SEQ_CONF_TASK_NBR_Assert' is negative, exit code 1 — confirming the fix correctly catches the violation.
  • Regression check: a normal case (4 tasks, well under the limit) and the default case (macro undefined, falls back to (32)) both still compile cleanly after the fix, exit code 0 — confirming no impact on valid configurations.

Disclosure

Generative AI (Claude) was used to help investigate this issue, implement, and verify this fix. All changes were reviewed by me before submission.

…ectronics#52)

UTIL_SEQ_CONF_TASK_NBR is frequently redefined in an application's
utilities_conf.h to an enum sentinel value, e.g.:

    #define UTIL_SEQ_CONF_TASK_NBR CFG_SEQ_Task_NBR

where CFG_SEQ_Task_Id_t is an enum whose last member (CFG_SEQ_Task_NBR)
represents the task count. Per C99 6.10.1p4, an identifier that is not
a macro is replaced by 0 when it appears in a preprocessor #if
expression, since the preprocessor has no visibility into enum values.
The existing guard:

    #if UTIL_SEQ_CONF_TASK_NBR > 32
    #error "UTIL_SEQ_CONF_TASK_NBR must be less than or equal to 32"
    #endif

therefore evaluates as "0 > 32", which is always false, so the #error
never fires even when an application defines more than 32 tasks. Since
several call sites in this file compute a task's bit position via
"1U << CurrentTaskIdx" (e.g. lines building UTIL_SEQ_SetTask_Mask and
similar masks), a task index >= 32 causes undefined behavior (shift
amount >= width of the shifted type) that this guard was meant to
prevent.

Replace the preprocessor guard with a compile-time array-size
assertion, which is evaluated by the compiler proper during semantic
analysis and does see the real (expanded) enum value:

    typedef char UTIL_SEQ_CONF_TASK_NBR_Assert[(UTIL_SEQ_CONF_TASK_NBR <= 32) ? 1 : -1];

A classic negative-array-size assertion was used instead of
_Static_assert/static_assert to avoid depending on C11 support across
all toolchains this project ships with (MDK-ARM/EWARM project files
still allow selecting pre-C11 dialects).

Verified with a standalone host-side reproduction (not on hardware, no
board/toolchain access in this environment): a minimal harness
mirroring the exact macro-to-enum indirection pattern, compiled with
gcc -std=c89.

Before the fix, with a 33-member task enum (one over the limit), the
file compiles cleanly (exit 0) — confirming the original guard is
silently bypassed. After the fix, the same 33-task case fails to
compile with "size of array ... is negative" (exit 1), while a normal
case (4 tasks, well under the limit) still compiles cleanly (exit 0),
confirming no regression for valid configurations.

Fixes STMicroelectronics#52

Generative AI (Claude) was used to help investigate this issue,
implement, and verify this fix. All changes were reviewed by me before
submission.

Signed-off-by: yi chen <94xhn1@gmail.com>
@KRASTM

KRASTM commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Hello @94xhn,

Thank you for the contribution. I will share your proposal with our team and keep you updated.

With regards,

@KRASTM KRASTM moved this from To do to Analyzed in stm32cube-mcu-fw-dashboard Jul 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working utils Utilities

Projects

Development

Successfully merging this pull request may close these issues.

Maximum number of tasks in sequencer not triggering an error

3 participants