From 72656fa60597b6fdbd15f1641dd076a47ce60852 Mon Sep 17 00:00:00 2001 From: Dongjoon Hyun Date: Sat, 13 Jun 2026 14:09:05 -0700 Subject: [PATCH] [SPARK-57426] Validate length before allocation in `Encoders.Strings.decode` --- .../spark/network/protocol/Encoders.java | 2 ++ .../spark/network/protocol/EncodersSuite.java | 22 +++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/common/network-common/src/main/java/org/apache/spark/network/protocol/Encoders.java b/common/network-common/src/main/java/org/apache/spark/network/protocol/Encoders.java index 8bab808ad6864..488e36004f2f3 100644 --- a/common/network-common/src/main/java/org/apache/spark/network/protocol/Encoders.java +++ b/common/network-common/src/main/java/org/apache/spark/network/protocol/Encoders.java @@ -20,6 +20,7 @@ import java.io.IOException; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; +import java.util.Objects; import io.netty.buffer.ByteBuf; import org.roaringbitmap.RoaringBitmap; @@ -41,6 +42,7 @@ public static void encode(ByteBuf buf, String s) { public static String decode(ByteBuf buf) { int length = buf.readInt(); + Objects.checkFromIndexSize(0, length, buf.readableBytes()); byte[] bytes = new byte[length]; buf.readBytes(bytes); return new String(bytes, StandardCharsets.UTF_8); diff --git a/common/network-common/src/test/java/org/apache/spark/network/protocol/EncodersSuite.java b/common/network-common/src/test/java/org/apache/spark/network/protocol/EncodersSuite.java index 127835d29bc01..55b09b66aef64 100644 --- a/common/network-common/src/test/java/org/apache/spark/network/protocol/EncodersSuite.java +++ b/common/network-common/src/test/java/org/apache/spark/network/protocol/EncodersSuite.java @@ -48,6 +48,28 @@ public void testRoaringBitmapEncodeShouldFailWhenBufferIsSmall() { () -> Encoders.Bitmaps.encode(buf, bitmap)); } + @Test + public void testStringsEncodeDecode() { + String s = "spark"; + ByteBuf buf = Unpooled.buffer(Encoders.Strings.encodedLength(s)); + Encoders.Strings.encode(buf, s); + assertEquals(s, Encoders.Strings.decode(buf)); + } + + @Test + public void testStringsDecodeShouldFailWhenLengthIsNegative() { + ByteBuf buf = Unpooled.buffer(); + buf.writeInt(-1); + assertThrows(IndexOutOfBoundsException.class, () -> Encoders.Strings.decode(buf)); + } + + @Test + public void testStringsDecodeShouldFailWhenLengthExceedsReadableBytes() { + ByteBuf buf = Unpooled.buffer(); + buf.writeInt(Integer.MAX_VALUE); + assertThrows(IndexOutOfBoundsException.class, () -> Encoders.Strings.decode(buf)); + } + @Test public void testBitmapArraysEncodeDecode() { RoaringBitmap[] bitmaps = new RoaringBitmap[] {