This is an automated email from the ASF dual-hosted git repository.
garydgregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-collections.git
The following commit(s) were added to refs/heads/master by this push:
new 9258f65e9 Reject non-positive entry count in bag/multiset doReadObject
(#679)
9258f65e9 is described below
commit 9258f65e9e2d41cfbbc2b08dba4c42060f26b308
Author: Dexter.k <[email protected]>
AuthorDate: Sun Jun 14 12:15:53 2026 +0000
Reject non-positive entry count in bag/multiset doReadObject (#679)
* reject non-positive entry count in bag/multiset doReadObject
* Potential fix for pull request finding
Co-authored-by: Copilot Autofix powered by AI
<[email protected]>
---------
Co-authored-by: Gary Gregory <[email protected]>
Co-authored-by: Copilot Autofix powered by AI
<[email protected]>
---
.../commons/collections4/bag/AbstractMapBag.java | 4 ++
.../collections4/multiset/AbstractMapMultiSet.java | 4 ++
.../commons/collections4/bag/HashBagTest.java | 43 ++++++++++++++++++++++
.../collections4/multiset/HashMultiSetTest.java | 43 ++++++++++++++++++++++
4 files changed, 94 insertions(+)
diff --git
a/src/main/java/org/apache/commons/collections4/bag/AbstractMapBag.java
b/src/main/java/org/apache/commons/collections4/bag/AbstractMapBag.java
index f64d19c93..bafd162e3 100644
--- a/src/main/java/org/apache/commons/collections4/bag/AbstractMapBag.java
+++ b/src/main/java/org/apache/commons/collections4/bag/AbstractMapBag.java
@@ -17,6 +17,7 @@
package org.apache.commons.collections4.bag;
import java.io.IOException;
+import java.io.InvalidObjectException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Array;
@@ -300,6 +301,9 @@ public abstract class AbstractMapBag<E> implements Bag<E> {
@SuppressWarnings("unchecked") // This will fail at runtime if the
stream is incorrect
final E obj = (E) in.readObject();
final int count = in.readInt();
+ if (count < 1) {
+ throw new InvalidObjectException("Invalid count for entry
(must be >= 1): " + count);
+ }
map.put(obj, new MutableInteger(count));
size += count;
}
diff --git
a/src/main/java/org/apache/commons/collections4/multiset/AbstractMapMultiSet.java
b/src/main/java/org/apache/commons/collections4/multiset/AbstractMapMultiSet.java
index 0e24a6e16..6dfedc7ee 100644
---
a/src/main/java/org/apache/commons/collections4/multiset/AbstractMapMultiSet.java
+++
b/src/main/java/org/apache/commons/collections4/multiset/AbstractMapMultiSet.java
@@ -17,6 +17,7 @@
package org.apache.commons.collections4.multiset;
import java.io.IOException;
+import java.io.InvalidObjectException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Array;
@@ -366,6 +367,9 @@ public abstract class AbstractMapMultiSet<E> extends
AbstractMultiSet<E> {
@SuppressWarnings("unchecked") // This will fail at runtime if the
stream is incorrect
final E obj = (E) in.readObject();
final int count = in.readInt();
+ if (count < 1) {
+ throw new InvalidObjectException("Invalid count for entry: " +
count);
+ }
map.put(obj, new MutableInteger(count));
size += count;
}
diff --git a/src/test/java/org/apache/commons/collections4/bag/HashBagTest.java
b/src/test/java/org/apache/commons/collections4/bag/HashBagTest.java
index e599fe83e..9b505ca5b 100644
--- a/src/test/java/org/apache/commons/collections4/bag/HashBagTest.java
+++ b/src/test/java/org/apache/commons/collections4/bag/HashBagTest.java
@@ -16,7 +16,16 @@
*/
package org.apache.commons.collections4.bag;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InvalidObjectException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
import org.apache.commons.collections4.Bag;
+import org.junit.jupiter.api.Test;
/**
* Extension of {@link AbstractBagTest} for exercising the {@link HashBag}
@@ -24,6 +33,20 @@ import org.apache.commons.collections4.Bag;
*/
public class HashBagTest<T> extends AbstractBagTest<T> {
+ private static void replaceInt(final byte[] bytes, final int from, final
int to) {
+ for (int i = 0; i + 4 <= bytes.length; i++) {
+ if (((bytes[i] & 0xFF) << 24 | (bytes[i + 1] & 0xFF) << 16
+ | (bytes[i + 2] & 0xFF) << 8 | bytes[i + 3] & 0xFF) ==
from) {
+ bytes[i] = (byte) (to >>> 24);
+ bytes[i + 1] = (byte) (to >>> 16);
+ bytes[i + 2] = (byte) (to >>> 8);
+ bytes[i + 3] = (byte) to;
+ return;
+ }
+ }
+ throw new IllegalStateException("marker not found in stream");
+ }
+
@Override
public String getCompatibilityVersion() {
return "4";
@@ -39,6 +62,26 @@ public class HashBagTest<T> extends AbstractBagTest<T> {
return new HashBag<>();
}
+ @Test
+ void testDeserializeRejectsNonPositiveCount() throws Exception {
+ final int marker = 0x11223344;
+ final HashBag<String> bag = new HashBag<>();
+ bag.add("X", marker);
+ final ByteArrayOutputStream out = new ByteArrayOutputStream();
+ try (ObjectOutputStream oos = new ObjectOutputStream(out)) {
+ oos.writeObject(bag);
+ }
+ for (final int count : new int[] {0, -7}) {
+ final byte[] bytes = out.toByteArray();
+ replaceInt(bytes, marker, count);
+ assertThrows(InvalidObjectException.class, () -> {
+ try (ObjectInputStream ois = new ObjectInputStream(new
ByteArrayInputStream(bytes))) {
+ ois.readObject();
+ }
+ });
+ }
+ }
+
// void testCreate() throws Exception {
// Bag<T> bag = makeObject();
// writeExternalFormToDisk((java.io.Serializable) bag,
"src/test/resources/data/test/HashBag.emptyCollection.version4.obj");
diff --git
a/src/test/java/org/apache/commons/collections4/multiset/HashMultiSetTest.java
b/src/test/java/org/apache/commons/collections4/multiset/HashMultiSetTest.java
index 6c28ac742..48dad2cd5 100644
---
a/src/test/java/org/apache/commons/collections4/multiset/HashMultiSetTest.java
+++
b/src/test/java/org/apache/commons/collections4/multiset/HashMultiSetTest.java
@@ -16,7 +16,16 @@
*/
package org.apache.commons.collections4.multiset;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InvalidObjectException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
import org.apache.commons.collections4.MultiSet;
+import org.junit.jupiter.api.Test;
/**
* Extension of {@link AbstractMultiSetTest} for exercising the
@@ -24,6 +33,20 @@ import org.apache.commons.collections4.MultiSet;
*/
public class HashMultiSetTest<T> extends AbstractMultiSetTest<T> {
+ private static void replaceInt(final byte[] bytes, final int from, final
int to) {
+ for (int i = 0; i + 4 <= bytes.length; i++) {
+ if (((bytes[i] & 0xFF) << 24 | (bytes[i + 1] & 0xFF) << 16
+ | (bytes[i + 2] & 0xFF) << 8 | bytes[i + 3] & 0xFF) ==
from) {
+ bytes[i] = (byte) (to >>> 24);
+ bytes[i + 1] = (byte) (to >>> 16);
+ bytes[i + 2] = (byte) (to >>> 8);
+ bytes[i + 3] = (byte) to;
+ return;
+ }
+ }
+ throw new IllegalStateException("marker not found in stream");
+ }
+
@Override
public String getCompatibilityVersion() {
return "4.1";
@@ -39,6 +62,26 @@ public class HashMultiSetTest<T> extends
AbstractMultiSetTest<T> {
return new HashMultiSet<>();
}
+ @Test
+ void testDeserializeRejectsNonPositiveCount() throws Exception {
+ final int marker = 0x11223344;
+ final HashMultiSet<String> set = new HashMultiSet<>();
+ set.add("Y", marker);
+ final ByteArrayOutputStream out = new ByteArrayOutputStream();
+ try (ObjectOutputStream oos = new ObjectOutputStream(out)) {
+ oos.writeObject(set);
+ }
+ for (final int count : new int[] {0, -7}) {
+ final byte[] bytes = out.toByteArray();
+ replaceInt(bytes, marker, count);
+ assertThrows(InvalidObjectException.class, () -> {
+ try (ObjectInputStream ois = new ObjectInputStream(new
ByteArrayInputStream(bytes))) {
+ ois.readObject();
+ }
+ });
+ }
+ }
+
// void testCreate() throws Exception {
// MultiSet<T> multiset = makeObject();
// writeExternalFormToDisk((java.io.Serializable) multiset,
"src/test/resources/data/test/HashMultiSet.emptyCollection.version4.1.obj");