Skip to content

Commit d2ee92f

Browse files
committed
SI-7880 Fix infinite loop in ResizableArray#ensureSize
This issue was triggered for values greater than Int.MaxValue/2, which caused the computation of the new array size to overflow and become negative, leading to an infinite loop.
1 parent b5ef79f commit d2ee92f

File tree

2 files changed

+20
-9
lines changed

2 files changed

+20
-9
lines changed

src/library/scala/collection/mutable/ResizableArray.scala

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -89,16 +89,20 @@ trait ResizableArray[A] extends IndexedSeq[A]
8989
}
9090
}
9191

92-
/** Ensure that the internal array has at `n` cells. */
92+
/** Ensure that the internal array has at least `n` cells. */
9393
protected def ensureSize(n: Int) {
94-
if (n > array.length) {
95-
var newsize = array.length * 2
96-
while (n > newsize)
97-
newsize = newsize * 2
98-
99-
val newar: Array[AnyRef] = new Array(newsize)
100-
scala.compat.Platform.arraycopy(array, 0, newar, 0, size0)
101-
array = newar
94+
// Use a Long to prevent overflows
95+
val arrayLength: Long = array.length
96+
if (n > arrayLength) {
97+
var newSize: Long = arrayLength * 2
98+
while (n > newSize)
99+
newSize = newSize * 2
100+
// Clamp newSize to Int.MaxValue
101+
if (newSize > Int.MaxValue) newSize = Int.MaxValue
102+
103+
val newArray: Array[AnyRef] = new Array(newSize.toInt)
104+
scala.compat.Platform.arraycopy(array, 0, newArray, 0, size0)
105+
array = newArray
102106
}
103107
}
104108

test/files/run/t7880.scala

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
object Test extends App {
2+
// This should terminate in one way or another, but it shouldn't loop forever.
3+
try {
4+
val buffer = collection.mutable.ArrayBuffer.fill(Int.MaxValue / 2 + 1)(0)
5+
buffer append 1
6+
} catch { case _: OutOfMemoryError => }
7+
}

0 commit comments

Comments
 (0)