From c592201a437ca8c4958add13127dc84386396e58 Mon Sep 17 00:00:00 2001 From: Abduqodiri Qurbonzoda Date: Tue, 21 Jan 2020 06:42:08 +0300 Subject: [PATCH] Fail fast in Regex.findAll on an invalid startIndex #KT-28356 --- libraries/stdlib/js/src/kotlin/text/regex.kt | 10 ++++++++-- libraries/stdlib/jvm/src/kotlin/text/regex/Regex.kt | 10 ++++++++-- libraries/stdlib/test/text/RegexTest.kt | 6 ++++++ 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/libraries/stdlib/js/src/kotlin/text/regex.kt b/libraries/stdlib/js/src/kotlin/text/regex.kt index 1f1be0e7dfa..2b37102f1d3 100644 --- a/libraries/stdlib/js/src/kotlin/text/regex.kt +++ b/libraries/stdlib/js/src/kotlin/text/regex.kt @@ -77,11 +77,17 @@ public actual class Regex actual constructor(pattern: String, options: Set = - generateSequence({ find(input, startIndex) }, { match -> match.next() }) + public actual fun findAll(input: CharSequence, startIndex: Int = 0): Sequence { + if (startIndex < 0 || startIndex > input.length) { + throw IndexOutOfBoundsException("Start index out of bounds: $startIndex, input length: ${input.length}") + } + return generateSequence({ find(input, startIndex) }, { match -> match.next() }) + } /** * Attempts to match the entire [input] CharSequence against the pattern. diff --git a/libraries/stdlib/jvm/src/kotlin/text/regex/Regex.kt b/libraries/stdlib/jvm/src/kotlin/text/regex/Regex.kt index ae8b63ef05c..93cdf3f694c 100644 --- a/libraries/stdlib/jvm/src/kotlin/text/regex/Regex.kt +++ b/libraries/stdlib/jvm/src/kotlin/text/regex/Regex.kt @@ -122,11 +122,17 @@ internal constructor(private val nativePattern: Pattern) : Serializable { /** * Returns a sequence of all occurrences of a regular expression within the [input] string, beginning at the specified [startIndex]. * + * @throws IndexOutOfBoundsException if [startIndex] is less than zero or greater than the length of the [input] char sequence. + * * @sample samples.text.Regexps.findAll */ @Suppress("ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS") - public actual fun findAll(input: CharSequence, startIndex: Int = 0): Sequence = - generateSequence({ find(input, startIndex) }, MatchResult::next) + public actual fun findAll(input: CharSequence, startIndex: Int = 0): Sequence { + if (startIndex < 0 || startIndex > input.length) { + throw IndexOutOfBoundsException("Start index out of bounds: $startIndex, input length: ${input.length}") + } + return generateSequence({ find(input, startIndex) }, MatchResult::next) + } /** * Attempts to match the entire [input] CharSequence against the pattern. diff --git a/libraries/stdlib/test/text/RegexTest.kt b/libraries/stdlib/test/text/RegexTest.kt index 1bb736c5089..1dd5a603cc5 100644 --- a/libraries/stdlib/test/text/RegexTest.kt +++ b/libraries/stdlib/test/text/RegexTest.kt @@ -67,6 +67,10 @@ class RegexTest { assertEquals(expected.drop(1), pattern.findAll(input, startIndex = 3).map { it.value }.toList()) assertEquals(listOf(0..2, 4..6, 8..10), matches.map { it.range }.toList()) + + assertFailsWith { pattern.findAll(input, -1) } + assertFailsWith { pattern.findAll(input, input.length + 1) } + assertEquals(emptyList(), pattern.findAll(input, input.length).toList()) } @Test fun matchAllSequence() { @@ -76,6 +80,8 @@ class RegexTest { assertEquals(input, matches[0].value) assertEquals(input, matches.joinToString("") { it.value }) assertEquals(2, matches.size) + + assertEquals("", pattern.findAll(input, input.length).single().value) } @Test fun matchGroups() {