mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-01-31 03:27:39 +00:00
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.
This commit is contained in:
parent
cca0edd62b
commit
75e161b27b
2 changed files with 44 additions and 8 deletions
|
@ -615,7 +615,7 @@ static void __fmt_ldfpbits(union U *u, struct FPBits *b) {
|
|||
#if LDBL_MANT_DIG == 113
|
||||
b->bits[3] |= 1 << (112 - 32 * 3); // set lowest exponent bit
|
||||
#endif
|
||||
} else if (b->bits[0] | b->bits[1] | b->bits[2] | b->bits[3]) {
|
||||
} else if (isnan(u->ld)) {
|
||||
i = STRTOG_NaN;
|
||||
} else {
|
||||
i = STRTOG_Infinite;
|
||||
|
@ -1145,8 +1145,8 @@ int __fmt(void *fn, void *arg, const char *format, va_list va, int *wrote) {
|
|||
s = s0 =
|
||||
gdtoa(fpb.fpi, fpb.ex, fpb.bits, &fpb.kind, 3, prec, &decpt, &se);
|
||||
}
|
||||
if (decpt == 9999) {
|
||||
Format9999:
|
||||
if (decpt == 9999 || decpt == -32768) {
|
||||
FormatDecpt9999Or32768:
|
||||
if (s0)
|
||||
freedtoa(s0);
|
||||
bzero(special, sizeof(special));
|
||||
|
@ -1258,8 +1258,8 @@ int __fmt(void *fn, void *arg, const char *format, va_list va, int *wrote) {
|
|||
s = s0 = gdtoa(fpb.fpi, fpb.ex, fpb.bits, &fpb.kind, prec ? 2 : 0,
|
||||
prec, &decpt, &se);
|
||||
}
|
||||
if (decpt == 9999)
|
||||
goto Format9999;
|
||||
if (decpt == 9999 || decpt == -32768)
|
||||
goto FormatDecpt9999Or32768;
|
||||
c = se - s;
|
||||
prec1 = prec;
|
||||
if (!prec) {
|
||||
|
@ -1304,8 +1304,8 @@ int __fmt(void *fn, void *arg, const char *format, va_list va, int *wrote) {
|
|||
s = s0 = gdtoa(fpb.fpi, fpb.ex, fpb.bits, &fpb.kind, prec ? 2 : 0,
|
||||
prec, &decpt, &se);
|
||||
}
|
||||
if (decpt == 9999)
|
||||
goto Format9999;
|
||||
if (decpt == 9999 || decpt == -32768)
|
||||
goto FormatDecpt9999Or32768;
|
||||
FormatExpo:
|
||||
if (fpb.sign /* && (x || sign) */)
|
||||
sign = '-';
|
||||
|
@ -1386,7 +1386,7 @@ int __fmt(void *fn, void *arg, const char *format, va_list va, int *wrote) {
|
|||
}
|
||||
if (fpb.kind == STRTOG_Infinite || fpb.kind == STRTOG_NaN) {
|
||||
s0 = 0;
|
||||
goto Format9999;
|
||||
goto FormatDecpt9999Or32768;
|
||||
}
|
||||
prec1 = __fmt_fpiprec(&fpb);
|
||||
if ((flags & FLAGS_PRECISION) && prec < prec1) {
|
||||
|
|
|
@ -35,3 +35,39 @@ TEST(snprintf, testPlusFlagOnChar) {
|
|||
ASSERT_EQ(i, 1);
|
||||
ASSERT_STREQ(buf, "=");
|
||||
}
|
||||
|
||||
TEST(snprintf, testInf) {
|
||||
char buf[10] = {};
|
||||
int i = snprintf(buf, sizeof(buf), "%f", 1.0 / 0.0);
|
||||
|
||||
ASSERT_EQ(i, 3);
|
||||
ASSERT_STREQ(buf, "inf");
|
||||
|
||||
memset(buf, 0, 4);
|
||||
i = snprintf(buf, sizeof(buf), "%Lf", 1.0L / 0.0L);
|
||||
ASSERT_EQ(i, 3);
|
||||
ASSERT_STREQ(buf, "inf");
|
||||
|
||||
memset(buf, 0, 4);
|
||||
i = snprintf(buf, sizeof(buf), "%e", 1.0 / 0.0);
|
||||
ASSERT_EQ(i, 3);
|
||||
ASSERT_STREQ(buf, "inf");
|
||||
|
||||
memset(buf, 0, 4);
|
||||
i = snprintf(buf, sizeof(buf), "%Le", 1.0L / 0.0L);
|
||||
ASSERT_EQ(i, 3);
|
||||
ASSERT_STREQ(buf, "inf");
|
||||
|
||||
memset(buf, 0, 4);
|
||||
i = snprintf(buf, sizeof(buf), "%g", 1.0 / 0.0);
|
||||
ASSERT_EQ(i, 3);
|
||||
ASSERT_STREQ(buf, "inf");
|
||||
|
||||
memset(buf, 0, 4);
|
||||
i = snprintf(buf, sizeof(buf), "%Lg", 1.0L / 0.0L);
|
||||
ASSERT_EQ(i, 3);
|
||||
ASSERT_STREQ(buf, "inf");
|
||||
|
||||
for (i = 4; i < 10; ++i)
|
||||
ASSERT_EQ(buf[i], '\0');
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue