From 81095e732c4954da94977433d3b3693811131058 Mon Sep 17 00:00:00 2001 From: Che-Liang Chiou Date: Sun, 11 Jan 2026 00:31:26 +0800 Subject: [PATCH] fix: zeroObject double-far pointer deref --- .../main/java/org/capnproto/WireHelpers.java | 4 +- .../test/java/org/capnproto/LayoutTest.java | 94 +++++++++++++++++++ 2 files changed, 96 insertions(+), 2 deletions(-) diff --git a/runtime/src/main/java/org/capnproto/WireHelpers.java b/runtime/src/main/java/org/capnproto/WireHelpers.java index 8df40a57..956b38b7 100644 --- a/runtime/src/main/java/org/capnproto/WireHelpers.java +++ b/runtime/src/main/java/org/capnproto/WireHelpers.java @@ -203,9 +203,9 @@ static void zeroObject(SegmentBuilder segment, int refOffset) { int padOffset = FarPointer.positionInSegment(ref); long pad = segment.get(padOffset); if (FarPointer.isDoubleFar(ref)) { - SegmentBuilder otherSegment = segment.getArena().getSegment(FarPointer.getSegmentId(ref)); + SegmentBuilder otherSegment = segment.getArena().getSegment(FarPointer.getSegmentId(pad)); if (otherSegment.isWritable()) { - zeroObject(otherSegment, padOffset + 1, FarPointer.positionInSegment(pad)); + zeroObject(otherSegment, segment.get(padOffset + 1), FarPointer.positionInSegment(pad)); } segment.buffer.putLong(padOffset * 8, 0L); segment.buffer.putLong((padOffset + 1) * 8, 0L); diff --git a/runtime/src/test/java/org/capnproto/LayoutTest.java b/runtime/src/test/java/org/capnproto/LayoutTest.java index acd0a81e..d0448694 100644 --- a/runtime/src/test/java/org/capnproto/LayoutTest.java +++ b/runtime/src/test/java/org/capnproto/LayoutTest.java @@ -6,6 +6,7 @@ import java.nio.ByteBuffer; import java.nio.ByteOrder; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; @@ -181,4 +182,97 @@ private void checkStruct(StructBuilder builder) { assertEquals(true, builder._getBooleanField(126)); assertEquals(false, builder._getBooleanField(127)); } + + @Test + public void testWireHelpersZeroObjectFarPointer() { + byte ffff = (byte)0xff; + byte[][] segments; + byte[][] expect; + + segments = new byte[][] { + { + // Far pointer, offset = 2, segment id = 1. + 0x12, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + ffff, ffff, ffff, ffff, ffff, ffff, ffff, ffff, + }, + { + ffff, ffff, ffff, ffff, ffff, ffff, ffff, ffff, + ffff, ffff, ffff, ffff, ffff, ffff, ffff, ffff, + // Landing pad, offset = 1, list of 6 bytes. + 0x05, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, + ffff, ffff, ffff, ffff, ffff, ffff, ffff, ffff, + // List data. + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, ffff, ffff, + ffff, ffff, ffff, ffff, ffff, ffff, ffff, ffff, + }, + }; + expect = new byte[][] { + { + 0x12, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + ffff, ffff, ffff, ffff, ffff, ffff, ffff, ffff, + }, + { + ffff, ffff, ffff, ffff, ffff, ffff, ffff, ffff, + ffff, ffff, ffff, ffff, ffff, ffff, ffff, ffff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ffff, ffff, ffff, ffff, ffff, ffff, ffff, ffff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ffff, ffff, ffff, ffff, ffff, ffff, ffff, ffff, + }, + }; + doTestWireHelpersZeroObject(segments, expect); + + segments = new byte[][] { + { + // Double-far pointer, offset = 2, segment id = 1. + 0x16, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + ffff, ffff, ffff, ffff, ffff, ffff, ffff, ffff, + }, + { + ffff, ffff, ffff, ffff, ffff, ffff, ffff, ffff, + ffff, ffff, ffff, ffff, ffff, ffff, ffff, ffff, + // Landing pad far pointer, offset = 1, segment id = 2. + 0x0e, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + // Landing pad tag, list of 6 bytes. + 0x01, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, + ffff, ffff, ffff, ffff, ffff, ffff, ffff, ffff, + }, + { + ffff, ffff, ffff, ffff, ffff, ffff, ffff, ffff, + // List data. + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, ffff, ffff, + ffff, ffff, ffff, ffff, ffff, ffff, ffff, ffff, + }, + }; + expect = new byte[][] { + { + 0x16, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + ffff, ffff, ffff, ffff, ffff, ffff, ffff, ffff, + }, + { + ffff, ffff, ffff, ffff, ffff, ffff, ffff, ffff, + ffff, ffff, ffff, ffff, ffff, ffff, ffff, ffff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ffff, ffff, ffff, ffff, ffff, ffff, ffff, ffff, + }, + { + ffff, ffff, ffff, ffff, ffff, ffff, ffff, ffff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ffff, ffff, ffff, ffff, ffff, ffff, ffff, ffff, + }, + }; + doTestWireHelpersZeroObject(segments, expect); + } + + private void doTestWireHelpersZeroObject(byte[][] segments, byte[][] expect) { + ByteBuffer[] buffers = new ByteBuffer[segments.length]; + for (int i = 0; i < segments.length; i++) { + buffers[i] = ByteBuffer.wrap(segments[i]); + buffers[i].order(ByteOrder.LITTLE_ENDIAN); + } + BuilderArena arena = new BuilderArena(new ReaderArena(buffers, 0x7fffffffffffffffL)); + WireHelpers.zeroObject(arena.getSegment(0), 0); + assertArrayEquals(expect, segments); + } }