Permalink
Browse files

Fix Iterator#copyToArray (fixes SI-6827).

As pointed out in #scala, when using a non-zero start it's possible
to get an ArrayIndexOutOfBoundsException due to an incorrect bounds
check. This patch fixes this, as well as another potential bounds
error, and adds test cases.

Incorporates some other suggestions by Som-Snytt to ensure that
callers will get useful error messages in cases where the start
parameter is wrong (negative or out-of-array-bounds).

Review by @som-snytt.
  • Loading branch information...
1 parent e112ac9 commit 92cf0e354e38d450bfe34d4612f9f869faec2baf @non non committed with adriaanm Dec 18, 2012
Showing with 49 additions and 2 deletions.
  1. +3 −2 src/library/scala/collection/Iterator.scala
  2. +15 −0 test/files/run/t6827.check
  3. +31 −0 test/files/run/t6827.scala
@@ -1111,9 +1111,10 @@ trait Iterator[+A] extends TraversableOnce[A] {
* $willNotTerminateInf
*/
def copyToArray[B >: A](xs: Array[B], start: Int, len: Int): Unit = {
+ require(start >= 0 && start < xs.length, s"start $start out of range ${xs.length}")
var i = start
- val end = start + math.min(len, xs.length)
- while (hasNext && i < end) {
+ val end = start + math.min(len, xs.length - start)
+ while (i < end && hasNext) {
xs(i) = next()
i += 1
}
View
@@ -0,0 +1,15 @@
+start at -5: java.lang.IllegalArgumentException: requirement failed: start -5 out of range 10
+start at -1: java.lang.IllegalArgumentException: requirement failed: start -1 out of range 10
+start at limit: java.lang.IllegalArgumentException: requirement failed: start 10 out of range 10
+start at limit-1: ok
+first 10: ok
+read all: ok
+test huge len: ok
+5 from 5: ok
+20 from 5: ok
+test len overflow: ok
+start beyond limit: java.lang.IllegalArgumentException: requirement failed: start 30 out of range 10
+read 0: ok
+read -1: ok
+invalid read 0: java.lang.IllegalArgumentException: requirement failed: start 30 out of range 10
+invalid read -1: java.lang.IllegalArgumentException: requirement failed: start 30 out of range 10
View
@@ -0,0 +1,31 @@
+object Test extends App {
+ val ns = (0 until 20)
+ val arr = new Array[Int](10)
+
+ def tryit(label: String, start: Int, len: Int): Unit = {
+ val status = try {
+ val it = ns.toIterator
+ it.copyToArray(arr, start, len)
+ "ok"
+ } catch {
+ case e: Exception => e.toString
+ }
+ println("%s: %s" format (label, status))
+ }
+
+ tryit("start at -5", -5, 10)
+ tryit("start at -1", -1, 10)
+ tryit("start at limit", 10, 10)
+ tryit("start at limit-1", 9, 10)
+ tryit("first 10", 0, 10)
+ tryit("read all", 0, 20)
+ tryit("test huge len", 0, Int.MaxValue)
+ tryit("5 from 5", 5, 10)
+ tryit("20 from 5", 5, 20)
+ tryit("test len overflow", 5, Int.MaxValue)
+ tryit("start beyond limit", 30, 10)
+ tryit("read 0", 0, 0)
+ tryit("read -1", 0, -1)
+ tryit("invalid read 0", 30, 0)
+ tryit("invalid read -1", 30, -1)
+}

0 comments on commit 92cf0e3

Please sign in to comment.