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");

Reply via email to