Unverified Commit 5fdaa53d authored by Matthew Douglass's avatar Matthew Douglass Committed by GitHub
Browse files

Fix conversion of numbers in lua args to redis args (#13115)



Since lua_Number is not explicitly an integer or a double, we need to
make an effort
to convert it as an integer when that's possible, since the string could
later be used
in a context that doesn't support scientific notation (e.g. 1e9 instead
of 100000000).

Since fpconv_dtoa converts numbers with the equivalent of `%f` or `%e`,
which ever is shorter,
this would break if we try to pass a long integer number to a command
that takes integer.
we'll get an implicit conversion to string in Lua, and then the parsing
in getLongLongFromObjectOrReply will fail.

```
> eval "redis.call('hincrby', 'key', 'field', '1000000000')" 0
(nil)
> eval "redis.call('hincrby', 'key', 'field', tonumber('1000000000'))" 0
(error) ERR value is not an integer or out of range script: ac99c32e4daf7e300d593085b611de261954a946, on @user_script:1.
```

Switch to using ll2string if the number can be safely represented as a
long long.

The problem was introduced in #10587 (Redis 7.2).
closes #13113.

---------
Co-authored-by: default avatarBinbin <binloveplay1314@qq.com>
Co-authored-by: default avatardebing.sun <debing.sun@redis.com>
Co-authored-by: default avatarOran Agra <oran@redislabs.com>
parent 4979cf02
...@@ -819,8 +819,17 @@ static robj **luaArgsToRedisArgv(lua_State *lua, int *argc, int *argv_len) { ...@@ -819,8 +819,17 @@ static robj **luaArgsToRedisArgv(lua_State *lua, int *argc, int *argv_len) {
/* We can't use lua_tolstring() for number -> string conversion /* We can't use lua_tolstring() for number -> string conversion
* since Lua uses a format specifier that loses precision. */ * since Lua uses a format specifier that loses precision. */
lua_Number num = lua_tonumber(lua,j+1); lua_Number num = lua_tonumber(lua,j+1);
obj_len = fpconv_dtoa((double)num, dbuf); /* Integer printing function is much faster, check if we can safely use it.
dbuf[obj_len] = '\0'; * Since lua_Number is not explicitly an integer or a double, we need to make an effort
* to convert it as an integer when that's possible, since the string could later be used
* in a context that doesn't support scientific notation (e.g. 1e9 instead of 100000000). */
long long lvalue;
if (double2ll((double)num, &lvalue))
obj_len = ll2string(dbuf, sizeof(dbuf), lvalue);
else {
obj_len = fpconv_dtoa((double)num, dbuf);
dbuf[obj_len] = '\0';
}
obj_s = dbuf; obj_s = dbuf;
} else { } else {
obj_s = (char*)lua_tolstring(lua,j+1,&obj_len); obj_s = (char*)lua_tolstring(lua,j+1,&obj_len);
......
...@@ -146,6 +146,14 @@ start_server {tags {"scripting"}} { ...@@ -146,6 +146,14 @@ start_server {tags {"scripting"}} {
} 1 x } 1 x
} {number 1} } {number 1}
test {EVAL - Lua number -> Redis integer conversion} {
r del hash
run_script {
local foo = redis.pcall('hincrby','hash','field',200000000)
return {type(foo),foo}
} 0
} {number 200000000}
test {EVAL - Redis bulk -> Lua type conversion} { test {EVAL - Redis bulk -> Lua type conversion} {
r set mykey myval r set mykey myval
run_script { run_script {
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment