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

tv pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-jcs.git


The following commit(s) were added to refs/heads/master by this push:
     new 96db75a0 JCS-244: Replace IElementSerializer asserts with IOExceptions
     new f700254d Merge branch 'master' of 
https://gitbox.apache.org/repos/asf/commons-jcs.git
96db75a0 is described below

commit 96db75a0dda6cf52f8836f935c701adb1c3f0e66
Author: Thomas Vandahl <[email protected]>
AuthorDate: Mon Mar 9 12:51:44 2026 +0100

    JCS-244: Replace IElementSerializer asserts with IOExceptions
---
 .../jcs4/engine/behavior/IElementSerializer.java   | 41 ++++++++++++----------
 .../serialization/StandardSerializerUnitTest.java  | 27 ++++++++++++++
 src/changes/changes.xml                            |  3 ++
 3 files changed, 53 insertions(+), 18 deletions(-)

diff --git 
a/commons-jcs4-core/src/main/java/org/apache/commons/jcs4/engine/behavior/IElementSerializer.java
 
b/commons-jcs4-core/src/main/java/org/apache/commons/jcs4/engine/behavior/IElementSerializer.java
index 20e89060..ded48dd3 100644
--- 
a/commons-jcs4-core/src/main/java/org/apache/commons/jcs4/engine/behavior/IElementSerializer.java
+++ 
b/commons-jcs4-core/src/main/java/org/apache/commons/jcs4/engine/behavior/IElementSerializer.java
@@ -25,6 +25,7 @@ import java.io.InputStream;
 import java.io.OutputStream;
 import java.nio.ByteBuffer;
 import java.nio.channels.AsynchronousByteChannel;
+import java.nio.channels.Channels;
 import java.nio.channels.ReadableByteChannel;
 import java.nio.channels.WritableByteChannel;
 import java.util.concurrent.ExecutionException;
@@ -77,16 +78,20 @@ public interface IElementSerializer
             {
                 throw new EOFException("End of stream reached (length)");
             }
-            assert read == bufferSize.capacity();
+            if (read != bufferSize.capacity())
+            {
+                throw new IOException("Unexpected data size (length) " + read);
+            }
         }
         catch (InterruptedException | ExecutionException | TimeoutException e)
         {
-            throw new IOException("Read timeout exceeded (length)" + 
readTimeoutMs, e);
+            throw new IOException("Read timeout exceeded (length) " + 
readTimeoutMs, e);
         }
 
         bufferSize.flip();
 
         final ByteBuffer serialized = ByteBuffer.allocate(bufferSize.getInt());
+        int totalRead = 0;
         while (serialized.remaining() > 0)
         {
             readFuture = ic.read(serialized);
@@ -97,13 +102,19 @@ public interface IElementSerializer
                 {
                     throw new EOFException("End of stream reached (object)");
                 }
+                totalRead += read;
             }
             catch (InterruptedException | ExecutionException | 
TimeoutException e)
             {
-                throw new IOException("Read timeout exceeded (object)" + 
readTimeoutMs, e);
+                throw new IOException("Read timeout exceeded (object) " + 
readTimeoutMs, e);
             }
         }
 
+        if (totalRead != serialized.capacity())
+        {
+            throw new IOException("Unexpected data size (object) " + 
totalRead);
+        }
+
         serialized.flip();
 
         return deSerialize(serialized.array(), loader);
@@ -124,20 +135,7 @@ public interface IElementSerializer
     default <T> T deSerializeFrom(final InputStream is, final ClassLoader 
loader)
         throws IOException, ClassNotFoundException
     {
-        final byte[] bufferSize = new byte[4];
-        int read = is.read(bufferSize);
-        if (read < 0)
-        {
-            throw new EOFException("End of stream reached");
-        }
-        assert read == bufferSize.length;
-        final ByteBuffer size = ByteBuffer.wrap(bufferSize);
-
-        final byte[] serialized = new byte[size.getInt()];
-        read = is.read(serialized);
-        assert read == serialized.length;
-
-        return deSerialize(serialized, loader);
+        return deSerializeFrom(Channels.newChannel(is), loader);
     }
 
     /**
@@ -161,7 +159,10 @@ public interface IElementSerializer
         {
             throw new EOFException("End of stream reached (length)");
         }
-        assert read == bufferSize.capacity();
+        if (read != bufferSize.capacity())
+        {
+            throw new IOException("Unexpected data size (length) " + read);
+        }
         bufferSize.flip();
 
         final ByteBuffer serialized = ByteBuffer.allocate(bufferSize.getInt());
@@ -172,6 +173,10 @@ public interface IElementSerializer
             {
                 throw new EOFException("End of stream reached (object)");
             }
+            if (read != serialized.capacity())
+            {
+                throw new IOException("Unexpected data size (object) " + read);
+            }
         }
         serialized.flip();
 
diff --git 
a/commons-jcs4-core/src/test/java/org/apache/commons/jcs4/utils/serialization/StandardSerializerUnitTest.java
 
b/commons-jcs4-core/src/test/java/org/apache/commons/jcs4/utils/serialization/StandardSerializerUnitTest.java
index 6350e86f..8b5aa00f 100644
--- 
a/commons-jcs4-core/src/test/java/org/apache/commons/jcs4/utils/serialization/StandardSerializerUnitTest.java
+++ 
b/commons-jcs4-core/src/test/java/org/apache/commons/jcs4/utils/serialization/StandardSerializerUnitTest.java
@@ -23,8 +23,11 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertNull;
 import static org.junit.jupiter.api.Assertions.assertThrows;
 
+import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.io.InvalidClassException;
+import java.io.StreamCorruptedException;
+import java.nio.ByteBuffer;
 
 import org.apache.commons.collections4.bag.HashBag;
 import org.apache.commons.jcs4.io.ObjectInputStreamClassLoaderAware;
@@ -132,4 +135,28 @@ class StandardSerializerUnitTest
 
         assertThrows(InvalidClassException.class, () -> 
serializer.deSerialize( serialized, null ));
     }
+
+    /**
+     * Test resilience of deserialization against data integrity errors 
(JCS-244)
+     */
+    @Test
+    void testDeserializationResilience()
+    {
+        byte[] inputArray1 = { 42 };
+        ByteArrayInputStream input1 = new ByteArrayInputStream(inputArray1);
+
+        assertThrows(IOException.class, () -> serializer.deSerializeFrom( 
input1, null ));
+
+        byte[] data2 = { 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78 };
+        byte[] inputArray2 = 
ByteBuffer.allocate(12).putInt(10).put(data2).array();
+        ByteArrayInputStream input2 = new ByteArrayInputStream(inputArray2);
+
+        assertThrows(IOException.class, () -> serializer.deSerializeFrom( 
input2, null ));
+
+        byte[] data3 = { 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78 };
+        byte[] inputArray3 = 
ByteBuffer.allocate(12).putInt(8).put(data3).array();
+        ByteArrayInputStream input3 = new ByteArrayInputStream(inputArray3);
+
+        assertThrows(StreamCorruptedException.class, () -> 
serializer.deSerializeFrom( input3, null ));
+    }
 }
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index abcc84e9..261c90ba 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -40,6 +40,9 @@
             <action dev="tv" type="fix" issue="JCS-243" due-to="Henrik 
Hiltunen">
                fix ICacheServiceAdmin not extending Remote
             </action>
+            <action dev="tv" type="fix" issue="JCS-244" due-to="Florin Pop">
+               replace IElementSerializer asserts with explicit IOExceptions. 
Add test.
+            </action>
             <action dev="tv" type="fix" issue="JCS-222" due-to="Arturo Bernal">
                fix typo "waterfal" method
             </action>

Reply via email to