diff --git a/libraries/stdlib/native-wasm/src/kotlin/text/StringBuilder.kt b/libraries/stdlib/native-wasm/src/kotlin/text/StringBuilder.kt index 0f44f22f138..a29ef7d5560 100644 --- a/libraries/stdlib/native-wasm/src/kotlin/text/StringBuilder.kt +++ b/libraries/stdlib/native-wasm/src/kotlin/text/StringBuilder.kt @@ -199,12 +199,8 @@ actual class StringBuilder private constructor ( * Otherwise, this method takes no action and simply returns. */ actual fun ensureCapacity(minimumCapacity: Int) { - if (minimumCapacity > array.size) { - var newSize = array.size * 2 + 2 - if (minimumCapacity > newSize) - newSize = minimumCapacity - array = array.copyOf(newSize) - } + if (minimumCapacity <= array.size) return + ensureCapacityInternal(minimumCapacity) } /** @@ -612,7 +608,15 @@ actual class StringBuilder private constructor ( // ---------------------------- private ---------------------------- private fun ensureExtraCapacity(n: Int) { - ensureCapacity(_length + n) + ensureCapacityInternal(_length + n) + } + + private fun ensureCapacityInternal(minCapacity: Int) { + if (minCapacity < 0) throw OutOfMemoryError() // overflow + if (minCapacity > array.size) { + val newSize = AbstractList.newCapacity(array.size, minCapacity) + array = array.copyOf(newSize) + } } private fun checkIndex(index: Int) { diff --git a/libraries/stdlib/test/text/StringBuilderTest.kt b/libraries/stdlib/test/text/StringBuilderTest.kt index a50689ee520..df4f1eb32e7 100644 --- a/libraries/stdlib/test/text/StringBuilderTest.kt +++ b/libraries/stdlib/test/text/StringBuilderTest.kt @@ -272,6 +272,8 @@ class StringBuilderTest { repeat(Random.nextInt(35, 62)) { sb.insert(0, "s") } sb.ensureCapacity(1) assertTrue(sb.capacity() >= sb.length) + sb.ensureCapacity(-1) // negative argument is ignored + assertTrue(sb.capacity() >= sb.length) sb.ensureCapacity(sb.length * 10) testExceptOn(TestPlatform.Js) { assertTrue(sb.capacity() >= sb.length * 10) // not implemented in JS @@ -279,6 +281,26 @@ class StringBuilderTest { } } + @Test + fun overflow() = testExceptOn(TestPlatform.Js) { + class CharSeq(override val length: Int) : CharSequence { + override fun get(index: Int): Char = + throw IllegalStateException("Not expected to be called") + + override fun subSequence(startIndex: Int, endIndex: Int): CharSequence = + throw IllegalStateException("Not expected to be called") + } + + val initialContent = "a".repeat(20) + val bigCharSeq = CharSeq(Int.MAX_VALUE - initialContent.length + 1) + assertFailsWith { // OutOfMemoryError + StringBuilder(initialContent).append(bigCharSeq) + } + assertFailsWith { // OutOfMemoryError + StringBuilder(initialContent).insert(5, bigCharSeq) + } + } + @Test fun indexOf() { StringBuilder("my indexOf test").let { sb ->