This is an archive of the discontinued LLVM Phabricator instance.

[libc] Fix printf %f bugs
ClosedPublic

Authored by michaelrj on Aug 9 2023, 11:42 AM.

Details

Summary

Fuzzing revealed several bugs in the %f float conversion. This patch
fixes them. Most of these bugs are related to rounding, such as
1.999...999 being rounded to 2.999...999 instead of 2.000...000 due to
rounding up not properly changing the nines to zeros. Additionally, much
of the rounding infrastructure has been refactored out so it can be
shared with the other conversions.

Diff Detail

Event Timeline

michaelrj created this revision.Aug 9 2023, 11:42 AM
Herald added projects: Restricted Project, Restricted Project. · View Herald TranscriptAug 9 2023, 11:42 AM
sivachandra added inline comments.Aug 9 2023, 2:28 PM
libc/test/src/stdio/sprintf_test.cpp
1286

Remove.

1288

Add a comment describing the "why" of the expected result. In a way it is obvious I think, but will help people who do not remember what the %.9f means.

Same for the tests below.

michaelrj updated this revision to Diff 548793.Aug 9 2023, 3:38 PM
michaelrj marked an inline comment as done.

add comments explaining more about the tests

libc/test/src/stdio/sprintf_test.cpp
1286

same as previous, this is a category.

sivachandra added inline comments.Aug 11 2023, 1:33 PM
libc/test/src/stdio/sprintf_test.cpp
1286

You can choose to leave the note about fuzzing, but the category I think is "Rounding behavior tests".

1303

Nit: Add a comment explaining why there are digits beyond the 3339 even though the literal above does not.

michaelrj updated this revision to Diff 549528.Aug 11 2023, 2:54 PM
michaelrj marked 3 inline comments as done.

adjust test comments

libc/test/src/stdio/sprintf_test.cpp
1286

that category is "precision tests" which these are already in, see line 1217 (might be adjusted by the previous patch).

sivachandra accepted this revision.Aug 14 2023, 10:04 PM

LGTM but I have left a question on a comment in the test.

libc/test/src/stdio/sprintf_test.cpp
1297

I am confused with this wording. My knowledge says that if you write down a literal, then is already an exact value (of course, might not correspond exactly to an encoded value). Likewise, if a floating number is encoded as single/double/quad precision number, then that is also an exact number.

1303

Isn't the reason that the closest number that can be represented as a double precision number to that literal?

This revision is now accepted and ready to land.Aug 14 2023, 10:04 PM
michaelrj updated this revision to Diff 550523.Aug 15 2023, 4:21 PM
michaelrj marked 2 inline comments as done.

simplify test comment

libc/test/src/stdio/sprintf_test.cpp
1297

The literal you write down maps to a value, but it's usually not exact. As an example, when you write 0.1 the "actual" value as a double is 0.1000000000000000055511151231257827021181583404541015625. That's the value you get if you actually calculate 1.mantissa * 2^exponent, but when converting to and from a string that's not the only valid value. The number only has ~17 significant figures, so if you change the digits after that point you'll still get the same result. In this case the first non-significant digit happens to be the first 5. You can set that digit and any digits after to any value you want and it'll still give you the same result. As long as you stay within that range (0.1000...000, 0.1000...001), the number is equivalent. That's what I meant by floating point numbers representing a range.

1303

This is a simpler way to explain it. I've adjusted the comment.

This revision was landed with ongoing or failed builds.Aug 15 2023, 4:23 PM
This revision was automatically updated to reflect the committed changes.