Found while adding Kickstart/Workbench version telemetry to mqttstats (PR #22): reading a UWORD struct field (SysBase->LibNode.lib_Version, workbench.library's lib_Version/lib_Revision) and passing it through sprintf(buf, "%u.%u", ...) produces garbage in the upper 16 bits of the promoted value only at -O2 - confirmed via an isolated on-target repro under Copperline. -O0 is correct.
Two "obvious" fixes did not work:
& 0xFFFF masking at the call site: optimized away as "provably redundant" by GCC's own (here, wrong) UWORD range analysis - confirmed by a byte-identical rebuild of the binary with and without the mask.
- Routing the value through a
volatile local: fixed an isolated single-function repro, but did not fix the real call site inside mqttstats_main.c - something about the surrounding code (register pressure? inlining decisions?) reintroduces it.
What actually worked, shipped in mqttstats_main.c's format_bcd_version(): a volatile local at the call site feeding a dedicated __attribute__((noinline)) manual digit-formatter, entirely avoiding sprintf's %u varargs path. See that function's own comment for the full story.
Why this matters beyond mqttstats: since M68K_CFLAGS builds everything at -O2 by default, this could silently affect any other code passing a 16-bit (UWORD) value through a variadic call (sprintf/RawDoFmt/etc.) - worth a dedicated investigation to find the toolchain version, minimal repro, and whether it's a known upstream m68k-amigaos-gcc bug, rather than working around it ad hoc every time it's hit. Not urgent (the workaround above is shipped and correct) but worth tracking so it doesn't get rediscovered from scratch.
Found while adding Kickstart/Workbench version telemetry to mqttstats (PR #22): reading a
UWORDstruct field (SysBase->LibNode.lib_Version,workbench.library'slib_Version/lib_Revision) and passing it throughsprintf(buf, "%u.%u", ...)produces garbage in the upper 16 bits of the promoted value only at-O2- confirmed via an isolated on-target repro under Copperline.-O0is correct.Two "obvious" fixes did not work:
& 0xFFFFmasking at the call site: optimized away as "provably redundant" by GCC's own (here, wrong) UWORD range analysis - confirmed by a byte-identical rebuild of the binary with and without the mask.volatilelocal: fixed an isolated single-function repro, but did not fix the real call site insidemqttstats_main.c- something about the surrounding code (register pressure? inlining decisions?) reintroduces it.What actually worked, shipped in
mqttstats_main.c'sformat_bcd_version(): avolatilelocal at the call site feeding a dedicated__attribute__((noinline))manual digit-formatter, entirely avoidingsprintf's%uvarargs path. See that function's own comment for the full story.Why this matters beyond mqttstats: since
M68K_CFLAGSbuilds everything at-O2by default, this could silently affect any other code passing a 16-bit (UWORD) value through a variadic call (sprintf/RawDoFmt/etc.) - worth a dedicated investigation to find the toolchain version, minimal repro, and whether it's a known upstream m68k-amigaos-gcc bug, rather than working around it ad hoc every time it's hit. Not urgent (the workaround above is shipped and correct) but worth tracking so it doesn't get rediscovered from scratch.