commit 7f5c31cdcac5388b3c48a26112dfb6d2cadb7321
parent 9e6807c3c9d5036e999f636f936df07b72284442
Author: Roberto Ierusalimschy <roberto@inf.puc-rio.br>
Date: Tue, 23 Jul 2019 12:46:06 -0300
Fixed bug in 'string.format' with option '%f'
As an example, 'print(string.format("%.99f", 1e70))' may have a
lot of garbage after the number.
The old test to ensure that 'string.format("%.99f", n)' was not too
large, 'fabs(n) < 1e100', assumes that the number will fit in the 99
bytes; but the 99 is not the space for the number, it is the added
extra zeros. The option worked for smaller numbers because of the
extra space added to MAX_ITEM.
Diffstat:
2 files changed, 12 insertions(+), 8 deletions(-)
diff --git a/lstrlib.c b/lstrlib.c
@@ -1227,16 +1227,14 @@ static int str_format (lua_State *L) {
nb = lua_number2strx(L, buff, maxitem, form,
luaL_checknumber(L, arg));
break;
- case 'e': case 'E': case 'f':
- case 'g': case 'G': {
+ case 'f':
+ maxitem = MAX_ITEMF; /* extra space for '%f' */
+ buff = luaL_prepbuffsize(&b, maxitem);
+ /* FALLTHROUGH */
+ case 'e': case 'E': case 'g': case 'G': {
lua_Number n = luaL_checknumber(L, arg);
- if (*(strfrmt - 1) == 'f' && l_mathop(fabs)(n) >= 1e100) {
- /* 'n' needs more than 99 digits */
- maxitem = MAX_ITEMF; /* extra space for '%f' */
- buff = luaL_prepbuffsize(&b, maxitem);
- }
addlenmod(form, LUA_NUMBER_FRMLEN);
- nb = l_sprintf(buff, maxitem, form, (LUAI_UACNUMBER)n);
+ nb = snprintf(buff, maxitem, form, (LUAI_UACNUMBER)n);
break;
}
case 'p': {
diff --git a/testes/strings.lua b/testes/strings.lua
@@ -255,6 +255,12 @@ do -- longest number that can be formatted
local s = string.format('%.99f', -(10^i))
assert(string.len(s) >= i + 101)
assert(tonumber(s) == -(10^i))
+
+ -- limit for floats
+ assert(10^38 < math.huge)
+ local s = string.format('%.99f', -(10^38))
+ assert(string.len(s) >= 38 + 101)
+ assert(tonumber(s) == -(10^38))
end