From 2f6190013d29d89c8eed4d0f01567882c1fc8c9b Mon Sep 17 00:00:00 2001 From: "Claude (on behalf of Steven Schlansker)" Date: Fri, 29 May 2026 15:27:24 +0000 Subject: [PATCH 1/3] fix(format): pass row body size, not full payload size, to BinaryRow.pointTo BinaryRowEncoder.decode consumes an 8-byte schema hash, then pointed the row at the rest of the buffer with the full payload size. The row's sizeInBytes was therefore 8 too large, so copy(), toBytes(), and getSizeInBytes() on that row would include 8 trailing bytes of unrelated buffer content. The bug is latent: decode does not expose the row to callers, and the reader index was already advanced correctly by size - 8. The regression test substitutes a capturing GeneratedRowEncoder and asserts BinaryRow.getSizeInBytes() equals the payload minus the schema hash. --- .../fory/format/encoder/BinaryRowEncoder.java | 5 +- .../encoder/BinaryRowEncoderPointToTest.java | 71 +++++++++++++++++++ 2 files changed, 74 insertions(+), 2 deletions(-) create mode 100644 java/fory-format/src/test/java/org/apache/fory/format/encoder/BinaryRowEncoderPointToTest.java diff --git a/java/fory-format/src/main/java/org/apache/fory/format/encoder/BinaryRowEncoder.java b/java/fory-format/src/main/java/org/apache/fory/format/encoder/BinaryRowEncoder.java index b21bff49e9..08c856b039 100644 --- a/java/fory-format/src/main/java/org/apache/fory/format/encoder/BinaryRowEncoder.java +++ b/java/fory-format/src/main/java/org/apache/fory/format/encoder/BinaryRowEncoder.java @@ -81,9 +81,10 @@ T decode(final MemoryBuffer buffer, final int size) { + "Please check writer schema.", schema, schemaHash, peerSchemaHash)); } + final int rowSize = size - 8; final BinaryRow row = codecFactory.newRow(schema); - row.pointTo(buffer, buffer.readerIndex(), size); - buffer.increaseReaderIndex(size - 8); + row.pointTo(buffer, buffer.readerIndex(), rowSize); + buffer.increaseReaderIndex(rowSize); return fromRow(row); } diff --git a/java/fory-format/src/test/java/org/apache/fory/format/encoder/BinaryRowEncoderPointToTest.java b/java/fory-format/src/test/java/org/apache/fory/format/encoder/BinaryRowEncoderPointToTest.java new file mode 100644 index 0000000000..0e0099ecc0 --- /dev/null +++ b/java/fory-format/src/test/java/org/apache/fory/format/encoder/BinaryRowEncoderPointToTest.java @@ -0,0 +1,71 @@ +/* + * 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.fory.format.encoder; + +import lombok.Data; +import org.apache.fory.format.row.binary.BinaryRow; +import org.apache.fory.format.row.binary.writer.BinaryRowWriter; +import org.apache.fory.format.type.Schema; +import org.apache.fory.format.type.TypeInference; +import org.testng.Assert; +import org.testng.annotations.Test; + +/** + * BinaryRowEncoder.decode must record the row body size on BinaryRow, not the full payload size + * including the leading 8-byte schema hash. + */ +public class BinaryRowEncoderPointToTest { + + @Data + public static class Tiny { + private int x; + } + + @Test + public void decodedRowSizeMatchesRowBody() { + Schema schema = TypeInference.inferSchema(Tiny.class); + RowEncoder real = Encoders.bean(Tiny.class); + Tiny in = new Tiny(); + in.setX(42); + byte[] payload = real.encode(in); + + BinaryRow[] captured = new BinaryRow[1]; + GeneratedRowEncoder captor = + new GeneratedRowEncoder() { + @Override + public BinaryRow toRow(Object obj) { + return real.toRow((Tiny) obj); + } + + @Override + public Object fromRow(BinaryRow row) { + captured[0] = row; + return null; + } + }; + + BinaryRowEncoder encoder = + new BinaryRowEncoder<>( + schema, DefaultCodecFormat.INSTANCE, captor, new BinaryRowWriter(schema), false); + encoder.decode(payload); + + Assert.assertNotNull(captured[0], "decode must hand the row to fromRow"); + Assert.assertEquals(captured[0].getSizeInBytes(), payload.length - 8); + } +} From 680edec860912b31b10510202ad58cc633b3ca08 Mon Sep 17 00:00:00 2001 From: "Claude (on behalf of Steven Schlansker)" Date: Thu, 28 May 2026 23:34:21 +0000 Subject: [PATCH 2/3] docs(format): drop stray javadoc fragment on Encoders MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The class javadoc carried a trailing "

, ganrunsheng" line — a truncated attribution. Keep only the one-sentence description. --- .../main/java/org/apache/fory/format/encoder/Encoders.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/java/fory-format/src/main/java/org/apache/fory/format/encoder/Encoders.java b/java/fory-format/src/main/java/org/apache/fory/format/encoder/Encoders.java index 13403c15f3..4a8c45021e 100644 --- a/java/fory-format/src/main/java/org/apache/fory/format/encoder/Encoders.java +++ b/java/fory-format/src/main/java/org/apache/fory/format/encoder/Encoders.java @@ -43,11 +43,7 @@ import org.apache.fory.type.TypeUtils; import org.apache.fory.util.Preconditions; -/** - * Factory to create {@link Encoder}. - * - *

, ganrunsheng - */ +/** Factory to create {@link Encoder}. */ public class Encoders { private static final Logger LOG = LoggerFactory.getLogger(Encoders.class); From f4facff3d3867f37d6bc6dff34f60a2d34463864 Mon Sep 17 00:00:00 2001 From: "Claude (on behalf of Steven Schlansker)" Date: Thu, 28 May 2026 23:35:36 +0000 Subject: [PATCH 3/3] docs(format): note byte[] decode skips sizeEmbedded by design The MemoryBuffer overloads respect sizeEmbedded for stream framing; the byte[] overloads do not, because encode(T) writes no size prefix and decode(byte[]) uses bytes.length. Comment the three byte[] decode methods so the asymmetry isn't mistaken for a bug. --- .../java/org/apache/fory/format/encoder/BinaryArrayEncoder.java | 1 + .../java/org/apache/fory/format/encoder/BinaryMapEncoder.java | 1 + .../java/org/apache/fory/format/encoder/BinaryRowEncoder.java | 1 + 3 files changed, 3 insertions(+) diff --git a/java/fory-format/src/main/java/org/apache/fory/format/encoder/BinaryArrayEncoder.java b/java/fory-format/src/main/java/org/apache/fory/format/encoder/BinaryArrayEncoder.java index f40a968aa8..d1b2b9184f 100644 --- a/java/fory-format/src/main/java/org/apache/fory/format/encoder/BinaryArrayEncoder.java +++ b/java/fory-format/src/main/java/org/apache/fory/format/encoder/BinaryArrayEncoder.java @@ -62,6 +62,7 @@ public T decode(final MemoryBuffer buffer) { @Override public T decode(final byte[] bytes) { + // byte[] overloads ignore sizeEmbedded: encode writes no size prefix, decode uses bytes.length. return decode(MemoryUtils.wrap(bytes), bytes.length); } diff --git a/java/fory-format/src/main/java/org/apache/fory/format/encoder/BinaryMapEncoder.java b/java/fory-format/src/main/java/org/apache/fory/format/encoder/BinaryMapEncoder.java index 925bdc332b..90ba96dc5e 100644 --- a/java/fory-format/src/main/java/org/apache/fory/format/encoder/BinaryMapEncoder.java +++ b/java/fory-format/src/main/java/org/apache/fory/format/encoder/BinaryMapEncoder.java @@ -85,6 +85,7 @@ M decode(final MemoryBuffer buffer, final int size) { @Override public M decode(final byte[] bytes) { + // byte[] overloads ignore sizeEmbedded: encode writes no size prefix, decode uses bytes.length. return decode(MemoryUtils.wrap(bytes), bytes.length); } diff --git a/java/fory-format/src/main/java/org/apache/fory/format/encoder/BinaryRowEncoder.java b/java/fory-format/src/main/java/org/apache/fory/format/encoder/BinaryRowEncoder.java index 08c856b039..296ee546f3 100644 --- a/java/fory-format/src/main/java/org/apache/fory/format/encoder/BinaryRowEncoder.java +++ b/java/fory-format/src/main/java/org/apache/fory/format/encoder/BinaryRowEncoder.java @@ -90,6 +90,7 @@ T decode(final MemoryBuffer buffer, final int size) { @Override public T decode(final byte[] bytes) { + // byte[] overloads ignore sizeEmbedded: encode writes no size prefix, decode uses bytes.length. return decode(MemoryUtils.wrap(bytes), bytes.length); }