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

git-hulk 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 d69035320 fix(commands): fix out-of-bounds access in CLIENT KILL 
argument parsing (#3661)
d69035320 is described below

commit d69035320ca27f3226c71cf09acdb25efbe60e82
Author: weimeng <[email protected]>
AuthorDate: Wed Oct 14 16:41:18 2026 +0800

    fix(commands): fix out-of-bounds access in CLIENT KILL argument parsing 
(#3661)
    
    ## Summary
    
    Fix a bounds-check bug in `CLIENT KILL` new-format argument parsing
    where a
    keyword at the end of the argument list with no following value could
    lead to
    an out-of-bounds read instead of returning a syntax error.
    
    ## Root Cause
    
    In `src/commands/cmd_server.cc`, the `ClientKillSubCommand::Parse`
    method uses
    a `more_args` guard to check whether a value follows each keyword before
    accessing `args[i + 1]`:
    
    ```cpp
    bool more_args = i < args.size();
    ```
    
    
    ## AI Usage Disclosure
    - The bug fix was implemented manually.
    - AI tools(Qoder) were used to assist in generating unit test
    scaffolding; all tests were reviewed and verified by the author.
    
    ---------
    
    Co-authored-by: weimeng <[email protected]>
    Co-authored-by: Copilot Autofix powered by AI 
<[email protected]>
    Co-authored-by: Aleks Lozovyuk <[email protected]>
---
 src/commands/cmd_server.cc                   |  2 +-
 tests/gocase/unit/client/client_kill_test.go | 70 ++++++++++++++++++++++++++++
 2 files changed, 71 insertions(+), 1 deletion(-)

diff --git a/src/commands/cmd_server.cc b/src/commands/cmd_server.cc
index b57382b53..ac1fd2561 100644
--- a/src/commands/cmd_server.cc
+++ b/src/commands/cmd_server.cc
@@ -610,7 +610,7 @@ class CommandClient : public Commander {
       new_format_ = true;
 
       while (i < args.size()) {
-        bool more_args = i < args.size();
+        bool more_args = i + 1 < args.size();
         if (util::EqualICase(args[i], "addr") && more_args) {
           addr_ = args[i + 1];
         } else if (util::EqualICase(args[i], "id") && more_args) {
diff --git a/tests/gocase/unit/client/client_kill_test.go 
b/tests/gocase/unit/client/client_kill_test.go
new file mode 100644
index 000000000..789d1043f
--- /dev/null
+++ b/tests/gocase/unit/client/client_kill_test.go
@@ -0,0 +1,70 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package client
+
+import (
+       "context"
+       "strings"
+       "testing"
+
+       "github.com/apache/kvrocks/tests/gocase/util"
+       "github.com/stretchr/testify/require"
+)
+
+func TestClientKillParseEdgeCases(t *testing.T) {
+       srv := util.StartServer(t, map[string]string{})
+       defer srv.Close()
+
+       ctx := context.Background()
+       rdb := srv.NewClient()
+       defer func() { require.NoError(t, rdb.Close()) }()
+
+       t.Run("CLIENT KILL with keyword but missing value returns error", 
func(t *testing.T) {
+               keywords := []string{"addr", "id", "skipme", "type"}
+               for _, kw := range keywords {
+                       err := rdb.Do(ctx, "CLIENT", "KILL", "addr", 
"127.0.0.1:1234", kw).Err()
+                       require.ErrorContains(t, err, "syntax", "CLIENT KILL %s 
should fail with a syntax error", kw)
+               }
+       })
+
+       t.Run("CLIENT KILL with odd number of new-format args returns syntax 
error", func(t *testing.T) {
+               err := rdb.Do(ctx, "CLIENT", "KILL", "addr", "127.0.0.1:1234", 
"type").Err()
+               require.Error(t, err)
+               require.True(t, strings.Contains(err.Error(), "syntax") || 
strings.Contains(err.Error(), "Syntax"),
+                       "expected syntax error, got: %s", err.Error())
+       })
+
+       t.Run("CLIENT KILL with unknown option returns syntax error", func(t 
*testing.T) {
+               err := rdb.Do(ctx, "CLIENT", "KILL", "unknown", "value").Err()
+               require.Error(t, err)
+               require.True(t, strings.Contains(err.Error(), "syntax") || 
strings.Contains(err.Error(), "Syntax"),
+                       "expected syntax error, got: %s", err.Error())
+       })
+
+       t.Run("CLIENT KILL with valid new-format options succeeds", func(t 
*testing.T) {
+               err := rdb.Do(ctx, "CLIENT", "KILL", "addr", 
"127.0.0.1:1234").Err()
+               require.NoError(t, err)
+       })
+
+       t.Run("CLIENT KILL with multiple valid options succeeds", func(t 
*testing.T) {
+               err := rdb.Do(ctx, "CLIENT", "KILL", "type", "normal", 
"skipme", "yes").Err()
+               require.NoError(t, err)
+       })
+}

Reply via email to