From 58a3b64baf570ca77f272ae3cb836e9233d23f41 Mon Sep 17 00:00:00 2001 From: Ilya Gorbunov Date: Sat, 4 Aug 2018 01:27:34 +0300 Subject: [PATCH] Add argument validation in copyOf(newSize) in JS #KT-19489 --- libraries/stdlib/js/src/generated/_ArraysJs.kt | 9 +++++++++ libraries/stdlib/test/collections/ArraysTest.kt | 11 +++++++++++ .../tools/kotlin-stdlib-gen/src/templates/Arrays.kt | 9 ++++++++- 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/libraries/stdlib/js/src/generated/_ArraysJs.kt b/libraries/stdlib/js/src/generated/_ArraysJs.kt index c97524bf45c..6e23c5d96cb 100644 --- a/libraries/stdlib/js/src/generated/_ArraysJs.kt +++ b/libraries/stdlib/js/src/generated/_ArraysJs.kt @@ -504,6 +504,7 @@ public actual fun CharArray.copyOf(): CharArray { * @sample samples.collections.Arrays.CopyOfOperations.resizedPrimitiveCopyOf */ public actual fun ByteArray.copyOf(newSize: Int): ByteArray { + require(newSize >= 0) { "Invalid new array size: $newSize." } return fillFrom(this, ByteArray(newSize)) } @@ -517,6 +518,7 @@ public actual fun ByteArray.copyOf(newSize: Int): ByteArray { * @sample samples.collections.Arrays.CopyOfOperations.resizedPrimitiveCopyOf */ public actual fun ShortArray.copyOf(newSize: Int): ShortArray { + require(newSize >= 0) { "Invalid new array size: $newSize." } return fillFrom(this, ShortArray(newSize)) } @@ -530,6 +532,7 @@ public actual fun ShortArray.copyOf(newSize: Int): ShortArray { * @sample samples.collections.Arrays.CopyOfOperations.resizedPrimitiveCopyOf */ public actual fun IntArray.copyOf(newSize: Int): IntArray { + require(newSize >= 0) { "Invalid new array size: $newSize." } return fillFrom(this, IntArray(newSize)) } @@ -543,6 +546,7 @@ public actual fun IntArray.copyOf(newSize: Int): IntArray { * @sample samples.collections.Arrays.CopyOfOperations.resizedPrimitiveCopyOf */ public actual fun LongArray.copyOf(newSize: Int): LongArray { + require(newSize >= 0) { "Invalid new array size: $newSize." } return withType("LongArray", arrayCopyResize(this, newSize, 0L)) } @@ -556,6 +560,7 @@ public actual fun LongArray.copyOf(newSize: Int): LongArray { * @sample samples.collections.Arrays.CopyOfOperations.resizedPrimitiveCopyOf */ public actual fun FloatArray.copyOf(newSize: Int): FloatArray { + require(newSize >= 0) { "Invalid new array size: $newSize." } return fillFrom(this, FloatArray(newSize)) } @@ -569,6 +574,7 @@ public actual fun FloatArray.copyOf(newSize: Int): FloatArray { * @sample samples.collections.Arrays.CopyOfOperations.resizedPrimitiveCopyOf */ public actual fun DoubleArray.copyOf(newSize: Int): DoubleArray { + require(newSize >= 0) { "Invalid new array size: $newSize." } return fillFrom(this, DoubleArray(newSize)) } @@ -582,6 +588,7 @@ public actual fun DoubleArray.copyOf(newSize: Int): DoubleArray { * @sample samples.collections.Arrays.CopyOfOperations.resizedPrimitiveCopyOf */ public actual fun BooleanArray.copyOf(newSize: Int): BooleanArray { + require(newSize >= 0) { "Invalid new array size: $newSize." } return withType("BooleanArray", arrayCopyResize(this, newSize, false)) } @@ -595,6 +602,7 @@ public actual fun BooleanArray.copyOf(newSize: Int): BooleanArray { * @sample samples.collections.Arrays.CopyOfOperations.resizedPrimitiveCopyOf */ public actual fun CharArray.copyOf(newSize: Int): CharArray { + require(newSize >= 0) { "Invalid new array size: $newSize." } return withType("CharArray", fillFrom(this, CharArray(newSize))) } @@ -609,6 +617,7 @@ public actual fun CharArray.copyOf(newSize: Int): CharArray { */ @Suppress("ACTUAL_WITHOUT_EXPECT") public actual fun Array.copyOf(newSize: Int): Array { + require(newSize >= 0) { "Invalid new array size: $newSize." } return arrayCopyResize(this, newSize, null) } diff --git a/libraries/stdlib/test/collections/ArraysTest.kt b/libraries/stdlib/test/collections/ArraysTest.kt index 0c053ce80d2..81f1b8d4058 100644 --- a/libraries/stdlib/test/collections/ArraysTest.kt +++ b/libraries/stdlib/test/collections/ArraysTest.kt @@ -724,6 +724,17 @@ class ArraysTest { assertArrayNotSameButEquals(charArrayOf('A', 'B'), charArrayOf('A', 'B', 'C').copyOf(2)) assertArrayNotSameButEquals(charArrayOf('A', 'B', '\u0000'), charArrayOf('A', 'B').copyOf(3)) + + assertArrayNotSameButEquals(emptyArray(), arrayOf("x").copyOf(0)) + assertArrayNotSameButEquals(intArrayOf(), intArrayOf(1).copyOf(0)) + assertArrayNotSameButEquals(longArrayOf(), longArrayOf(1).copyOf(0)) + assertArrayNotSameButEquals(charArrayOf(), charArrayOf('a').copyOf(0)) + + // RuntimeException is the most specific common of JVM and JS implementations + assertFailsWith { arrayOf("x").copyOf(-1) } + assertFailsWith { intArrayOf().copyOf(-1) } + assertFailsWith { longArrayOf().copyOf(-1) } + assertFailsWith { charArrayOf('c').copyOf(-1) } } @Test fun copyOfRange() { diff --git a/libraries/tools/kotlin-stdlib-gen/src/templates/Arrays.kt b/libraries/tools/kotlin-stdlib-gen/src/templates/Arrays.kt index bed61de4d98..f667458c2f4 100644 --- a/libraries/tools/kotlin-stdlib-gen/src/templates/Arrays.kt +++ b/libraries/tools/kotlin-stdlib-gen/src/templates/Arrays.kt @@ -453,6 +453,7 @@ object ArrayOps : TemplateGroupBase() { - If [newSize] is greater than the size of the original array, the extra elements in the copy array are filled with ${primitive.zero} values. """ } + val newSizeCheck = """require(newSize >= 0) { "Invalid new array size: ${'$'}newSize." }""" specialFor(ArraysOfPrimitives) { sample("samples.collections.Arrays.CopyOfOperations.resizedPrimitiveCopyOf") returns("SELF") @@ -467,6 +468,7 @@ object ArrayOps : TemplateGroupBase() { else -> body { "return fillFrom(this, ${primitive}Array(newSize))" } } + body { newSizeCheck + "\n" + body } } } @@ -476,7 +478,12 @@ object ArrayOps : TemplateGroupBase() { on(Platform.JS) { family = ArraysOfObjects suppress("ACTUAL_WITHOUT_EXPECT") // TODO: KT-21937 - body { "return arrayCopyResize(this, newSize, null)" } + body { + """ + $newSizeCheck + return arrayCopyResize(this, newSize, null) + """ + } } } on(Platform.JVM) {