|
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^63Most 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.) -- RobertoThat 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