Skip to content

Commit

Permalink
Avoid integer overflow in computeMapCapacity
Browse files Browse the repository at this point in the history
Updated the StaticUtils.computeMapCapacity method to provide
protection against integer overflow for very large capacity values.
  • Loading branch information
dirmgr committed Oct 19, 2018
1 parent 7b252c0 commit ebbe0b9
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 2 deletions.
26 changes: 25 additions & 1 deletion src/com/unboundid/util/StaticUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -3431,7 +3431,31 @@ public static int computeMapCapacity(final int expectedItemCount)
Validator.ensureTrue((expectedItemCount >= 0),
"StaticUtils.computeMapOrSetCapacity.expectedItemCount must be " +
"greater than or equal to zero.");
return ((expectedItemCount * 4) / 3) + 1;

// NOTE: 536,870,911 is Integer.MAX_VALUE/4. If the value is larger
// than that, then we'll fall back to using floating-point arithmetic
//
if (expectedItemCount > 536_870_911)
{
final int computedCapacity = ((int) (expectedItemCount / 0.75)) + 1;
if (computedCapacity <= expectedItemCount)
{
// This suggests that the expected number of items is so big that
// the computed capacity can't be adequately represented by an
// integer. In that case, we'll just return the expected item
// count and let the map or set get re-hashed/re-balanced if it
// actually gets anywhere near that size.
return expectedItemCount;
}
else
{
return computedCapacity;
}
}
else
{
return ((expectedItemCount * 4) / 3) + 1;
}
}
}

Expand Down
17 changes: 16 additions & 1 deletion tests/unit/src/com/unboundid/util/StaticUtilsTestCase.java
Original file line number Diff line number Diff line change
Expand Up @@ -2705,8 +2705,23 @@ public void testComputeMapCapacity()
for (int i=1; i <= 1000; i++)
{
assertEquals(StaticUtils.computeMapCapacity(i),
(((i * 4 )/ 3) + 1));
(((i * 4 ) / 3) + 1));
}

final int biggestIntegerArithmeticValue = Integer.MAX_VALUE / 4;
assertEquals(StaticUtils.computeMapCapacity(biggestIntegerArithmeticValue),
(((biggestIntegerArithmeticValue * 4) / 3) + 1));

final int smallestFloatingPointArithmeticValue =
biggestIntegerArithmeticValue + 1;
assertEquals(
StaticUtils.computeMapCapacity(smallestFloatingPointArithmeticValue),
(((int) (smallestFloatingPointArithmeticValue / 0.75)) + 1));

final int tooBigForAllPracticalPurposesValue = Integer.MAX_VALUE;
assertEquals(
StaticUtils.computeMapCapacity(tooBigForAllPracticalPurposesValue),
tooBigForAllPracticalPurposesValue);
}


Expand Down

0 comments on commit ebbe0b9

Please sign in to comment.