This is an automated email from the ASF dual-hosted git repository.

FrankChen021 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/druid.git


The following commit(s) were added to refs/heads/master by this push:
     new 195d1e1b847 fix: validate blockSize and numBlocks in 
CompressedBlockReader (#20243)
195d1e1b847 is described below

commit 195d1e1b847d25737f01d61fcee6613155e971f6
Author: dfengliu <[email protected]>
AuthorDate: Fri Sep 4 10:28:55 2026 +0800

    fix: validate blockSize and numBlocks in CompressedBlockReader (#20243)
    
    * fix: validate blockSize and numBlocks in CompressedBlockReader
    
    * fix checkstyle: end file with newline, keep call args on single line
    
    * fix: pass numBlocks to format string to satisfy Error Prone 
LenientFormatStringValidation
---
 .../druid/segment/data/CompressedBlockReader.java  |   7 ++
 .../segment/data/CompressedBlockReaderTest.java    | 106 +++++++++++++++++++++
 2 files changed, 113 insertions(+)

diff --git 
a/processing/src/main/java/org/apache/druid/segment/data/CompressedBlockReader.java
 
b/processing/src/main/java/org/apache/druid/segment/data/CompressedBlockReader.java
index 78138a5aa53..76e9e00e10b 100644
--- 
a/processing/src/main/java/org/apache/druid/segment/data/CompressedBlockReader.java
+++ 
b/processing/src/main/java/org/apache/druid/segment/data/CompressedBlockReader.java
@@ -72,7 +72,14 @@ public final class CompressedBlockReader implements Closeable
           blockSize <= CompressedPools.BUFFER_SIZE,
           "Maximum block size must be less than " + CompressedPools.BUFFER_SIZE
       );
+      Preconditions.checkArgument(blockSize > 0, "Block size[%s] must be 
positive", blockSize);
       final int numBlocks = buffer.getInt();
+      Preconditions.checkArgument(numBlocks > 0, "Number of blocks[%s] must be 
positive", numBlocks);
+      Preconditions.checkArgument(
+          (long) numBlocks * Integer.BYTES <= buffer.remaining(),
+          "Number of blocks[%s] exceeds the available buffer",
+          numBlocks
+      );
       final int offsetsSize = numBlocks * Integer.BYTES;
       // buffer is at start of ending offsets
       final ByteBuffer offsets = 
buffer.asReadOnlyBuffer().order(compressionOrder);
diff --git 
a/processing/src/test/java/org/apache/druid/segment/data/CompressedBlockReaderTest.java
 
b/processing/src/test/java/org/apache/druid/segment/data/CompressedBlockReaderTest.java
new file mode 100644
index 00000000000..b247ccfdaad
--- /dev/null
+++ 
b/processing/src/test/java/org/apache/druid/segment/data/CompressedBlockReaderTest.java
@@ -0,0 +1,106 @@
+/*
+ * 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.druid.segment.data;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+public class CompressedBlockReaderTest
+{
+  private static ByteBuffer header(int blockSize, int numBlocks)
+  {
+    final ByteBuffer buffer = 
ByteBuffer.allocate(64).order(ByteOrder.nativeOrder());
+    buffer.put(CompressedBlockReader.VERSION);
+    buffer.put(CompressionStrategy.UNCOMPRESSED.getId());
+    buffer.putInt(blockSize);
+    buffer.putInt(numBlocks);
+    buffer.flip();
+    return buffer;
+  }
+
+  @Test
+  public void testNumBlocksZeroRejected()
+  {
+    final IllegalArgumentException e = Assertions.assertThrows(
+        IllegalArgumentException.class,
+        () -> CompressedBlockReader.fromByteBuffer(
+            header(64, 0), ByteOrder.nativeOrder(), ByteOrder.nativeOrder(), 
false
+        )
+    );
+    Assertions.assertTrue(e.getMessage().contains("Number of blocks[0] must be 
positive"), e.getMessage());
+  }
+
+  @Test
+  public void testNumBlocksNegativeRejected()
+  {
+    final IllegalArgumentException e = Assertions.assertThrows(
+        IllegalArgumentException.class,
+        () -> CompressedBlockReader.fromByteBuffer(
+            header(64, -5), ByteOrder.nativeOrder(), ByteOrder.nativeOrder(), 
false
+        )
+    );
+    Assertions.assertTrue(e.getMessage().contains("Number of blocks[-5] must 
be positive"), e.getMessage());
+  }
+
+  @Test
+  public void testBlockSizeZeroRejected()
+  {
+    final IllegalArgumentException e = Assertions.assertThrows(
+        IllegalArgumentException.class,
+        () -> CompressedBlockReader.fromByteBuffer(
+            header(0, 1), ByteOrder.nativeOrder(), ByteOrder.nativeOrder(), 
false
+        )
+    );
+    Assertions.assertTrue(e.getMessage().contains("Block size[0] must be 
positive"), e.getMessage());
+  }
+
+  @Test
+  public void testNumBlocksBeyondBufferRejected()
+  {
+    final IllegalArgumentException e = Assertions.assertThrows(
+        IllegalArgumentException.class,
+        () -> CompressedBlockReader.fromByteBuffer(
+            header(64, 32), ByteOrder.nativeOrder(), ByteOrder.nativeOrder(), 
false
+        )
+    );
+    Assertions.assertTrue(e.getMessage().contains("exceeds the available 
buffer"), e.getMessage());
+  }
+
+  @Test
+  public void testValidHeaderAccepted()
+  {
+    final ByteBuffer buffer = 
ByteBuffer.allocate(64).order(ByteOrder.nativeOrder());
+    buffer.put(CompressedBlockReader.VERSION);
+    buffer.put(CompressionStrategy.UNCOMPRESSED.getId());
+    buffer.putInt(64); // blockSize
+    buffer.putInt(2);  // numBlocks
+    buffer.putInt(4);  // offsets
+    buffer.putInt(8);
+    buffer.putInt(0);  // compressed bytes
+    buffer.putInt(0);
+    buffer.flip();
+
+    CompressedBlockReader.fromByteBuffer(buffer, ByteOrder.nativeOrder(), 
ByteOrder.nativeOrder(), false);
+    Assertions.assertTrue(true);
+  }
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to