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

RongtongJin pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/rocketmq.git


The following commit(s) were added to refs/heads/develop by this push:
     new bb996b4a50 [ISSUE #11283] fix(remoting): RpcClientUtils.encodeBody 
must not clobber the caller's ByteBuffer mark (#11296)
bb996b4a50 is described below

commit bb996b4a5053a644375ceee2a8d897df4312aec2
Author: 健康宝 <[email protected]>
AuthorDate: Thu Oct 8 10:46:11 2026 +0800

    [ISSUE #11283] fix(remoting): RpcClientUtils.encodeBody must not clobber 
the caller's ByteBuffer mark (#11296)
    
    encodeBody used mark()/get()/reset() on the caller's buffer, which
    restored the position but silently overwrote any mark the caller had set,
    so a later reset() jumped to the wrong position. Read the remaining bytes
    from a duplicate() instead, leaving the original buffer's position, limit
    and mark untouched, and add a regression test.
    
    Co-authored-by: Claude Opus 5 (1M context) <[email protected]>
---
 .../rocketmq/remoting/rpc/RpcClientUtils.java      |  4 +-
 .../rocketmq/remoting/rpc/RpcClientUtilsTest.java  | 87 ++++++++++++++++++++++
 2 files changed, 88 insertions(+), 3 deletions(-)

diff --git 
a/remoting/src/main/java/org/apache/rocketmq/remoting/rpc/RpcClientUtils.java 
b/remoting/src/main/java/org/apache/rocketmq/remoting/rpc/RpcClientUtils.java
index 78a33b72c5..68f16807c2 100644
--- 
a/remoting/src/main/java/org/apache/rocketmq/remoting/rpc/RpcClientUtils.java
+++ 
b/remoting/src/main/java/org/apache/rocketmq/remoting/rpc/RpcClientUtils.java
@@ -44,11 +44,9 @@ public class RpcClientUtils {
         } else if (body instanceof RemotingSerializable) {
             return ((RemotingSerializable) body).encode();
         } else if (body instanceof ByteBuffer) {
-            ByteBuffer buffer = (ByteBuffer)body;
-            buffer.mark();
+            ByteBuffer buffer = ((ByteBuffer)body).duplicate();
             byte[] data = new byte[buffer.remaining()];
             buffer.get(data);
-            buffer.reset();
             return data;
         } else {
             throw new RuntimeException("Unsupported body type " + 
body.getClass());
diff --git 
a/remoting/src/test/java/org/apache/rocketmq/remoting/rpc/RpcClientUtilsTest.java
 
b/remoting/src/test/java/org/apache/rocketmq/remoting/rpc/RpcClientUtilsTest.java
new file mode 100644
index 0000000000..1208ca7cd7
--- /dev/null
+++ 
b/remoting/src/test/java/org/apache/rocketmq/remoting/rpc/RpcClientUtilsTest.java
@@ -0,0 +1,87 @@
+/*
+ * 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 org.apache.rocketmq.remoting.rpc;
+
+import java.nio.ByteBuffer;
+import org.junit.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class RpcClientUtilsTest {
+
+    @Test
+    public void testEncodeBodyByteBufferPreservesCallerMarkAndPosition() {
+        ByteBuffer buffer = ByteBuffer.allocate(5);
+        buffer.put(new byte[] {1, 2, 3, 4, 5});
+        buffer.flip();
+        buffer.position(1);
+        buffer.mark();
+        buffer.position(3);
+
+        byte[] data = RpcClientUtils.encodeBody(buffer);
+
+        assertThat(data).hasSize(2);
+        assertThat(data).containsExactly((byte) 4, (byte) 5);
+        assertThat(buffer.position()).isEqualTo(3);
+        assertThat(buffer.limit()).isEqualTo(5);
+        // Regression for issue #11283: the caller's mark must survive 
encodeBody,
+        // so reset() rewinds to the marked position instead of the current 
one.
+        buffer.reset();
+        assertThat(buffer.position()).isEqualTo(1);
+    }
+
+    @Test
+    public void testEncodeBodyByteBufferReadsRemainingBytes() {
+        ByteBuffer buffer = ByteBuffer.allocate(5);
+        buffer.put(new byte[] {1, 2, 3, 4, 5});
+        buffer.flip();
+
+        byte[] data = RpcClientUtils.encodeBody(buffer);
+
+        assertThat(data).containsExactly((byte) 1, (byte) 2, (byte) 3, (byte) 
4, (byte) 5);
+        assertThat(buffer.position()).isEqualTo(0);
+        assertThat(buffer.limit()).isEqualTo(5);
+    }
+
+    @Test
+    public void testEncodeBodyByteBufferReadOnly() {
+        ByteBuffer buffer = ByteBuffer.allocate(5);
+        buffer.put(new byte[] {1, 2, 3, 4, 5});
+        buffer.flip();
+        buffer.position(2);
+        ByteBuffer readOnlyBuffer = buffer.asReadOnlyBuffer();
+
+        byte[] data = RpcClientUtils.encodeBody(readOnlyBuffer);
+
+        assertThat(data).containsExactly((byte) 3, (byte) 4, (byte) 5);
+        assertThat(readOnlyBuffer.position()).isEqualTo(2);
+        assertThat(readOnlyBuffer.limit()).isEqualTo(5);
+    }
+
+    @Test
+    public void testEncodeBodyNullReturnsNull() {
+        assertThat(RpcClientUtils.encodeBody(null)).isNull();
+    }
+
+    @Test
+    public void testEncodeBodyByteArrayPassthrough() {
+        byte[] body = new byte[] {1, 2, 3};
+
+        assertThat(RpcClientUtils.encodeBody(body)).isSameAs(body);
+    }
+}

Reply via email to