Browse Source

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.
Roberto Ierusalimschy 6 năm trước cách đây
mục cha
commit
2d3f095448
2 tập tin đã thay đổi với 29 bổ sung20 xóa
  1. 28 12
      lstrlib.c
  2. 1 8
      luaconf.h

+ 28 - 12
lstrlib.c

@@ -1038,13 +1038,23 @@ static int lua_number2strx (lua_State *L, char *buff, int sz,
 
 
 /*
-** Maximum size of each formatted item. This maximum size is produced
+** Maximum size for items formatted with '%f'. This size is produced
 ** by format('%.99f', -maxfloat), and is equal to 99 + 3 ('-', '.',
 ** and '\0') + number of decimal digits to represent maxfloat (which
-** is maximum exponent + 1). (99+3+1 then rounded to 120 for "extra
-** expenses", such as locale-dependent stuff)
+** is maximum exponent + 1). (99+3+1, adding some extra, 110)
 */
-#define MAX_ITEM        (120 + l_mathlim(MAX_10_EXP))
+#define MAX_ITEMF	(110 + l_mathlim(MAX_10_EXP))
+
+
+/*
+** All formats except '%f' do not need that large limit.  The other
+** float formats use exponents, so that they fit in the 99 limit for
+** significant digits; 's' for large strings and 'q' add items directly
+** to the buffer; all integer formats also fit in the 99 limit.  The
+** worst case are floats: they may need 99 significant digits, plus
+** '0x', '-', '.', 'e+XXXX', and '\0'. Adding some extra, 120.
+*/
+#define MAX_ITEM	120
 
 
 /* valid flags in a format specification */
@@ -1194,38 +1204,44 @@ static int str_format (lua_State *L) {
       luaL_addchar(&b, *strfrmt++);  /* %% */
     else { /* format item */
       char form[MAX_FORMAT];  /* to store the format ('%...') */
-      char *buff = luaL_prepbuffsize(&b, MAX_ITEM);  /* to put formatted item */
+      int maxitem = MAX_ITEM;
+      char *buff = luaL_prepbuffsize(&b, maxitem);  /* to put formatted item */
       int nb = 0;  /* number of bytes in added item */
       if (++arg > top)
         return luaL_argerror(L, arg, "no value");
       strfrmt = scanformat(L, strfrmt, form);
       switch (*strfrmt++) {
         case 'c': {
-          nb = l_sprintf(buff, MAX_ITEM, form, (int)luaL_checkinteger(L, arg));
+          nb = l_sprintf(buff, maxitem, form, (int)luaL_checkinteger(L, arg));
           break;
         }
         case 'd': case 'i':
         case 'o': case 'u': case 'x': case 'X': {
           lua_Integer n = luaL_checkinteger(L, arg);
           addlenmod(form, LUA_INTEGER_FRMLEN);
-          nb = l_sprintf(buff, MAX_ITEM, form, (LUAI_UACINT)n);
+          nb = l_sprintf(buff, maxitem, form, (LUAI_UACINT)n);
           break;
         }
         case 'a': case 'A':
           addlenmod(form, LUA_NUMBER_FRMLEN);
-          nb = lua_number2strx(L, buff, MAX_ITEM, form,
+          nb = lua_number2strx(L, buff, maxitem, form,
                                   luaL_checknumber(L, arg));
           break;
         case 'e': case 'E': case 'f':
         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, MAX_ITEM, form, (LUAI_UACNUMBER)n);
+          nb = l_sprintf(buff, maxitem, form, (LUAI_UACNUMBER)n);
           break;
         }
         case 'p': {
           const void *p = lua_topointer(L, arg);
-          nb = l_sprintf(buff, MAX_ITEM, form, p);
+          nb = l_sprintf(buff, maxitem, form, p);
           break;
         }
         case 'q': {
@@ -1246,7 +1262,7 @@ static int str_format (lua_State *L) {
               luaL_addvalue(&b);  /* keep entire string */
             }
             else {  /* format the string into 'buff' */
-              nb = l_sprintf(buff, MAX_ITEM, form, s);
+              nb = l_sprintf(buff, maxitem, form, s);
               lua_pop(L, 1);  /* remove result from 'luaL_tolstring' */
             }
           }
@@ -1256,7 +1272,7 @@ static int str_format (lua_State *L) {
           return luaL_error(L, "invalid conversion '%s' to 'format'", form);
         }
       }
-      lua_assert(nb < MAX_ITEM);
+      lua_assert(nb < maxitem);
       luaL_addsize(&b, nb);
     }
   }

+ 1 - 8
luaconf.h

@@ -709,16 +709,9 @@
 
 /*
 @@ LUAL_BUFFERSIZE is the buffer size used by the lauxlib buffer system.
-** CHANGE it if it uses too much C-stack space. (For long double,
-** 'string.format("%.99f", -1e4932)' needs 5052 bytes, so a
-** smaller buffer would force a memory allocation for each call to
-** 'string.format'.)
 */
-#if LUA_FLOAT_TYPE == LUA_FLOAT_LONGDOUBLE
-#define LUAL_BUFFERSIZE		8192
-#else
 #define LUAL_BUFFERSIZE   ((int)(16 * sizeof(void*) * sizeof(lua_Number)))
-#endif
+
 
 /*
 @@ LUAI_MAXALIGN defines fields that, when used in a union, ensure