This is an automated email from the ASF dual-hosted git repository.

binbin pushed a commit to branch unstable
in repository https://gitbox.apache.org/repos/asf/kvrocks.git


The following commit(s) were added to refs/heads/unstable by this push:
     new 54423b6a Fix LPOS rank passing LLONG_MIN overflow issue (#1687)
54423b6a is described below

commit 54423b6a545ccdb849e2a6b038cbc559f58e3d4a
Author: Binbin <[email protected]>
AuthorDate: Mon Aug 21 17:30:55 2023 +0800

    Fix LPOS rank passing LLONG_MIN overflow issue (#1687)
    
    There is a minor overflow issue in RANK negation, passing LLONG_MIN
    will overflow and is effectively be the same as passing -1.
    
    This is the example before the fix:
    ```
    127.0.0.1:6666> flushall
    OK
    127.0.0.1:6666> lpos mylist foo rank -9223372036854775808
    (nil)
    127.0.0.1:6666> lpush mylist foo foo foo foo foo
    (integer) 5
    
    127.0.0.1:6666> lpos mylist foo rank -1
    (integer) 4
    127.0.0.1:6666> lpos mylist foo rank -5
    (integer) 0
    127.0.0.1:6666> lpos mylist foo rank -6
    (nil)
    127.0.0.1:6666> lpos mylist foo rank -9223372036854775807
    (nil)
    
    -- this should return nil but it returned the last one because the overflow 
rank became -1
    127.0.0.1:6666> lpos mylist foo rank -9223372036854775808
    (integer) 4
    ```
    
    Now we limit RANK to not be LLONG_MIN and will throw an error directly
    (this is the behavior of Redis 7.2, but with different error words):
    ```
    127.0.0.1:6666> lpos mylist foo rank -9223372036854775808
    (error) ERR rank would overflow
    
    127.0.0.1:6379> lpos mylist foo rank -9223372036854775808
    (error) ERR value is out of range, value must between -9223372036854775807 
and 9223372036854775807
    ```
    
    Unrelated change: a small cleanup, return RedisParseErr instead of
    RedisExecErr in Parse.
---
 src/commands/cmd_list.cc                 | 7 +++++--
 tests/gocase/unit/type/list/list_test.go | 5 +++++
 2 files changed, 10 insertions(+), 2 deletions(-)

diff --git a/src/commands/cmd_list.cc b/src/commands/cmd_list.cc
index 60621fdf..1ad581a6 100644
--- a/src/commands/cmd_list.cc
+++ b/src/commands/cmd_list.cc
@@ -697,16 +697,19 @@ class CommandLPos : public Commander {
                   "RANK can't be zero: use 1 to start from "
                   "the first match, 2 from the second ... "
                   "or use negative to start from the end of the list"};
+        } else if (spec_.rank == LLONG_MIN) {
+          // Negating LLONG_MIN will cause an overflow, and is effectively be 
the same as passing -1.
+          return {Status::RedisParseErr, "rank would overflow"};
         }
       } else if (parser.EatEqICase("count")) {
         spec_.count = GET_OR_RET(parser.TakeInt());
         if (spec_.count < 0) {
-          return {Status::RedisExecErr, "COUNT can't be negative"};
+          return {Status::RedisParseErr, "COUNT can't be negative"};
         }
       } else if (parser.EatEqICase("maxlen")) {
         spec_.max_len = GET_OR_RET(parser.TakeInt());
         if (spec_.max_len < 0) {
-          return {Status::RedisExecErr, "MAXLEN can't be negative"};
+          return {Status::RedisParseErr, "MAXLEN can't be negative"};
         }
       } else {
         return {Status::RedisParseErr, errInvalidSyntax};
diff --git a/tests/gocase/unit/type/list/list_test.go 
b/tests/gocase/unit/type/list/list_test.go
index 2cf2e317..b7db17e7 100644
--- a/tests/gocase/unit/type/list/list_test.go
+++ b/tests/gocase/unit/type/list/list_test.go
@@ -942,6 +942,11 @@ func TestList(t *testing.T) {
                require.Equal(t, "bar", rdb.LRange(ctx, "target", 0, 
-1).Val()[0])
        })
 
+       t.Run("LPOS rank negation overflow", func(t *testing.T) {
+               require.NoError(t, rdb.Del(ctx, "mylist").Err())
+               util.ErrorRegexp(t, rdb.Do(ctx, "LPOS", "mylist", "foo", 
"RANK", "-9223372036854775808").Err(), ".*rank would overflow.*")
+       })
+
        for listType, large := range largeValue {
                t.Run(fmt.Sprintf("LPOS basic usage - %s", listType), func(t 
*testing.T) {
                        createList("mylist", []string{"a", "b", "c", large, 
"2", "3", "c", "c"})

Reply via email to