Summary: | printf produces bogus output when printing double 0x00000000000000ff with %g | ||||||
---|---|---|---|---|---|---|---|
Product: | Base System | Reporter: | Robert Clausecker <fuz> | ||||
Component: | arm | Assignee: | Michal Meloun <mmel> | ||||
Status: | Closed FIXED | ||||||
Severity: | Affects Many People | CC: | diizzy, emaste, jfc, mmel | ||||
Priority: | --- | Flags: | fuz:
mfc-stable13?
fuz: mfc-stable12? |
||||
Version: | 13.1-RELEASE | ||||||
Hardware: | Any | ||||||
OS: | Any | ||||||
Attachments: |
|
Description
Robert Clausecker
![]() ![]() Here's a simpler reproducer: #include <stdio.h> int main() { printf("%g\n", 1.26e-321); } This works fine on i386, amd64, and aarch64 but fails identically on armv7. The test program as written includes 4 uninitialized bytes in the double value on a 32 bit system. Forcing those bytes to zero using memset(&intf, 0, sizeof intf); before assigning to the int member results in the described output. (In reply to John F. Carr from comment #2) The bug also happens without the union, see the simpler reproducer in comment #1. A commit in branch main references this bug: URL: https://cgit.FreeBSD.org/ports/commit/?id=cb61cd8b665eccd6764df0ecae01dcaa4b8f5b5f commit cb61cd8b665eccd6764df0ecae01dcaa4b8f5b5f Author: Robert Clausecker <fuz@FreeBSD.org> AuthorDate: 2023-06-26 19:43:25 +0000 Commit: Robert Clausecker <fuz@FreeBSD.org> CommitDate: 2023-06-26 23:30:29 +0000 devel/orc: work around armv7 libc bug The armv7 libc has a bug in printf() where printing a denormal double may cause NUL bytes to be written out. This port tries to write a diagnostic comment containing such a denormal to a C source file. The bug causes the source file to be malformed, breaking the port and its consumers. Work around the bug by killing the offending part of the diagnostic comment. Approved by: portmgr (build fix blanket) Reviewed by: diizzy PR: 272229 devel/orc/Makefile | 1 + devel/orc/files/patch-orc_orcprogram-c.c (new) | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+) The file with __dtoa() is /usr/src/contrib/gdtoa/dtoa.c. It is compiled under the name gdtoa_dtoa.c. See lib/libc/gdtoa/Makefile.inc. For a more direct test, skipping printf, I used #include <stdio.h> extern char *__dtoa(double d0, int mode, int ndigits, int *decpt, int *sign, char **rve); int main(int argc, char *argv[]) { double d = 1.26e-321; int decpt = 0, sign = 0; char *converted = __dtoa(d, 2, 6, &decpt, &sign, 0); if (converted) fprintf(stdout, "sign = %d decpt = %d text = %s\n", sign, decpt, converted); return ferror(stdout); } I got the bad result on FreeBSD 13 and CURRENT, both in an armv7 chroot on an arm64 host. It seems that libc/arm/gd_qnan.h is wrong (or at least qnan config tool gives different values). Also libc/arm/arith.h is probably suboptimal... Created attachment 243053 [details]
regenerate gdtoa headers
(In reply to Michal Meloun from comment #6) gd_qnan.h and arith.h were both wrong. The bug was caused by arith.h defining Sudden_Underflow. The test program works with the patch I attached. I can not say whether this patch is appropriate for armv6 or for software floating point. Apparently CURRENT only supports little-endian with hardware floating point. I can confirm that attachment #243053 [details] fixes the bug.
@mmel any progress on getting this committed? It would be great if we could get this in for 14.0. A commit in branch main references this bug: URL: https://cgit.FreeBSD.org/src/commit/?id=e59b6e48f4c8bbfee43a1bc6d9fd47691d3bd603 commit e59b6e48f4c8bbfee43a1bc6d9fd47691d3bd603 Author: Michal Meloun <mmel@FreeBSD.org> AuthorDate: 2023-08-13 05:51:56 +0000 Commit: Michal Meloun <mmel@FreeBSD.org> CommitDate: 2023-08-13 07:35:48 +0000 gdtoa: Regenerate configuration headers for 32-bit arm. These configuration headers were only guessed, but unfortunately not exactly correctly. Therefore, re-generate them on real HW. Generated on CA15, verified on CA9, CA7(with VFP lite) and on 32-bit ARMv9. PR: 272229 Reported by: Robert Clausecker <fuz@FreeBSD.org> MFC after: 2 weeks lib/libc/arm/arith.h | 9 ++++----- lib/libc/arm/gd_qnan.h | 11 +++++------ 2 files changed, 9 insertions(+), 11 deletions(-) Could you please MFC this one? It should go into releng/14.0, too. Broken printf is really quite bad. A commit in branch stable/13 references this bug: URL: https://cgit.FreeBSD.org/src/commit/?id=8ca43e674e3cddf3574e062abde6cd70c120984e commit 8ca43e674e3cddf3574e062abde6cd70c120984e Author: Michal Meloun <mmel@FreeBSD.org> AuthorDate: 2023-08-13 05:51:56 +0000 Commit: Michal Meloun <mmel@FreeBSD.org> CommitDate: 2024-07-31 12:25:35 +0000 gdtoa: Regenerate configuration headers for 32-bit arm. These configuration headers were only guessed, but unfortunately not exactly correctly. Therefore, re-generate them on real HW. Generated on CA15, verified on CA9, CA7(with VFP lite) and on 32-bit ARMv9. PR: 272229 Reported by: Robert Clausecker <fuz@FreeBSD.org> MFC after: 2 weeks (cherry picked from commit e59b6e48f4c8bbfee43a1bc6d9fd47691d3bd603) lib/libc/arm/arith.h | 10 ++++++---- lib/libc/arm/gd_qnan.h | 11 ++++++----- 2 files changed, 12 insertions(+), 9 deletions(-) |