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

kenhuuu pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git

commit eadea8a53e9d40dd1cd4ef16c2e7386fc95e375a
Author: Ken Hu <[email protected]>
AuthorDate: Wed Jun 3 15:18:48 2026 -0700

    Fix ByteBuf leak when IOException thrown during serialization CTR
    
    Assisted-by: Claude Code:claude-opus-4-6
---
 CHANGELOG.asciidoc                                   |  1 +
 .../util/ser/GraphBinaryMessageSerializerV4.java     |  1 +
 .../binary/GraphBinaryMessageSerializerV4Test.java   | 20 ++++++++++++++++++++
 3 files changed, 22 insertions(+)

diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc
index 3d3284d480..424408b53d 100644
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@ -25,6 +25,7 @@ 
image::https://raw.githubusercontent.com/apache/tinkerpop/master/docs/static/ima
 [[release-4-0-0]]
 === TinkerPop 4.0.0 (Release Date: NOT OFFICIALLY RELEASED YET)
 
+* Fixed `ByteBuf` leak in `GraphBinaryMessageSerializerV4` when serialization 
throws an `IOException`.
 * Added typed numeric wrappers and `preciseNumbers` connection option to 
`gremlin-javascript` for explicit control over numeric type serialization and 
deserialization.
 * Added `NextN(n)` to `Traversal` in `gremlin-go` for batched result 
iteration, providing API parity with `next(n)` in the Java, Python, and .NET 
GLVs, and updated the Go translators in `gremlin-core` and `gremlin-javascript` 
to emit `NextN(n)` for the batched form.
 * Added Gremlator, a single page web application, that translates Gremlin into 
various programming languages like Javascript and Python.
diff --git 
a/gremlin-util/src/main/java/org/apache/tinkerpop/gremlin/util/ser/GraphBinaryMessageSerializerV4.java
 
b/gremlin-util/src/main/java/org/apache/tinkerpop/gremlin/util/ser/GraphBinaryMessageSerializerV4.java
index e9c7a97f82..5ad6c8f04e 100644
--- 
a/gremlin-util/src/main/java/org/apache/tinkerpop/gremlin/util/ser/GraphBinaryMessageSerializerV4.java
+++ 
b/gremlin-util/src/main/java/org/apache/tinkerpop/gremlin/util/ser/GraphBinaryMessageSerializerV4.java
@@ -252,6 +252,7 @@ public class GraphBinaryMessageSerializerV4 extends 
AbstractMessageSerializer<Gr
                 writer.writeValue(status.getException(), buffer, true);
             }
         } catch (IOException e) {
+            byteBuf.release();
             throw new SerializationException(e);
         }
         return byteBuf;
diff --git 
a/gremlin-util/src/test/java/org/apache/tinkerpop/gremlin/util/ser/binary/GraphBinaryMessageSerializerV4Test.java
 
b/gremlin-util/src/test/java/org/apache/tinkerpop/gremlin/util/ser/binary/GraphBinaryMessageSerializerV4Test.java
index 07a14e60d1..add9f215e7 100644
--- 
a/gremlin-util/src/test/java/org/apache/tinkerpop/gremlin/util/ser/binary/GraphBinaryMessageSerializerV4Test.java
+++ 
b/gremlin-util/src/test/java/org/apache/tinkerpop/gremlin/util/ser/binary/GraphBinaryMessageSerializerV4Test.java
@@ -20,15 +20,18 @@ package org.apache.tinkerpop.gremlin.util.ser.binary;
 
 import io.netty.buffer.ByteBuf;
 import io.netty.buffer.ByteBufAllocator;
+import io.netty.buffer.Unpooled;
 import io.netty.handler.codec.http.HttpResponseStatus;
 import org.apache.tinkerpop.gremlin.structure.io.binary.TypeSerializerRegistry;
 import org.apache.tinkerpop.gremlin.util.message.ResponseMessage;
 import org.apache.tinkerpop.gremlin.util.ser.GraphBinaryMessageSerializerV4;
 import org.apache.tinkerpop.gremlin.util.ser.SerializationException;
 import org.junit.Test;
+import org.mockito.Mockito;
 
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -36,6 +39,7 @@ import java.util.concurrent.atomic.AtomicInteger;
 import java.util.stream.Stream;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
 
 public class GraphBinaryMessageSerializerV4Test {
 
@@ -220,4 +224,20 @@ public class GraphBinaryMessageSerializerV4Test {
         return responseMessage.getResult() == null || 
responseMessage.getResult().getData() == null ||
                 responseMessage.getResult().getData().isEmpty();
     }
+
+    @Test
+    public void shouldReleaseByteBufOnWriteFailure() {
+        final ByteBuf buf = Unpooled.buffer();
+        final ByteBufAllocator mockAllocator = 
Mockito.mock(ByteBufAllocator.class);
+        Mockito.when(mockAllocator.buffer()).thenReturn(buf);
+
+        try {
+            serializer.writeChunk(Collections.singletonList(new Object()), 
mockAllocator);
+            fail("Expected SerializationException");
+        } catch (SerializationException e) {
+            // expected
+        }
+
+        assertEquals(0, buf.refCnt());
+    }
 }

Reply via email to