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
@@ -364,3 +364,20 @@ private fun rangeCheck(size: Int, fromIndex: Int, toIndex: Int) {
}
@PublishedApi
@SinceKotlin("1.3")
internal expect fun checkIndexOverflow(index: Int): Int
@PublishedApi
@SinceKotlin("1.3")
internal expect fun checkCountOverflow(count: Int): Int
@PublishedApi
@SinceKotlin("1.3")
internal fun throwIndexOverflow() { throw ArithmeticException("Index overflow has happened.") }
@PublishedApi
@SinceKotlin("1.3")
internal fun throwCountOverflow() { throw ArithmeticException("Count overflow has happened.") }
@@ -37,5 +37,5 @@ public inline fun <T> Iterator<T>.forEach(operation: (T) -> Unit): Unit {
internal class IndexingIterator<out T>(private val iterator: Iterator<T>) : Iterator<IndexedValue<T>> {
private var index = 0
final override fun hasNext(): Boolean = iterator.hasNext()
final override fun next(): IndexedValue<T> = IndexedValue(index++, iterator.next())
final override fun next(): IndexedValue<T> = IndexedValue(checkIndexOverflow(index++), iterator.next())
}
@@ -178,7 +178,7 @@ constructor(private val sequence: Sequence<T>, private val transformer: (Int, T)
val iterator = sequence.iterator()
var index = 0
override fun next(): R {
return transformer(index++, iterator.next())
return transformer(checkIndexOverflow(index++), iterator.next())
}
override fun hasNext(): Boolean {
@@ -197,7 +197,7 @@ constructor(private val sequence: Sequence<T>) : Sequence<IndexedValue<T>> {
val iterator = sequence.iterator()
var index = 0
override fun next(): IndexedValue<T> {
return IndexedValue(index++, iterator.next())
return IndexedValue(checkIndexOverflow(index++), iterator.next())
}
override fun hasNext(): Boolean {