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>