JDK-8305734 : BitSet.get(int, int) always returns the empty BitSet when the Integer.MAX VALUE is set
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.util
  • Affected Version: 8,11,17,19,20,21
  • Priority: P4
  • Status: New
  • Resolution: Unresolved
  • OS: generic
  • CPU: generic
  • Submitted: 2023-04-06
  • Updated: 2023-04-07
Description
A DESCRIPTION OF THE PROBLEM :
When the Integer.MAX VALUE bit is set, the get(int, int) function always returns a BitSet of size 0.
This is because length() overflows when Integer.MAX VALUE is set and so returns Integer.MIN VALUE.

public BitSet get(int fromIndex, int toIndex) {
    checkRange(fromIndex, toIndex);

    checkInvariants();

    int len = length(); // (*)

    // If no set bits in range return empty bitset
    if (len <= fromIndex || fromIndex == toIndex)
        return new BitSet(0);
    ...

When the comparison len <= fromIndex is done, this always evaluates to true regardless of the value of fromIndex, and as such the function returns BitSet(0).

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Create a BitSet with the default constructor, and set the Integer.MAX VALUE bit. Next, set bit 999.
Then do BitSet.get(0, 1000).

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
A BitSet is returned with length = 1000 and size = 1024. In the resulting BitSet, the bit with index 999 is set.
ACTUAL -
A BitSet is returned with length and size = 0. The bit with index 999 is not set.

---------- BEGIN SOURCE ----------
public class BitSetGet {
    public static void main(String[] args) {
        BitSet bitSet = new BitSet(); 
        bitSet.set(Integer.MAX_VALUE);
        bitSet.set(999);  
        BitSet result = bitSet.get(0,1000);
        System.out.println(result.length());
        System.out.println(result.size());
        System.out.println(result.get(999));
    }
}
---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
Clients can manually obtain the value of the bits using the get(int) method repeatedly.

Suggested fix: After assigning the output of length() to len, check if len < 0. If so, set len to Integer.MAX VALUE.

int len = length(); // (*)
if ( len < 0 ) len = Integer.MAX_VALUE;

This prevents the len <= fromIndex check being an issue. 
Lowering the length also does not affect the bits that can be accessed by this function. toIndex already cannot be higher than Integer.MAX VALUE, so the Integer.MAX VALUE bit was already inaccessible in this get() function.

FREQUENCY : always



Comments
The observations on Windows 10: JDK 8: Failed, BitSet.get returned false. JDK 11: Failed. JDK 17: Failed. JDK 19: Failed. JDK 20: Failed. JDK 21ea+5: Failed.
07-04-2023