Make sure index and count do not overflow for long sequences

Throw an exception immediately before an overflow becomes observable.
Place check to prevent negative index from indexOf, indexOfFirst.
Do not insert overflow checks for arrays, lists, maps and char sequences.

#KT-16097
This commit is contained in:
Ilya Gorbunov
2018-08-09 23:31:31 +03:00
parent c44f62a3d4
commit 357c5be4fb
16 changed files with 252 additions and 58 deletions
@@ -9701,7 +9701,7 @@ public inline fun CharArray.count(): Int {
*/
public inline fun <T> Array<out T>.count(predicate: (T) -> Boolean): Int {
var count = 0
for (element in this) if (predicate(element)) count++
for (element in this) if (predicate(element)) ++count
return count
}
@@ -9710,7 +9710,7 @@ public inline fun <T> Array<out T>.count(predicate: (T) -> Boolean): Int {
*/
public inline fun ByteArray.count(predicate: (Byte) -> Boolean): Int {
var count = 0
for (element in this) if (predicate(element)) count++
for (element in this) if (predicate(element)) ++count
return count
}
@@ -9719,7 +9719,7 @@ public inline fun ByteArray.count(predicate: (Byte) -> Boolean): Int {
*/
public inline fun ShortArray.count(predicate: (Short) -> Boolean): Int {
var count = 0
for (element in this) if (predicate(element)) count++
for (element in this) if (predicate(element)) ++count
return count
}
@@ -9728,7 +9728,7 @@ public inline fun ShortArray.count(predicate: (Short) -> Boolean): Int {
*/
public inline fun IntArray.count(predicate: (Int) -> Boolean): Int {
var count = 0
for (element in this) if (predicate(element)) count++
for (element in this) if (predicate(element)) ++count
return count
}
@@ -9737,7 +9737,7 @@ public inline fun IntArray.count(predicate: (Int) -> Boolean): Int {
*/
public inline fun LongArray.count(predicate: (Long) -> Boolean): Int {
var count = 0
for (element in this) if (predicate(element)) count++
for (element in this) if (predicate(element)) ++count
return count
}
@@ -9746,7 +9746,7 @@ public inline fun LongArray.count(predicate: (Long) -> Boolean): Int {
*/
public inline fun FloatArray.count(predicate: (Float) -> Boolean): Int {
var count = 0
for (element in this) if (predicate(element)) count++
for (element in this) if (predicate(element)) ++count
return count
}
@@ -9755,7 +9755,7 @@ public inline fun FloatArray.count(predicate: (Float) -> Boolean): Int {
*/
public inline fun DoubleArray.count(predicate: (Double) -> Boolean): Int {
var count = 0
for (element in this) if (predicate(element)) count++
for (element in this) if (predicate(element)) ++count
return count
}
@@ -9764,7 +9764,7 @@ public inline fun DoubleArray.count(predicate: (Double) -> Boolean): Int {
*/
public inline fun BooleanArray.count(predicate: (Boolean) -> Boolean): Int {
var count = 0
for (element in this) if (predicate(element)) count++
for (element in this) if (predicate(element)) ++count
return count
}
@@ -9773,7 +9773,7 @@ public inline fun BooleanArray.count(predicate: (Boolean) -> Boolean): Int {
*/
public inline fun CharArray.count(predicate: (Char) -> Boolean): Int {
var count = 0
for (element in this) if (predicate(element)) count++
for (element in this) if (predicate(element)) ++count
return count
}
@@ -13504,7 +13504,7 @@ public fun Array<out Byte>.average(): Double {
var count: Int = 0
for (element in this) {
sum += element
count += 1
++count
}
return if (count == 0) Double.NaN else sum / count
}
@@ -13518,7 +13518,7 @@ public fun Array<out Short>.average(): Double {
var count: Int = 0
for (element in this) {
sum += element
count += 1
++count
}
return if (count == 0) Double.NaN else sum / count
}
@@ -13532,7 +13532,7 @@ public fun Array<out Int>.average(): Double {
var count: Int = 0
for (element in this) {
sum += element
count += 1
++count
}
return if (count == 0) Double.NaN else sum / count
}
@@ -13546,7 +13546,7 @@ public fun Array<out Long>.average(): Double {
var count: Int = 0
for (element in this) {
sum += element
count += 1
++count
}
return if (count == 0) Double.NaN else sum / count
}
@@ -13560,7 +13560,7 @@ public fun Array<out Float>.average(): Double {
var count: Int = 0
for (element in this) {
sum += element
count += 1
++count
}
return if (count == 0) Double.NaN else sum / count
}
@@ -13574,7 +13574,7 @@ public fun Array<out Double>.average(): Double {
var count: Int = 0
for (element in this) {
sum += element
count += 1
++count
}
return if (count == 0) Double.NaN else sum / count
}
@@ -13587,7 +13587,7 @@ public fun ByteArray.average(): Double {
var count: Int = 0
for (element in this) {
sum += element
count += 1
++count
}
return if (count == 0) Double.NaN else sum / count
}
@@ -13600,7 +13600,7 @@ public fun ShortArray.average(): Double {
var count: Int = 0
for (element in this) {
sum += element
count += 1
++count
}
return if (count == 0) Double.NaN else sum / count
}
@@ -13613,7 +13613,7 @@ public fun IntArray.average(): Double {
var count: Int = 0
for (element in this) {
sum += element
count += 1
++count
}
return if (count == 0) Double.NaN else sum / count
}
@@ -13626,7 +13626,7 @@ public fun LongArray.average(): Double {
var count: Int = 0
for (element in this) {
sum += element
count += 1
++count
}
return if (count == 0) Double.NaN else sum / count
}
@@ -13639,7 +13639,7 @@ public fun FloatArray.average(): Double {
var count: Int = 0
for (element in this) {
sum += element
count += 1
++count
}
return if (count == 0) Double.NaN else sum / count
}
@@ -13652,7 +13652,7 @@ public fun DoubleArray.average(): Double {
var count: Int = 0
for (element in this) {
sum += element
count += 1
++count
}
return if (count == 0) Double.NaN else sum / count
}
@@ -251,6 +251,7 @@ public fun <@kotlin.internal.OnlyInputTypes T> Iterable<T>.indexOf(element: T):
if (this is List) return this.indexOf(element)
var index = 0
for (item in this) {
checkIndexOverflow(index)
if (element == item)
return index
index++
@@ -272,6 +273,7 @@ public fun <@kotlin.internal.OnlyInputTypes T> List<T>.indexOf(element: T): Int
public inline fun <T> Iterable<T>.indexOfFirst(predicate: (T) -> Boolean): Int {
var index = 0
for (item in this) {
checkIndexOverflow(index)
if (predicate(item))
return index
index++
@@ -299,6 +301,7 @@ public inline fun <T> Iterable<T>.indexOfLast(predicate: (T) -> Boolean): Int {
var lastIndex = -1
var index = 0
for (item in this) {
checkIndexOverflow(index)
if (predicate(item))
lastIndex = index
index++
@@ -387,6 +390,7 @@ public fun <@kotlin.internal.OnlyInputTypes T> Iterable<T>.lastIndexOf(element:
var lastIndex = -1
var index = 0
for (item in this) {
checkIndexOverflow(index)
if (element == item)
lastIndex = index
index++
@@ -1258,7 +1262,7 @@ public inline fun <T, R : Any, C : MutableCollection<in R>> Iterable<T>.mapIndex
public inline fun <T, R, C : MutableCollection<in R>> Iterable<T>.mapIndexedTo(destination: C, transform: (index: Int, T) -> R): C {
var index = 0
for (item in this)
destination.add(transform(index++, item))
destination.add(transform(checkIndexOverflow(index++), item))
return destination
}
@@ -1407,7 +1411,7 @@ public inline fun <T> Iterable<T>.any(predicate: (T) -> Boolean): Boolean {
public fun <T> Iterable<T>.count(): Int {
if (this is Collection) return size
var count = 0
for (element in this) count++
for (element in this) checkCountOverflow(++count)
return count
}
@@ -1425,7 +1429,7 @@ public inline fun <T> Collection<T>.count(): Int {
public inline fun <T> Iterable<T>.count(predicate: (T) -> Boolean): Int {
if (this is Collection && isEmpty()) return 0
var count = 0
for (element in this) if (predicate(element)) count++
for (element in this) if (predicate(element)) checkCountOverflow(++count)
return count
}
@@ -1447,7 +1451,7 @@ public inline fun <T, R> Iterable<T>.fold(initial: R, operation: (acc: R, T) ->
public inline fun <T, R> Iterable<T>.foldIndexed(initial: R, operation: (index: Int, acc: R, T) -> R): R {
var index = 0
var accumulator = initial
for (element in this) accumulator = operation(index++, accumulator, element)
for (element in this) accumulator = operation(checkIndexOverflow(index++), accumulator, element)
return accumulator
}
@@ -1498,7 +1502,7 @@ public inline fun <T> Iterable<T>.forEach(action: (T) -> Unit): Unit {
*/
public inline fun <T> Iterable<T>.forEachIndexed(action: (index: Int, T) -> Unit): Unit {
var index = 0
for (item in this) action(index++, item)
for (item in this) action(checkIndexOverflow(index++), item)
}
/**
@@ -1725,7 +1729,7 @@ public inline fun <S, T : S> Iterable<T>.reduceIndexed(operation: (index: Int, a
var index = 1
var accumulator: S = iterator.next()
while (iterator.hasNext()) {
accumulator = operation(index++, accumulator, iterator.next())
accumulator = operation(checkIndexOverflow(index++), accumulator, iterator.next())
}
return accumulator
}
@@ -2238,7 +2242,7 @@ public fun Iterable<Byte>.average(): Double {
var count: Int = 0
for (element in this) {
sum += element
count += 1
checkCountOverflow(++count)
}
return if (count == 0) Double.NaN else sum / count
}
@@ -2252,7 +2256,7 @@ public fun Iterable<Short>.average(): Double {
var count: Int = 0
for (element in this) {
sum += element
count += 1
checkCountOverflow(++count)
}
return if (count == 0) Double.NaN else sum / count
}
@@ -2266,7 +2270,7 @@ public fun Iterable<Int>.average(): Double {
var count: Int = 0
for (element in this) {
sum += element
count += 1
checkCountOverflow(++count)
}
return if (count == 0) Double.NaN else sum / count
}
@@ -2280,7 +2284,7 @@ public fun Iterable<Long>.average(): Double {
var count: Int = 0
for (element in this) {
sum += element
count += 1
checkCountOverflow(++count)
}
return if (count == 0) Double.NaN else sum / count
}
@@ -2294,7 +2298,7 @@ public fun Iterable<Float>.average(): Double {
var count: Int = 0
for (element in this) {
sum += element
count += 1
checkCountOverflow(++count)
}
return if (count == 0) Double.NaN else sum / count
}
@@ -2308,7 +2312,7 @@ public fun Iterable<Double>.average(): Double {
var count: Int = 0
for (element in this) {
sum += element
count += 1
checkCountOverflow(++count)
}
return if (count == 0) Double.NaN else sum / count
}
@@ -135,7 +135,7 @@ public inline fun <K, V> Map<out K, V>.count(): Int {
public inline fun <K, V> Map<out K, V>.count(predicate: (Map.Entry<K, V>) -> Boolean): Int {
if (isEmpty()) return 0
var count = 0
for (element in this) if (predicate(element)) count++
for (element in this) if (predicate(element)) ++count
return count
}
@@ -146,6 +146,7 @@ public inline fun <T> Sequence<T>.firstOrNull(predicate: (T) -> Boolean): T? {
public fun <@kotlin.internal.OnlyInputTypes T> Sequence<T>.indexOf(element: T): Int {
var index = 0
for (item in this) {
checkIndexOverflow(index)
if (element == item)
return index
index++
@@ -161,6 +162,7 @@ public fun <@kotlin.internal.OnlyInputTypes T> Sequence<T>.indexOf(element: T):
public inline fun <T> Sequence<T>.indexOfFirst(predicate: (T) -> Boolean): Int {
var index = 0
for (item in this) {
checkIndexOverflow(index)
if (predicate(item))
return index
index++
@@ -177,6 +179,7 @@ public inline fun <T> Sequence<T>.indexOfLast(predicate: (T) -> Boolean): Int {
var lastIndex = -1
var index = 0
for (item in this) {
checkIndexOverflow(index)
if (predicate(item))
lastIndex = index
index++
@@ -229,6 +232,7 @@ public fun <@kotlin.internal.OnlyInputTypes T> Sequence<T>.lastIndexOf(element:
var lastIndex = -1
var index = 0
for (item in this) {
checkIndexOverflow(index)
if (element == item)
lastIndex = index
index++
@@ -852,7 +856,7 @@ public inline fun <T, R : Any, C : MutableCollection<in R>> Sequence<T>.mapIndex
public inline fun <T, R, C : MutableCollection<in R>> Sequence<T>.mapIndexedTo(destination: C, transform: (index: Int, T) -> R): C {
var index = 0
for (item in this)
destination.add(transform(index++, item))
destination.add(transform(checkIndexOverflow(index++), item))
return destination
}
@@ -976,7 +980,7 @@ public inline fun <T> Sequence<T>.any(predicate: (T) -> Boolean): Boolean {
*/
public fun <T> Sequence<T>.count(): Int {
var count = 0
for (element in this) count++
for (element in this) checkCountOverflow(++count)
return count
}
@@ -987,7 +991,7 @@ public fun <T> Sequence<T>.count(): Int {
*/
public inline fun <T> Sequence<T>.count(predicate: (T) -> Boolean): Int {
var count = 0
for (element in this) if (predicate(element)) count++
for (element in this) if (predicate(element)) checkCountOverflow(++count)
return count
}
@@ -1013,7 +1017,7 @@ public inline fun <T, R> Sequence<T>.fold(initial: R, operation: (acc: R, T) ->
public inline fun <T, R> Sequence<T>.foldIndexed(initial: R, operation: (index: Int, acc: R, T) -> R): R {
var index = 0
var accumulator = initial
for (element in this) accumulator = operation(index++, accumulator, element)
for (element in this) accumulator = operation(checkIndexOverflow(index++), accumulator, element)
return accumulator
}
@@ -1035,7 +1039,7 @@ public inline fun <T> Sequence<T>.forEach(action: (T) -> Unit): Unit {
*/
public inline fun <T> Sequence<T>.forEachIndexed(action: (index: Int, T) -> Unit): Unit {
var index = 0
for (item in this) action(index++, item)
for (item in this) action(checkIndexOverflow(index++), item)
}
/**
@@ -1293,7 +1297,7 @@ public inline fun <S, T : S> Sequence<T>.reduceIndexed(operation: (index: Int, a
var index = 1
var accumulator: S = iterator.next()
while (iterator.hasNext()) {
accumulator = operation(index++, accumulator, iterator.next())
accumulator = operation(checkIndexOverflow(index++), accumulator, iterator.next())
}
return accumulator
}
@@ -1696,7 +1700,7 @@ public fun Sequence<Byte>.average(): Double {
var count: Int = 0
for (element in this) {
sum += element
count += 1
checkCountOverflow(++count)
}
return if (count == 0) Double.NaN else sum / count
}
@@ -1712,7 +1716,7 @@ public fun Sequence<Short>.average(): Double {
var count: Int = 0
for (element in this) {
sum += element
count += 1
checkCountOverflow(++count)
}
return if (count == 0) Double.NaN else sum / count
}
@@ -1728,7 +1732,7 @@ public fun Sequence<Int>.average(): Double {
var count: Int = 0
for (element in this) {
sum += element
count += 1
checkCountOverflow(++count)
}
return if (count == 0) Double.NaN else sum / count
}
@@ -1744,7 +1748,7 @@ public fun Sequence<Long>.average(): Double {
var count: Int = 0
for (element in this) {
sum += element
count += 1
checkCountOverflow(++count)
}
return if (count == 0) Double.NaN else sum / count
}
@@ -1760,7 +1764,7 @@ public fun Sequence<Float>.average(): Double {
var count: Int = 0
for (element in this) {
sum += element
count += 1
checkCountOverflow(++count)
}
return if (count == 0) Double.NaN else sum / count
}
@@ -1776,7 +1780,7 @@ public fun Sequence<Double>.average(): Double {
var count: Int = 0
for (element in this) {
sum += element
count += 1
checkCountOverflow(++count)
}
return if (count == 0) Double.NaN else sum / count
}
@@ -883,7 +883,7 @@ public inline fun CharSequence.count(): Int {
*/
public inline fun CharSequence.count(predicate: (Char) -> Boolean): Int {
var count = 0
for (element in this) if (predicate(element)) count++
for (element in this) if (predicate(element)) ++count
return count
}