Skip to content

Commit 2e3dc3a

Browse files
stevenschlanskerchaokunyang
authored andcommitted
fix(java): row format buffer recycling leaves offset and size for null values (#2540)
1 parent 55bddbb commit 2e3dc3a

3 files changed

Lines changed: 26 additions & 3 deletions

File tree

java/fory-format/src/main/java/org/apache/fory/format/row/binary/writer/BinaryRowWriter.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,12 @@ public void write(int ordinal, BigDecimal value) {
128128
writeDecimal(ordinal, value, (ArrowType.Decimal) schema.getFields().get(ordinal).getType());
129129
}
130130

131+
@Override
132+
public void setNullAt(int ordinal) {
133+
super.setNullAt(ordinal);
134+
write(ordinal, 0L);
135+
}
136+
131137
public BinaryRow getRow() {
132138
BinaryRow row = new BinaryRow(schema);
133139
int size = size();

java/fory-format/src/main/java/org/apache/fory/format/row/binary/writer/BinaryWriter.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -121,10 +121,10 @@ protected final void zeroOutPaddingBytes(int numBytes) {
121121
}
122122

123123
/**
124-
* Since writer is used for one-pass writer, same field won't be writer twice. There is no need to
125-
* put zero into the corresponding field when set null.
124+
* Writer might recycle buffers, so implementations should clear data from a previous not-null
125+
* write when setting null to avoid information leaks.
126126
*/
127-
public final void setNullAt(int ordinal) {
127+
public void setNullAt(int ordinal) {
128128
BitUtils.set(buffer, startIndex + bytesBeforeBitMap, ordinal);
129129
}
130130

java/fory-format/src/test/java/org/apache/fory/format/encoder/RowEncoderTest.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,4 +118,21 @@ public void testPrivateBean() {
118118
Assert.assertEquals(s1.f1, s.f1);
119119
Assert.assertEquals(s1.f2, s.f2);
120120
}
121+
122+
@Test
123+
public void testNullClearOffset() {
124+
RowEncoder<Bar> encoder = Encoders.bean(Bar.class);
125+
Bar bar = new Bar();
126+
bar.f1 = 42;
127+
bar.f2 = null;
128+
byte[] nullBefore = encoder.encode(bar);
129+
130+
bar.f2 = "not null";
131+
// write offset and size
132+
encoder.encode(bar);
133+
134+
bar.f2 = null;
135+
byte[] nullAfter = encoder.encode(bar);
136+
Assert.assertEquals(nullAfter, nullBefore);
137+
}
121138
}

0 commit comments

Comments
 (0)