Skip to content

Commit 75e161b

Browse files
Fix printf-family functions on long double inf (#1273)
Cosmopolitan's printf-family functions currently very poorly handle being passed a long double infinity. For instance, a program such as: ```cpp #include <stdio.h> int main() { printf("%f\n", 1.0 / 0.0); printf("%Lf\n", 1.0L / 0.0L); printf("%e\n", 1.0 / 0.0); printf("%Le\n", 1.0L / 0.0L); printf("%g\n", 1.0 / 0.0); printf("%Lg\n", 1.0L / 0.0L); } ``` will currently output the following: ``` inf 0.000000[followed by 32763 more zeros] inf N.aN0000e-32769 inf N.aNe-32769 ``` when the correct expected output would be: ``` inf inf inf inf inf inf ``` This patch fixes this, and adds tests for the behavior.
1 parent cca0edd commit 75e161b

File tree

2 files changed

+44
-8
lines changed

2 files changed

+44
-8
lines changed

libc/stdio/fmt.c

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -615,7 +615,7 @@ static void __fmt_ldfpbits(union U *u, struct FPBits *b) {
615615
#if LDBL_MANT_DIG == 113
616616
b->bits[3] |= 1 << (112 - 32 * 3); // set lowest exponent bit
617617
#endif
618-
} else if (b->bits[0] | b->bits[1] | b->bits[2] | b->bits[3]) {
618+
} else if (isnan(u->ld)) {
619619
i = STRTOG_NaN;
620620
} else {
621621
i = STRTOG_Infinite;
@@ -1145,8 +1145,8 @@ int __fmt(void *fn, void *arg, const char *format, va_list va, int *wrote) {
11451145
s = s0 =
11461146
gdtoa(fpb.fpi, fpb.ex, fpb.bits, &fpb.kind, 3, prec, &decpt, &se);
11471147
}
1148-
if (decpt == 9999) {
1149-
Format9999:
1148+
if (decpt == 9999 || decpt == -32768) {
1149+
FormatDecpt9999Or32768:
11501150
if (s0)
11511151
freedtoa(s0);
11521152
bzero(special, sizeof(special));
@@ -1258,8 +1258,8 @@ int __fmt(void *fn, void *arg, const char *format, va_list va, int *wrote) {
12581258
s = s0 = gdtoa(fpb.fpi, fpb.ex, fpb.bits, &fpb.kind, prec ? 2 : 0,
12591259
prec, &decpt, &se);
12601260
}
1261-
if (decpt == 9999)
1262-
goto Format9999;
1261+
if (decpt == 9999 || decpt == -32768)
1262+
goto FormatDecpt9999Or32768;
12631263
c = se - s;
12641264
prec1 = prec;
12651265
if (!prec) {
@@ -1304,8 +1304,8 @@ int __fmt(void *fn, void *arg, const char *format, va_list va, int *wrote) {
13041304
s = s0 = gdtoa(fpb.fpi, fpb.ex, fpb.bits, &fpb.kind, prec ? 2 : 0,
13051305
prec, &decpt, &se);
13061306
}
1307-
if (decpt == 9999)
1308-
goto Format9999;
1307+
if (decpt == 9999 || decpt == -32768)
1308+
goto FormatDecpt9999Or32768;
13091309
FormatExpo:
13101310
if (fpb.sign /* && (x || sign) */)
13111311
sign = '-';
@@ -1386,7 +1386,7 @@ int __fmt(void *fn, void *arg, const char *format, va_list va, int *wrote) {
13861386
}
13871387
if (fpb.kind == STRTOG_Infinite || fpb.kind == STRTOG_NaN) {
13881388
s0 = 0;
1389-
goto Format9999;
1389+
goto FormatDecpt9999Or32768;
13901390
}
13911391
prec1 = __fmt_fpiprec(&fpb);
13921392
if ((flags & FLAGS_PRECISION) && prec < prec1) {

test/libc/stdio/snprintf_test.c

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,39 @@ TEST(snprintf, testPlusFlagOnChar) {
3535
ASSERT_EQ(i, 1);
3636
ASSERT_STREQ(buf, "=");
3737
}
38+
39+
TEST(snprintf, testInf) {
40+
char buf[10] = {};
41+
int i = snprintf(buf, sizeof(buf), "%f", 1.0 / 0.0);
42+
43+
ASSERT_EQ(i, 3);
44+
ASSERT_STREQ(buf, "inf");
45+
46+
memset(buf, 0, 4);
47+
i = snprintf(buf, sizeof(buf), "%Lf", 1.0L / 0.0L);
48+
ASSERT_EQ(i, 3);
49+
ASSERT_STREQ(buf, "inf");
50+
51+
memset(buf, 0, 4);
52+
i = snprintf(buf, sizeof(buf), "%e", 1.0 / 0.0);
53+
ASSERT_EQ(i, 3);
54+
ASSERT_STREQ(buf, "inf");
55+
56+
memset(buf, 0, 4);
57+
i = snprintf(buf, sizeof(buf), "%Le", 1.0L / 0.0L);
58+
ASSERT_EQ(i, 3);
59+
ASSERT_STREQ(buf, "inf");
60+
61+
memset(buf, 0, 4);
62+
i = snprintf(buf, sizeof(buf), "%g", 1.0 / 0.0);
63+
ASSERT_EQ(i, 3);
64+
ASSERT_STREQ(buf, "inf");
65+
66+
memset(buf, 0, 4);
67+
i = snprintf(buf, sizeof(buf), "%Lg", 1.0L / 0.0L);
68+
ASSERT_EQ(i, 3);
69+
ASSERT_STREQ(buf, "inf");
70+
71+
for (i = 4; i < 10; ++i)
72+
ASSERT_EQ(buf[i], '\0');
73+
}

0 commit comments

Comments
 (0)