I've run across a crash on a few different STM32 Nucleo boards (h743zi2, f767zi, and f446re) caused by the Idlestack not being8-byte aligned due to syslog messages at startup (with timestamps enabled) that passes a uintmax_t parameter to vsprinf_internal().

I originally found this on nucleo-h743zi2:jumbo while trying to fix the "Missing logic" warning in stm32_irq.c:152 I've been able to apply my same changes to nucleo-f446re and nucleo-f767zi and exhibit the issue. Even w/o my changes, forcing the .bss section to not be 8-byte aligned in size causes the same issue.

The underlying issue occurs due to calling stm32_dumpnvic from the idletask with SYSLOG_TIMESTAMP enabled, but only when the Idlestak is not aligned to an 8-byte bvoundary.  The issue is due to invoking "x = va_arg(ap, unsigned long long);" in vsprintf_internal (lib_libvsprintf.c:1061) which aligns ap before accessing the long long:

Breakpoint 5, vsprintf_internal (stream=stream@entry=0x20005390, arglist=0x0,
    numargs=0, fmt=0x8018bf2 ".%06ld] [%6s] %s: ",
    fmt@entry=0x8005817 <lib_sprintf_internal+22> "...",
    ap=..., ap@entry=..., numargs=0, arglist=0x0)
    at stream/lib_libvsprintf.c:1061
1061                    x = va_arg(ap, unsigned long long);
p ap
$18 = {__ap =*0x2000536c*}
(gdb) x/5i $pc
=> 0x800563a <vsprintf_internal+782>:   add.w   r9, r9, #7
   0x800563e <vsprintf_internal+786>:*bic.w   r9, r9, #7 # align ap*
   0x8005642 <vsprintf_internal+790>:   mov     r7, r9
   0x8005644 <vsprintf_internal+792>:   ldr.w   r1, [r9, #4]
   0x8005648 <vsprintf_internal+796>:   ldr.w   r0, [r7], #8
(gdb) p/x $r9
$19 = 0x2000536c
(gdb) s
1108              flags &= ~(FL_PLUS | FL_SPACE);
(gdb) p ap
$20 = {__ap =*0x20005378*}
(gdb) p/x $r7
$21 = 0x20005378
(gdb)

This works fine if the stack is aligned on an 8-byte boundary (which all other task/user stacks currently are due to MM_DEFAULT_ALIGNMENT being 8). But if the idletask stack is not aligned, ap ends up incremented by 12 causing access to any following vararg in vsprintf_internal to be offset by 4 bytes resulting in potential exceptions.

A fix is to increase the alignment in the .bss section to 8 in the linker description file (since the idlestack immediately follows .bss starting at _ebss).  I've tested this fix on nucleo-743zi2 (based on stm32h7), nucleo-h767zi (based on stm32f7), and nucleo-f446re (based on stm32), all with success.

I can provide a PR, but my question is whether this alignment should be applied to all ARM?

--
Peter Barada
[email protected]

Reply via email to