From f8dae12708383506bc8cfdda878ce5e47cdac020 Mon Sep 17 00:00:00 2001 From: Ethan Atkins Date: Wed, 21 Aug 2019 08:51:49 -0700 Subject: [PATCH] Fix stack overflow in Glob ordering This issue was reported in https://github.com/sbt/sbt/issues/4970. The isssu was that the glob ordering had an infinite loop in it when a Root glob was compared to a FullFileGlob (which are created to convert directory + fileFilter to Glob for legacy support). The reason this hadn't been seen is because the play plugin is one of the few places that creates sbt.internal.io.Source from single paths, which is from where the Root globs (which are rarely a part of the watch globs) are coming. This seems to be a side effect of play putting assets in the source directory: watchSources ++= { ((sourceDirectory in Compile).value ** "*" --- (sourceDirectory in Assets).value ** "*").get }, is the setting that triggered the issue. --- io/src/main/scala/sbt/nio/file/Glob.scala | 2 ++ io/src/test/scala/sbt/nio/GlobOrderingSpec.scala | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/io/src/main/scala/sbt/nio/file/Glob.scala b/io/src/main/scala/sbt/nio/file/Glob.scala index 3099bab1..aa59843c 100644 --- a/io/src/main/scala/sbt/nio/file/Glob.scala +++ b/io/src/main/scala/sbt/nio/file/Glob.scala @@ -262,11 +262,13 @@ object Glob { case Root(leftRoot) => right match { case Root(rightRoot) => leftRoot.compareTo(rightRoot) + case _: FullFileGlob => -1 case _ => -compare(right, left) } case FullFileGlob(leftBase, _, _) => right match { case FullFileGlob(rightBase, _, _) => leftBase.compareTo(rightBase) + case _: Root => 1 case _ => -compare(right, left) } } diff --git a/io/src/test/scala/sbt/nio/GlobOrderingSpec.scala b/io/src/test/scala/sbt/nio/GlobOrderingSpec.scala index ec5d1831..12133860 100644 --- a/io/src/test/scala/sbt/nio/GlobOrderingSpec.scala +++ b/io/src/test/scala/sbt/nio/GlobOrderingSpec.scala @@ -26,4 +26,9 @@ class GlobOrderingSpec extends FlatSpec { val nonRecursive = Glob(dir) assert(Seq(nonRecursive, recursive).sorted == Seq(recursive, nonRecursive)) } + they should "not stack overflow" in IO.withTemporaryDirectory { dir => + val exact = Glob(dir.toPath.resolve("foo")) + val fullFile = sbt.internal.nio.Globs(dir.toPath, true, sbt.io.HiddenFileFilter) + assert(Seq(exact, fullFile).sorted == Seq(exact, fullFile)) + } }