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

chaokunyang pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/fory.git


The following commit(s) were added to refs/heads/main by this push:
     new 40d1e4c10 fix(java): guard aligned varint unsafe read (#3772)
40d1e4c10 is described below

commit 40d1e4c109940fc023a62203911bc0a878fb3ae7
Author: Shawn Yang <[email protected]>
AuthorDate: Sun Jun 21 08:40:02 2026 +0530

    fix(java): guard aligned varint unsafe read (#3772)
    
    ## Why?
    
    
    
    ## What does this PR do?
    
    
    
    ## Related issues
    
    
    
    ## AI Contribution Checklist
    
    
    
    - [ ] Substantial AI assistance was used in this PR: `yes` / `no`
    - [ ] If `yes`, I included a completed [AI Contribution
    
Checklist](https://github.com/apache/fory/blob/main/AI_POLICY.md#9-contributor-checklist-for-ai-assisted-prs)
    in this PR description and the required `AI Usage Disclosure`.
    - [ ] If `yes`, my PR description includes the required `ai_review`
    summary and screenshot evidence of the final clean AI review results
    from both fresh reviewers on the current PR diff or current HEAD after
    the latest code changes.
    
    
    
    ## Does this PR introduce any user-facing change?
    
    
    
    - [ ] Does this PR introduce any public API change?
    - [ ] Does this PR introduce any binary protocol compatibility change?
    
    ## Benchmark
---
 java/fory-core/pom.xml                                       |  2 ++
 .../src/main/java/org/apache/fory/memory/MemoryBuffer.java   |  6 ++++--
 .../src/main/java25/org/apache/fory/memory/MemoryBuffer.java |  6 ++++--
 .../test/java/org/apache/fory/memory/MemoryBufferTest.java   | 12 ++++++++++++
 .../org/apache/fory/serializer/BufferSerializersTest.java    | 11 +++++++++++
 5 files changed, 33 insertions(+), 4 deletions(-)

diff --git a/java/fory-core/pom.xml b/java/fory-core/pom.xml
index d8a0784a6..735affa28 100644
--- a/java/fory-core/pom.xml
+++ b/java/fory-core/pom.xml
@@ -452,6 +452,8 @@
             <groupId>org.apache.maven.plugins</groupId>
             <artifactId>maven-surefire-plugin</artifactId>
             <configuration>
+              <!-- Tests use the classpath overlay above, so target the 
unnamed-module launch shape. -->
+              <argLine>${argLine} 
--add-opens=java.base/java.lang.invoke=ALL-UNNAMED</argLine>
               <classesDirectory>${fory.jdk25.test.classes}</classesDirectory>
             </configuration>
           </plugin>
diff --git 
a/java/fory-core/src/main/java/org/apache/fory/memory/MemoryBuffer.java 
b/java/fory-core/src/main/java/org/apache/fory/memory/MemoryBuffer.java
index c88cf66e1..94dd96188 100644
--- a/java/fory-core/src/main/java/org/apache/fory/memory/MemoryBuffer.java
+++ b/java/fory-core/src/main/java/org/apache/fory/memory/MemoryBuffer.java
@@ -3020,8 +3020,10 @@ public final class MemoryBuffer {
       return MemoryOps.readAlignedVarUInt32(this);
     }
     int readerIdx = readerIndex;
-    // use subtract to avoid overflow
-    if (readerIdx < size - 10) {
+    // Use subtraction to avoid overflow. The unrolled Unsafe path assumes the
+    // full aligned-varint scratch range is addressable; short buffers must use
+    // readByte() checks.
+    if (readerIdx > size - 10) {
       return slowReadAlignedVarUInt32();
     }
     long pos = address + readerIdx;
diff --git 
a/java/fory-core/src/main/java25/org/apache/fory/memory/MemoryBuffer.java 
b/java/fory-core/src/main/java25/org/apache/fory/memory/MemoryBuffer.java
index 309d9e6e4..7fbf021ff 100644
--- a/java/fory-core/src/main/java25/org/apache/fory/memory/MemoryBuffer.java
+++ b/java/fory-core/src/main/java25/org/apache/fory/memory/MemoryBuffer.java
@@ -2965,8 +2965,10 @@ public final class MemoryBuffer {
   /** Reads the 1-9 byte int part of an aligned varint. */
   public int readAlignedVarUInt32() {
     int readerIdx = readerIndex;
-    // use subtract to avoid overflow
-    if (readerIdx < size - 10) {
+    // Use subtraction to avoid overflow. The unrolled fast path assumes the
+    // full aligned-varint scratch range is inside the logical MemoryBuffer
+    // range; shorter buffers must use readByte() checks.
+    if (readerIdx > size - 10) {
       return slowReadAlignedVarUInt32();
     }
     long pos = address + readerIdx;
diff --git 
a/java/fory-core/src/test/java/org/apache/fory/memory/MemoryBufferTest.java 
b/java/fory-core/src/test/java/org/apache/fory/memory/MemoryBufferTest.java
index 1054c2a01..363955523 100644
--- a/java/fory-core/src/test/java/org/apache/fory/memory/MemoryBufferTest.java
+++ b/java/fory-core/src/test/java/org/apache/fory/memory/MemoryBufferTest.java
@@ -917,6 +917,18 @@ public class MemoryBufferTest {
     assertEquals(buffer.readAlignedVarUInt32(), Integer.MAX_VALUE);
   }
 
+  @Test
+  public void testReadAlignedVarUInt32Bounds() {
+    assertThrows(
+        IndexOutOfBoundsException.class,
+        () -> MemoryBuffer.fromByteArray(new byte[] {(byte) 
0xff}).readAlignedVarUInt32());
+    assertThrows(
+        IndexOutOfBoundsException.class,
+        () ->
+            MemoryBuffer.fromByteArray(new byte[] {(byte) 0xff, 0x40}, 0, 1)
+                .readAlignedVarUInt32());
+  }
+
   @Test
   public void testGetShortB() {
     byte[] data = new byte[4];
diff --git 
a/java/fory-core/src/test/java/org/apache/fory/serializer/BufferSerializersTest.java
 
b/java/fory-core/src/test/java/org/apache/fory/serializer/BufferSerializersTest.java
index 6d44bbf57..c8cccfeed 100644
--- 
a/java/fory-core/src/test/java/org/apache/fory/serializer/BufferSerializersTest.java
+++ 
b/java/fory-core/src/test/java/org/apache/fory/serializer/BufferSerializersTest.java
@@ -74,6 +74,17 @@ public class BufferSerializersTest extends ForyTestBase {
         DeserializationException.class, () -> readSerializer(fory, serializer, 
invalidOrder));
   }
 
+  @Test
+  public void testByteBufferRejectsTruncatedSize() {
+    Fory fory = Fory.builder().withXlang(false).withCompatible(false).build();
+    Serializer<ByteBuffer> serializer =
+        new BufferSerializers.ByteBufferSerializer(fory.getTypeResolver(), 
ByteBuffer.class);
+
+    MemoryBuffer truncatedSize = MemoryBuffer.fromByteArray(new byte[] {1, 
(byte) 0xff});
+    org.testng.Assert.assertThrows(
+        IndexOutOfBoundsException.class, () -> readSerializer(fory, 
serializer, truncatedSize));
+  }
+
   @Test
   public void testBufferObjectRejectsInvalidInBandSizeWithoutBinaryCap() {
     Fory fory = Fory.builder().withXlang(true).withCompatible(false).build();


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

Reply via email to