Permalink
Browse files

SI-8100 - prevent possible SOE during Stream#flatten.

This commit changes stream flatten to avoid allocating a
stack frame for every stream item. Previously, flattening
a stream whose elements are mostly empty would result in
a StackOverflowException.

This commit also adds a test demonstrating the problem.
  • Loading branch information...
1 parent 9f0594c commit 2477bbd9d64df3dbfac063e1fc71115daf0f3ea7 @non non committed Dec 24, 2013
Showing with 19 additions and 8 deletions.
  1. +10 −8 src/library/scala/collection/immutable/Stream.scala
  2. +1 −0 test/files/run/t8100.check
  3. +8 −0 test/files/run/t8100.scala
@@ -960,14 +960,16 @@ self =>
* }}}
*/
override def flatten[B](implicit asTraversable: A => /*<:<!!!*/ GenTraversableOnce[B]): Stream[B] = {
- def flatten1(t: Traversable[B]): Stream[B] =
- if (!t.isEmpty)
- cons(t.head, flatten1(t.tail))
- else
- tail.flatten
-
- if (isEmpty) Stream.empty
- else flatten1(asTraversable(head).seq.toTraversable)
+ var st: Stream[A] = this
+ while (st.nonEmpty) {
+ val h = asTraversable(st.head)
+ if (h.isEmpty) {
+ st = st.tail
+ } else {
+ return h.toStream #::: st.tail.flatten
+ }
+ }
+ Stream.empty
}
override def view = new StreamView[A, Stream[A]] {
@@ -0,0 +1 @@
+Success(0)
@@ -0,0 +1,8 @@
+object Test {
+ import scala.util.Try
+
+ def main(args: Array[String]): Unit = {
+ def stream = Stream.from(0).take(100000).map(n => None)
+ println(Try(stream.flatten.length))
+ }
+}

0 comments on commit 2477bbd

Please sign in to comment.