lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


Am 22.07.2015 um 08:33 schröbte Dirk Laurie:
2015-07-22 0:32 GMT+02:00 Rena <hyperhacker@gmail.com>:
On Tue, Jul 21, 2015 at 8:28 AM, Roberto Ierusalimschy
<roberto@inf.puc-rio.br> wrote:
The OP's problem can be solved with something much less ambitious.
Replace the first line above by:

       case 'd':
           lua_Integer n = (lua_Integer)luaL_checknumber(L, arg);
           addlenmod(form, LUA_INTEGER_FRMLEN);
           nb = sprintf(buff, form, (n);
           break;
       case 'i':

My question was: which of the other five cases should also be
treated like case 'd?


IIUC, this would break it for some numbers between 2^53 and 2^63

Most of them, actually. It also has undefined behavior for numbers
larger than 2^63. (On most machines this "undefined behavior" manifests
as plainly wrong results.)

-- Roberto


That can still be addressed:
case 'd':
     lua_Integer n;
     if(lua_isinteger(L, arg)) n = lua_tointeger(L, arg);
     else n = (lua_Integer)luaL_checknumber(L, arg);
     addlenmod(form, LUA_INTEGER_FRMLEN);
     nb = sprintf(buff, form, (n);
     break;
case 'i':

Excellent! We have now demonstrated that a very easy change
allows anybody to build a custom string.format that will silently
throw away the fractional part of a non-integer.

Obviously the change isn't that easy, because the code above is still incorrect: It yields undefined behavior for large floating point numbers as Roberto already mentioned. ISO C 90:

When a value of floating type is converted to integral type, the
fractional part is discarded.  If the value of the integral part
cannot be represented by the integral type, the behavior is
undefined.

There are probably a lot of places in C code for Lua 5.2 and before where this problem might occur, so raising an error by default like in Lua 5.3 is actually a very good choice, IMHO.

One way to address this issue for `string.format` would be to use `%f` with a zero precision for the `sprintf` if the number is a floating point number, and the LUA_INTEGER_FRM* in case the value is already an integer.


Philipp