diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2019-04-12 11:48:24 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2019-04-12 11:48:24 -0300 |
commit | 2d3f09544895b422eeecf89e0d108da8b8fcdfca (patch) | |
tree | dcbb636cecf51d52945c1b0bd378f07781c5b987 /lstrlib.c | |
parent | b0810c51c3f075cc8a309bfb3c1714ac42b0f020 (diff) | |
download | lua-2d3f09544895b422eeecf89e0d108da8b8fcdfca.tar.gz lua-2d3f09544895b422eeecf89e0d108da8b8fcdfca.tar.bz2 lua-2d3f09544895b422eeecf89e0d108da8b8fcdfca.zip |
Avoid using large buffers in 'string.format'
The result of "string.format("%.99f", -1e308) is 410 characters long,
but all other formats have much smaller limits (at most 99 plus a fex
extras). This commit avoids 'string.format' asking for a buffer
~400 chars large when ~100 will do.
Diffstat (limited to 'lstrlib.c')
-rw-r--r-- | lstrlib.c | 40 |
1 files changed, 28 insertions, 12 deletions
@@ -1038,13 +1038,23 @@ static int lua_number2strx (lua_State *L, char *buff, int sz, | |||
1038 | 1038 | ||
1039 | 1039 | ||
1040 | /* | 1040 | /* |
1041 | ** Maximum size of each formatted item. This maximum size is produced | 1041 | ** Maximum size for items formatted with '%f'. This size is produced |
1042 | ** by format('%.99f', -maxfloat), and is equal to 99 + 3 ('-', '.', | 1042 | ** by format('%.99f', -maxfloat), and is equal to 99 + 3 ('-', '.', |
1043 | ** and '\0') + number of decimal digits to represent maxfloat (which | 1043 | ** and '\0') + number of decimal digits to represent maxfloat (which |
1044 | ** is maximum exponent + 1). (99+3+1 then rounded to 120 for "extra | 1044 | ** is maximum exponent + 1). (99+3+1, adding some extra, 110) |
1045 | ** expenses", such as locale-dependent stuff) | ||
1046 | */ | 1045 | */ |
1047 | #define MAX_ITEM (120 + l_mathlim(MAX_10_EXP)) | 1046 | #define MAX_ITEMF (110 + l_mathlim(MAX_10_EXP)) |
1047 | |||
1048 | |||
1049 | /* | ||
1050 | ** All formats except '%f' do not need that large limit. The other | ||
1051 | ** float formats use exponents, so that they fit in the 99 limit for | ||
1052 | ** significant digits; 's' for large strings and 'q' add items directly | ||
1053 | ** to the buffer; all integer formats also fit in the 99 limit. The | ||
1054 | ** worst case are floats: they may need 99 significant digits, plus | ||
1055 | ** '0x', '-', '.', 'e+XXXX', and '\0'. Adding some extra, 120. | ||
1056 | */ | ||
1057 | #define MAX_ITEM 120 | ||
1048 | 1058 | ||
1049 | 1059 | ||
1050 | /* valid flags in a format specification */ | 1060 | /* valid flags in a format specification */ |
@@ -1194,38 +1204,44 @@ static int str_format (lua_State *L) { | |||
1194 | luaL_addchar(&b, *strfrmt++); /* %% */ | 1204 | luaL_addchar(&b, *strfrmt++); /* %% */ |
1195 | else { /* format item */ | 1205 | else { /* format item */ |
1196 | char form[MAX_FORMAT]; /* to store the format ('%...') */ | 1206 | char form[MAX_FORMAT]; /* to store the format ('%...') */ |
1197 | char *buff = luaL_prepbuffsize(&b, MAX_ITEM); /* to put formatted item */ | 1207 | int maxitem = MAX_ITEM; |
1208 | char *buff = luaL_prepbuffsize(&b, maxitem); /* to put formatted item */ | ||
1198 | int nb = 0; /* number of bytes in added item */ | 1209 | int nb = 0; /* number of bytes in added item */ |
1199 | if (++arg > top) | 1210 | if (++arg > top) |
1200 | return luaL_argerror(L, arg, "no value"); | 1211 | return luaL_argerror(L, arg, "no value"); |
1201 | strfrmt = scanformat(L, strfrmt, form); | 1212 | strfrmt = scanformat(L, strfrmt, form); |
1202 | switch (*strfrmt++) { | 1213 | switch (*strfrmt++) { |
1203 | case 'c': { | 1214 | case 'c': { |
1204 | nb = l_sprintf(buff, MAX_ITEM, form, (int)luaL_checkinteger(L, arg)); | 1215 | nb = l_sprintf(buff, maxitem, form, (int)luaL_checkinteger(L, arg)); |
1205 | break; | 1216 | break; |
1206 | } | 1217 | } |
1207 | case 'd': case 'i': | 1218 | case 'd': case 'i': |
1208 | case 'o': case 'u': case 'x': case 'X': { | 1219 | case 'o': case 'u': case 'x': case 'X': { |
1209 | lua_Integer n = luaL_checkinteger(L, arg); | 1220 | lua_Integer n = luaL_checkinteger(L, arg); |
1210 | addlenmod(form, LUA_INTEGER_FRMLEN); | 1221 | addlenmod(form, LUA_INTEGER_FRMLEN); |
1211 | nb = l_sprintf(buff, MAX_ITEM, form, (LUAI_UACINT)n); | 1222 | nb = l_sprintf(buff, maxitem, form, (LUAI_UACINT)n); |
1212 | break; | 1223 | break; |
1213 | } | 1224 | } |
1214 | case 'a': case 'A': | 1225 | case 'a': case 'A': |
1215 | addlenmod(form, LUA_NUMBER_FRMLEN); | 1226 | addlenmod(form, LUA_NUMBER_FRMLEN); |
1216 | nb = lua_number2strx(L, buff, MAX_ITEM, form, | 1227 | nb = lua_number2strx(L, buff, maxitem, form, |
1217 | luaL_checknumber(L, arg)); | 1228 | luaL_checknumber(L, arg)); |
1218 | break; | 1229 | break; |
1219 | case 'e': case 'E': case 'f': | 1230 | case 'e': case 'E': case 'f': |
1220 | case 'g': case 'G': { | 1231 | case 'g': case 'G': { |
1221 | lua_Number n = luaL_checknumber(L, arg); | 1232 | lua_Number n = luaL_checknumber(L, arg); |
1233 | if (*(strfrmt - 1) == 'f' && l_mathop(fabs)(n) >= 1e100) { | ||
1234 | /* 'n' needs more than 99 digits */ | ||
1235 | maxitem = MAX_ITEMF; /* extra space for '%f' */ | ||
1236 | buff = luaL_prepbuffsize(&b, maxitem); | ||
1237 | } | ||
1222 | addlenmod(form, LUA_NUMBER_FRMLEN); | 1238 | addlenmod(form, LUA_NUMBER_FRMLEN); |
1223 | nb = l_sprintf(buff, MAX_ITEM, form, (LUAI_UACNUMBER)n); | 1239 | nb = l_sprintf(buff, maxitem, form, (LUAI_UACNUMBER)n); |
1224 | break; | 1240 | break; |
1225 | } | 1241 | } |
1226 | case 'p': { | 1242 | case 'p': { |
1227 | const void *p = lua_topointer(L, arg); | 1243 | const void *p = lua_topointer(L, arg); |
1228 | nb = l_sprintf(buff, MAX_ITEM, form, p); | 1244 | nb = l_sprintf(buff, maxitem, form, p); |
1229 | break; | 1245 | break; |
1230 | } | 1246 | } |
1231 | case 'q': { | 1247 | case 'q': { |
@@ -1246,7 +1262,7 @@ static int str_format (lua_State *L) { | |||
1246 | luaL_addvalue(&b); /* keep entire string */ | 1262 | luaL_addvalue(&b); /* keep entire string */ |
1247 | } | 1263 | } |
1248 | else { /* format the string into 'buff' */ | 1264 | else { /* format the string into 'buff' */ |
1249 | nb = l_sprintf(buff, MAX_ITEM, form, s); | 1265 | nb = l_sprintf(buff, maxitem, form, s); |
1250 | lua_pop(L, 1); /* remove result from 'luaL_tolstring' */ | 1266 | lua_pop(L, 1); /* remove result from 'luaL_tolstring' */ |
1251 | } | 1267 | } |
1252 | } | 1268 | } |
@@ -1256,7 +1272,7 @@ static int str_format (lua_State *L) { | |||
1256 | return luaL_error(L, "invalid conversion '%s' to 'format'", form); | 1272 | return luaL_error(L, "invalid conversion '%s' to 'format'", form); |
1257 | } | 1273 | } |
1258 | } | 1274 | } |
1259 | lua_assert(nb < MAX_ITEM); | 1275 | lua_assert(nb < maxitem); |
1260 | luaL_addsize(&b, nb); | 1276 | luaL_addsize(&b, nb); |
1261 | } | 1277 | } |
1262 | } | 1278 | } |