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]