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()); + } }
