Skip to content

Commit

Permalink
Fix bug with overflow checking in Combinations
Browse files Browse the repository at this point in the history
  • Loading branch information
Markoutte committed Jul 28, 2022
1 parent d21426f commit 3351aaa
Show file tree
Hide file tree
Showing 3 changed files with 20 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,10 @@ class Combinations(vararg elementNumbers: Int): Iterable<IntArray> {
}
count = LongArray(elementNumbers.size) { elementNumbers[it].toLong() }
for (i in count.size - 2 downTo 0) {
count[i] = count[i] * count[i + 1]
if(count[i] < count[i + 1]) {
throw TooManyCombinationsException("Long overflow or bad sequence: ${count[i]} < ${count[i + 1]}")
try {
count[i] = StrictMath.multiplyExact(count[i], count[i + 1])
} catch (e: ArithmeticException) {
throw TooManyCombinationsException("Long overflow: ${count[i]} * ${count[i + 1]}")
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -228,12 +228,24 @@ class CombinationsTest {
assertTrue(expected.isEmpty())
}

@Test
fun testCartesianProductDoesNotThrowsExceptionBeforeOverflow() {
// We assume that a standard method has no more than 7 parameters.
// In this case every parameter can accept up to 511 values without Long overflow.
// CartesianProduct throws exception
val values = Array(511) { it }.toList()
val parameters = Array(7) { values }.toList()
assertDoesNotThrow {
CartesianProduct(parameters, Random(0)).asSequence()
}
}

@Test
fun testCartesianProductThrowsExceptionOnOverflow() {
// We assume that a standard method has no more than 7 parameters.
// In this case every parameter can accept up to 1700 values without Long overflow.
// In this case every parameter can accept up to 511 values without Long overflow.
// CartesianProduct throws exception
val values = Array(1701) { it }.toList()
val values = Array(512) { it }.toList()
val parameters = Array(7) { values }.toList()
assertThrows(TooManyCombinationsException::class.java) {
CartesianProduct(parameters, Random(0)).asSequence()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,12 +115,12 @@ class FuzzerTest {
), fuzz.map { arguments -> arguments.map { fuzzedValue -> fuzzedValue.model } }.toSet())
}

// Because of Long limitation fuzzer can process no more than 1700 values for method with 7 parameters
// Because of Long limitation fuzzer can process no more than 511 values for method with 7 parameters
@Test
@Timeout(1, unit = TimeUnit.SECONDS)
fun `the worst case works well`() {
assertDoesNotThrow {
val values = (0 until 1700).map { UtPrimitiveModel(it).fuzzed() }.asSequence()
val values = (0 until 511).map { UtPrimitiveModel(it).fuzzed() }.asSequence()
val provider = ModelProvider { descr ->
(0 until descr.parameters.size).asSequence()
.flatMap { index -> values.map { FuzzedParameter(index, it) } }
Expand Down

0 comments on commit 3351aaa

Please sign in to comment.