summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorantirez <antirez@gmail.com>2014-06-04 18:33:24 +0200
committerantirez <antirez@gmail.com>2014-06-04 18:33:24 +0200
commit072982d83c83b161f555538bad6a82815d1c36eb (patch)
tree12cfad3f2ce7d7e95cfbaf7b37c9a3d9c638e78d
parent8a588ac14d229aa330d7b2daea1778c606e6588b (diff)
downloadredis-072982d83c83b161f555538bad6a82815d1c36eb.tar.gz
Scripting: better Lua number -> string conversion in luaRedisGenericCommand().
The lua_to*string() family of functions use a non optimal format specifier when converting integers to strings. This has both the problem of the number being converted in exponential notation, which we don't use as a Redis return value when floating point numbers are involed, and, moreover, there is a loss of precision since the default format specifier is not able to represent numbers that must be represented exactly in the IEEE 754 number mantissa. The new code handles it as a special case using a saner conversion. This fixes issue #1118.
-rw-r--r--src/scripting.c18
1 files changed, 14 insertions, 4 deletions
diff --git a/src/scripting.c b/src/scripting.c
index 4b485d9b4..2a7f1b910 100644
--- a/src/scripting.c
+++ b/src/scripting.c
@@ -233,12 +233,22 @@ int luaRedisGenericCommand(lua_State *lua, int raise_error) {
char *obj_s;
size_t obj_len;
- obj_s = (char*)lua_tolstring(lua,j+1,&obj_len);
- if (obj_s == NULL) break; /* Not a string. */
+ if (lua_isnumber(lua,j+1)) {
+ /* We can't use lua_tolstring() for number -> string conversion
+ * since Lua uses a format specifier that loses precision. */
+ char dbuf[64];
+ lua_Number num = lua_tonumber(lua,j+1);
+
+ obj_len = snprintf(dbuf,sizeof(dbuf),"%.17g",(double)num);
+ obj_s = dbuf;
+ } else {
+ obj_s = (char*)lua_tolstring(lua,j+1,&obj_len);
+ if (obj_s == NULL) break; /* Not a string. */
+ }
/* Try to use a cached object. */
- if (j < LUA_CMD_OBJCACHE_SIZE && cached_objects[j] &&
- cached_objects_len[j] >= obj_len)
+ if (j < LUA_CMD_OBJCACHE_SIZE && cached_objects[j] &&
+ cached_objects_len[j] >= obj_len)
{
char *s = cached_objects[j]->ptr;
struct sdshdr *sh = (void*)(s-(sizeof(struct sdshdr)));