severity 1078556 grave
tags 1078556 + upstream patch
forwarded 1078556 https://lists.gnu.org/archive/html/bug-bash/2024-08/msg00087.html
forcemerge 1078556 1078583
thanks
it's crazy to me that these were allowed to stay as normal
(I'd say it's critical, since it "makes unrelated software on the system [...] break";
call it grave since actual usage of printf %f in system-provided
programs is pretty rare),
or that bash with this bug was allowed to migrate to testing.
My analysis agrees with the mailing list:
# valgrind bash -c 'printf %f 2'
==4136153== Memcheck, a memory error detector
==4136153== Copyright (C) 2002-2022, and GNU GPL'd, by Julian Seward et al.
==4136153== Using Valgrind-3.20.0 and LibVEX; rerun with -h for copyright info
==4136153== Command: bash -c printf\ %f\ 2
==4136153==
==4136153== Conditional jump or move depends on uninitialised value(s)
==4136153== at 0x48E5435: __printf_fp_buffer_1.isra.0 (printf_fp.c:227)
==4136153== by 0x48E745B: __printf_fp_l_buffer (printf_fp.c:1122)
==4136153== by 0x48EDE4C: __printf_fp_spec (vfprintf-internal.c:266)
==4136153== by 0x48EDE4C: __printf_buffer (vfprintf-internal.c:999)
==4136153== by 0x48EECA0: __vfprintf_internal (vfprintf-internal.c:1544)
==4136153== by 0x49A16A6: __printf_chk (printf_chk.c:33)
==4136153== by 0x1C00A4: printf (stdio2.h:86)
==4136153== by 0x1C00A4: printf_builtin (printf.def:721)
==4136153== by 0x14E969: execute_builtin (execute_cmd.c:4971)
==4136153== by 0x154B24: execute_builtin_or_function (execute_cmd.c:5485)
==4136153== by 0x154B24: execute_simple_command (execute_cmd.c:4737)
==4136153== by 0x154B24: execute_command_internal (execute_cmd.c:866)
==4136153== by 0x1AEF58: parse_and_execute (evalstring.c:539)
==4136153== by 0x139FD9: run_one_command.isra.0 (shell.c:1473)
==4136153== by 0x138AA1: main (shell.c:763)
==4136153==
==4136153== Conditional jump or move depends on uninitialised value(s)
==4136153== at 0x48E538C: __printf_fp_buffer_1.isra.0 (printf_fp.c:238)
==4136153== by 0x48E745B: __printf_fp_l_buffer (printf_fp.c:1122)
==4136153== by 0x48EDE4C: __printf_fp_spec (vfprintf-internal.c:266)
==4136153== by 0x48EDE4C: __printf_buffer (vfprintf-internal.c:999)
==4136153== by 0x48EECA0: __vfprintf_internal (vfprintf-internal.c:1544)
==4136153== by 0x49A16A6: __printf_chk (printf_chk.c:33)
==4136153== by 0x1C00A4: printf (stdio2.h:86)
==4136153== by 0x1C00A4: printf_builtin (printf.def:721)
==4136153== by 0x14E969: execute_builtin (execute_cmd.c:4971)
==4136153== by 0x154B24: execute_builtin_or_function (execute_cmd.c:5485)
==4136153== by 0x154B24: execute_simple_command (execute_cmd.c:4737)
==4136153== by 0x154B24: execute_command_internal (execute_cmd.c:866)
==4136153== by 0x1AEF58: parse_and_execute (evalstring.c:539)
==4136153== by 0x139FD9: run_one_command.isra.0 (shell.c:1473)
==4136153== by 0x138AA1: main (shell.c:763)
==4136153==
-nan==4136153==
==4136153== HEAP SUMMARY:
==4136153== in use at exit: 53,517 bytes in 422 blocks
==4136153== total heap usage: 459 allocs, 37 frees, 57,384 bytes allocated
==4136153==
==4136153== LEAK SUMMARY:
==4136153== definitely lost: 0 bytes in 0 blocks
==4136153== indirectly lost: 0 bytes in 0 blocks
==4136153== possibly lost: 0 bytes in 0 blocks
==4136153== still reachable: 53,517 bytes in 422 blocks
==4136153== suppressed: 0 bytes in 0 blocks
==4136153== Rerun with --leak-check=full to see details of leaked memory
==4136153==
==4136153== Use --track-origins=yes to see where uninitialised values come from
==4136153== For lists of detected and suppressed errors, rerun with: -s
==4136153== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
and this clearly shows that bash is actually using a normal-length
double (strtod()):
strchr("#'-+ 0", 'f') = nil
strchr("hjlLtz", 'f') = nil
__errno_location() = 0x7fdd273a86c8
strtod("2", "") = 2.000000
strlen("%f") = 2
malloc(1024) = 0x55ce477f5ee0
memcpy(0x55ce477f5ee0, "%", 1) = 0x55ce477f5ee0
clearerr(0x7fdd275825c0, 76, 0, 1) = 0xfbad2284
__printf_chk(1, 0x55ce477f5ee0, 0, 1) = 2094
and if it's giving that to %Lf then that's obviously wrong and the
other half of the long double is uninitialised.
This bug is only made visible because the configuration script
is /also/ broken, since bookworm bash uses strtold().
This was identified by upstream and a patch is given in
https://lists.gnu.org/archive/html/bug-bash/2024-08/msg00090.html
I've verified that on sid with 5.2.21-2.1 prior to this patch,
strtold() is not detected (and this triggers the bug, per valgrind):
checking whether strtold is declared... yes
checking for broken strtold... yes
but with this patch strtold() is detected
checking whether strtold is declared... yes
checking for broken strtold... no
and the bug is not triggered
# valgrind ./debian/bash/usr/bin/bash -c 'printf %f 2'
==148139== Memcheck, a memory error detector
==148139== Copyright (C) 2002-2022, and GNU GPL'd, by Julian Seward et al.
==148139== Using Valgrind-3.20.0 and LibVEX; rerun with -h for copyright info
==148139== Command: ./debian/bash/usr/bin/bash -c printf\ %f\ 2
==148139==
2.000000==148139==
==148139== HEAP SUMMARY:
==148139== in use at exit: 53,735 bytes in 425 blocks
==148139== total heap usage: 460 allocs, 35 frees, 57,631 bytes allocated
==148139==
==148139== LEAK SUMMARY:
==148139== definitely lost: 0 bytes in 0 blocks
==148139== indirectly lost: 0 bytes in 0 blocks
==148139== possibly lost: 0 bytes in 0 blocks
==148139== still reachable: 53,735 bytes in 425 blocks
==148139== suppressed: 0 bytes in 0 blocks
==148139== Rerun with --leak-check=full to see details of leaked memory
==148139==
==148139== For lists of detected and suppressed errors, rerun with: -s
==148139== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
I'm attaching upstream's configure-strtold-check (reformatted to unified
debian/patches/-compatible format, tested against 5.2.21-2.1).
Best,