From b712494e477c2c54d17517851b1290ef90e09152 Mon Sep 17 00:00:00 2001 From: "Sergey.Shanshin" Date: Thu, 8 Aug 2024 11:58:21 +0200 Subject: [PATCH 1/9] Implemented skipping of filed with proto Id=0 if it missed in the descriptor Also optimized skipping of size delimited fields - removed the creation of an byte array in case of skipping Fixes #2649 --- .../protobuf/internal/ProtobufDecoding.kt | 6 ++- .../protobuf/internal/ProtobufReader.kt | 9 ++++- .../protobuf/internal/Streams.kt | 6 +++ .../serialization/protobuf/SkipFieldsTest.kt | 39 +++++++++++++++++++ 4 files changed, 58 insertions(+), 2 deletions(-) create mode 100644 formats/protobuf/commonTest/src/kotlinx/serialization/protobuf/SkipFieldsTest.kt diff --git a/formats/protobuf/commonMain/src/kotlinx/serialization/protobuf/internal/ProtobufDecoding.kt b/formats/protobuf/commonMain/src/kotlinx/serialization/protobuf/internal/ProtobufDecoding.kt index 7cae22a24..f8d4b351d 100644 --- a/formats/protobuf/commonMain/src/kotlinx/serialization/protobuf/internal/ProtobufDecoding.kt +++ b/formats/protobuf/commonMain/src/kotlinx/serialization/protobuf/internal/ProtobufDecoding.kt @@ -45,8 +45,12 @@ internal open class ProtobufDecoder( * If we have reasonably small count of elements, try to build sequential * array for the fast-path. Fast-path implies that elements are not marked with @ProtoId * explicitly or are monotonic and incremental (maybe, 1-indexed) + * + * Since the library allows the use of fields with proto ID 0, + * it is necessary to initialize all elements, because there will always be one extra element + * in the fast path array, which misses in the descriptor */ - val cache = IntArray(elements + 1) + val cache = IntArray(elements + 1) { -1 } for (i in 0 until elements) { val protoId = extractProtoId(descriptor, i, false) // If any element is marked as ProtoOneOf, diff --git a/formats/protobuf/commonMain/src/kotlinx/serialization/protobuf/internal/ProtobufReader.kt b/formats/protobuf/commonMain/src/kotlinx/serialization/protobuf/internal/ProtobufReader.kt index 3fab92001..528f14236 100644 --- a/formats/protobuf/commonMain/src/kotlinx/serialization/protobuf/internal/ProtobufReader.kt +++ b/formats/protobuf/commonMain/src/kotlinx/serialization/protobuf/internal/ProtobufReader.kt @@ -59,7 +59,7 @@ internal class ProtobufReader(private val input: ByteArrayInput) { when (currentType) { ProtoWireType.VARINT -> readInt(ProtoIntegerType.DEFAULT) ProtoWireType.i64 -> readLong(ProtoIntegerType.FIXED) - ProtoWireType.SIZE_DELIMITED -> readByteArray() + ProtoWireType.SIZE_DELIMITED -> skipSizeDelimited() ProtoWireType.i32 -> readInt(ProtoIntegerType.FIXED) else -> throw ProtobufDecodingException("Unsupported start group or end group wire type: $currentType") } @@ -75,6 +75,13 @@ internal class ProtobufReader(private val input: ByteArrayInput) { return readByteArrayNoTag() } + fun skipSizeDelimited() { + assertWireType(SIZE_DELIMITED) + val length = decode32() + checkLength(length) + input.scipExactNBytes(length) + } + fun readByteArrayNoTag(): ByteArray { val length = decode32() checkLength(length) diff --git a/formats/protobuf/commonMain/src/kotlinx/serialization/protobuf/internal/Streams.kt b/formats/protobuf/commonMain/src/kotlinx/serialization/protobuf/internal/Streams.kt index 575c5e742..ec43d92bd 100644 --- a/formats/protobuf/commonMain/src/kotlinx/serialization/protobuf/internal/Streams.kt +++ b/formats/protobuf/commonMain/src/kotlinx/serialization/protobuf/internal/Streams.kt @@ -33,6 +33,12 @@ internal class ByteArrayInput(private var array: ByteArray, private val endIndex return b } + + fun scipExactNBytes(bytesCount: Int) { + ensureEnoughBytes(bytesCount) + position += bytesCount + } + private fun ensureEnoughBytes(bytesCount: Int) { if (bytesCount > availableBytes) { throw SerializationException("Unexpected EOF, available $availableBytes bytes, requested: $bytesCount") diff --git a/formats/protobuf/commonTest/src/kotlinx/serialization/protobuf/SkipFieldsTest.kt b/formats/protobuf/commonTest/src/kotlinx/serialization/protobuf/SkipFieldsTest.kt new file mode 100644 index 000000000..5def6a2ad --- /dev/null +++ b/formats/protobuf/commonTest/src/kotlinx/serialization/protobuf/SkipFieldsTest.kt @@ -0,0 +1,39 @@ +/* + * Copyright 2017-2024 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. + */ + +package kotlinx.serialization.protobuf + + +import kotlinx.serialization.* +import kotlin.test.* + +class SkipFieldsTest { + + @Serializable + data class Holder(val value: Int) + + @Test + fun testSkipZeroId() { + // first value with id = 0 + val hexString = "000f082a" + val holder = ProtoBuf.decodeFromHexString(hexString) + assertEquals(42, holder.value) + } + + @Test + fun testSkipBigId() { + // first value with id = 2047 and takes 2 bytes + val hexString = "f87f20082a" + val holder = ProtoBuf.decodeFromHexString(hexString) + assertEquals(42, holder.value) + } + + @Test + fun testSkipString() { + // first value is size delimited (string) with id = 42 + val hexString = "d2020c48656c6c6f20576f726c6421082a" + val holder = ProtoBuf.decodeFromHexString(hexString) + assertEquals(42, holder.value) + } +} \ No newline at end of file From c5c5d9f65a96ed6adb8b41eb76f0da0e4848a212 Mon Sep 17 00:00:00 2001 From: "Sergey.Shanshin" Date: Thu, 8 Aug 2024 17:47:34 +0200 Subject: [PATCH 2/9] Prohibited using of zero and negative filed number in ProtoNumber and zero field numbers in input bytes Fixes #1566 --- .../protobuf/internal/Helpers.kt | 11 +++ .../protobuf/internal/ProtobufDecoding.kt | 3 + .../protobuf/internal/ProtobufReader.kt | 2 +- .../protobuf/internal/Streams.kt | 2 +- .../protobuf/InvalidFieldNumberTest.kt | 70 +++++++++++++++++++ .../protobuf/PackedArraySerializerTest.kt | 5 +- .../serialization/protobuf/SkipFieldsTest.kt | 12 +--- 7 files changed, 90 insertions(+), 15 deletions(-) create mode 100644 formats/protobuf/commonTest/src/kotlinx/serialization/protobuf/InvalidFieldNumberTest.kt diff --git a/formats/protobuf/commonMain/src/kotlinx/serialization/protobuf/internal/Helpers.kt b/formats/protobuf/commonMain/src/kotlinx/serialization/protobuf/internal/Helpers.kt index d696bf07b..db607a2d2 100644 --- a/formats/protobuf/commonMain/src/kotlinx/serialization/protobuf/internal/Helpers.kt +++ b/formats/protobuf/commonMain/src/kotlinx/serialization/protobuf/internal/Helpers.kt @@ -87,6 +87,7 @@ internal fun SerialDescriptor.extractParameters(index: Int): ProtoDesc { val annotation = annotations[i] if (annotation is ProtoNumber) { protoId = annotation.number + checkFieldNumber(protoId, this) } else if (annotation is ProtoType) { format = annotation.type } else if (annotation is ProtoPacked) { @@ -118,11 +119,21 @@ internal fun extractProtoId(descriptor: SerialDescriptor, index: Int, zeroBasedD return ID_HOLDER_ONE_OF } else if (annotation is ProtoNumber) { result = annotation.number + // 0 or negative numbers are acceptable for enums + if (!zeroBasedDefault) { + checkFieldNumber(result, descriptor) + } } } return result } +private fun checkFieldNumber(fieldNumber: Int, descriptor: SerialDescriptor) { + if (fieldNumber <= 0) { + throw SerializationException("$fieldNumber is not allowed in ProtoNumber for ${descriptor.serialName}, because protobuf support field values in range 1..2147483647") + } +} + internal class ProtobufDecodingException(message: String, e: Throwable? = null) : SerializationException(message, e) internal expect fun Int.reverseBytes(): Int diff --git a/formats/protobuf/commonMain/src/kotlinx/serialization/protobuf/internal/ProtobufDecoding.kt b/formats/protobuf/commonMain/src/kotlinx/serialization/protobuf/internal/ProtobufDecoding.kt index f8d4b351d..f7584917e 100644 --- a/formats/protobuf/commonMain/src/kotlinx/serialization/protobuf/internal/ProtobufDecoding.kt +++ b/formats/protobuf/commonMain/src/kotlinx/serialization/protobuf/internal/ProtobufDecoding.kt @@ -311,6 +311,9 @@ internal open class ProtobufDecoder( if (protoId == -1) { // EOF return elementMarker.nextUnmarkedIndex() } + if (protoId == 0) { + throw SerializationException("0 is not allowed as the protobuf field number in ${descriptor.serialName}, the input bytes may have been corrupted") + } val index = getIndexByNum(protoId) if (index == -1) { // not found reader.skipElement() diff --git a/formats/protobuf/commonMain/src/kotlinx/serialization/protobuf/internal/ProtobufReader.kt b/formats/protobuf/commonMain/src/kotlinx/serialization/protobuf/internal/ProtobufReader.kt index 528f14236..29177c041 100644 --- a/formats/protobuf/commonMain/src/kotlinx/serialization/protobuf/internal/ProtobufReader.kt +++ b/formats/protobuf/commonMain/src/kotlinx/serialization/protobuf/internal/ProtobufReader.kt @@ -79,7 +79,7 @@ internal class ProtobufReader(private val input: ByteArrayInput) { assertWireType(SIZE_DELIMITED) val length = decode32() checkLength(length) - input.scipExactNBytes(length) + input.skipExactNBytes(length) } fun readByteArrayNoTag(): ByteArray { diff --git a/formats/protobuf/commonMain/src/kotlinx/serialization/protobuf/internal/Streams.kt b/formats/protobuf/commonMain/src/kotlinx/serialization/protobuf/internal/Streams.kt index ec43d92bd..ea2ab5e4e 100644 --- a/formats/protobuf/commonMain/src/kotlinx/serialization/protobuf/internal/Streams.kt +++ b/formats/protobuf/commonMain/src/kotlinx/serialization/protobuf/internal/Streams.kt @@ -34,7 +34,7 @@ internal class ByteArrayInput(private var array: ByteArray, private val endIndex } - fun scipExactNBytes(bytesCount: Int) { + fun skipExactNBytes(bytesCount: Int) { ensureEnoughBytes(bytesCount) position += bytesCount } diff --git a/formats/protobuf/commonTest/src/kotlinx/serialization/protobuf/InvalidFieldNumberTest.kt b/formats/protobuf/commonTest/src/kotlinx/serialization/protobuf/InvalidFieldNumberTest.kt new file mode 100644 index 000000000..17f5263a9 --- /dev/null +++ b/formats/protobuf/commonTest/src/kotlinx/serialization/protobuf/InvalidFieldNumberTest.kt @@ -0,0 +1,70 @@ +/* + * Copyright 2017-2024 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. + */ + +package kotlinx.serialization.protobuf + + +import kotlinx.serialization.* +import kotlin.test.* + +class InvalidFieldNumberTest { + + @Serializable + data class Holder(val value: Int) + + @Serializable + data class ListHolder(val value: List) + + @Serializable + data class ZeroProtoNumber(@ProtoNumber(0) val value: Int) + + @Serializable + data class NegativeProtoNumber(@ProtoNumber(-5) val value: Int) + + @Test + fun testDeserializeZeroInput() { + assertFailsWithMessage("0 is not allowed as the protobuf field number in kotlinx.serialization.protobuf.InvalidFieldNumberTest.Holder, the input bytes may have been corrupted") { + // first value with field number = 0 + val hexString = "000f" + ProtoBuf.decodeFromHexString(hexString) + } + } + + @Test + fun testDeserializeZeroInputForElement() { + assertFailsWithMessage("0 is not allowed as the protobuf field number in kotlinx.serialization.protobuf.InvalidFieldNumberTest.ListHolder, the input bytes may have been corrupted") { + // first element with field number = 0 + val hexString = "000f" + ProtoBuf.decodeFromHexString(hexString) + } + } + + @Test + fun testSerializeZeroProtoNumber() { + assertFailsWithMessage("0 is not allowed in ProtoNumber for kotlinx.serialization.protobuf.InvalidFieldNumberTest.ZeroProtoNumber, because protobuf support field values in range 1..2147483647") { + ProtoBuf.encodeToHexString(ZeroProtoNumber(42)) + } + } + + @Test + fun testDeserializeZeroProtoNumber() { + assertFailsWithMessage("0 is not allowed in ProtoNumber for kotlinx.serialization.protobuf.InvalidFieldNumberTest.ZeroProtoNumber, because protobuf support field values in range 1..2147483647") { + ProtoBuf.decodeFromHexString("000f") + } + } + + @Test + fun testSerializeNegativeProtoNumber() { + assertFailsWithMessage("-5 is not allowed in ProtoNumber for kotlinx.serialization.protobuf.InvalidFieldNumberTest.NegativeProtoNumber, because protobuf support field values in range 1..2147483647") { + ProtoBuf.encodeToHexString(NegativeProtoNumber(42)) + } + } + + @Test + fun testDeserializeNegativeProtoNumber() { + assertFailsWithMessage("-5 is not allowed in ProtoNumber for kotlinx.serialization.protobuf.InvalidFieldNumberTest.NegativeProtoNumber, because protobuf support field values in range 1..2147483647") { + ProtoBuf.decodeFromHexString("000f") + } + } +} \ No newline at end of file diff --git a/formats/protobuf/commonTest/src/kotlinx/serialization/protobuf/PackedArraySerializerTest.kt b/formats/protobuf/commonTest/src/kotlinx/serialization/protobuf/PackedArraySerializerTest.kt index e7bf67622..d6e604fd1 100644 --- a/formats/protobuf/commonTest/src/kotlinx/serialization/protobuf/PackedArraySerializerTest.kt +++ b/formats/protobuf/commonTest/src/kotlinx/serialization/protobuf/PackedArraySerializerTest.kt @@ -47,7 +47,6 @@ class PackedArraySerializerTest { @Serializable data class PackedStringCarrier( - @ProtoNumber(0) @ProtoPacked val s: List ) @@ -110,12 +109,12 @@ class PackedArraySerializerTest { @Test fun testEncodeAnnotatedStringList() { val obj = PackedStringCarrier(listOf("aaa", "bbb", "ccc")) - val expectedHex = "020361616102036262620203636363" + val expectedHex = "0a036161610a036262620a03636363" val encodedHex = ProtoBuf.encodeToHexString(obj) assertEquals(expectedHex, encodedHex) assertEquals(obj, ProtoBuf.decodeFromHexString(expectedHex)) - val invalidPackedHex = "020C036161610362626203636363" + val invalidPackedHex = "0a0C036161610362626203636363" val decoded = ProtoBuf.decodeFromHexString(invalidPackedHex) val invalidString = "\u0003aaa\u0003bbb\u0003ccc" assertEquals(PackedStringCarrier(listOf(invalidString)), decoded) diff --git a/formats/protobuf/commonTest/src/kotlinx/serialization/protobuf/SkipFieldsTest.kt b/formats/protobuf/commonTest/src/kotlinx/serialization/protobuf/SkipFieldsTest.kt index 5def6a2ad..1d60d951a 100644 --- a/formats/protobuf/commonTest/src/kotlinx/serialization/protobuf/SkipFieldsTest.kt +++ b/formats/protobuf/commonTest/src/kotlinx/serialization/protobuf/SkipFieldsTest.kt @@ -14,15 +14,7 @@ class SkipFieldsTest { data class Holder(val value: Int) @Test - fun testSkipZeroId() { - // first value with id = 0 - val hexString = "000f082a" - val holder = ProtoBuf.decodeFromHexString(hexString) - assertEquals(42, holder.value) - } - - @Test - fun testSkipBigId() { + fun testSkipBigFieldNumber() { // first value with id = 2047 and takes 2 bytes val hexString = "f87f20082a" val holder = ProtoBuf.decodeFromHexString(hexString) @@ -30,7 +22,7 @@ class SkipFieldsTest { } @Test - fun testSkipString() { + fun testSkipUnknownFiledNumberForString() { // first value is size delimited (string) with id = 42 val hexString = "d2020c48656c6c6f20576f726c6421082a" val holder = ProtoBuf.decodeFromHexString(hexString) From 49c8a93093390fe42a54a8a94690619a83575116 Mon Sep 17 00:00:00 2001 From: Sergey Shanshin Date: Fri, 23 Aug 2024 17:18:04 +0200 Subject: [PATCH 3/9] Apply suggestions from code review Co-authored-by: Leonid Startsev --- .../src/kotlinx/serialization/protobuf/internal/Helpers.kt | 2 +- .../kotlinx/serialization/protobuf/internal/ProtobufDecoding.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/formats/protobuf/commonMain/src/kotlinx/serialization/protobuf/internal/Helpers.kt b/formats/protobuf/commonMain/src/kotlinx/serialization/protobuf/internal/Helpers.kt index db607a2d2..865c43c31 100644 --- a/formats/protobuf/commonMain/src/kotlinx/serialization/protobuf/internal/Helpers.kt +++ b/formats/protobuf/commonMain/src/kotlinx/serialization/protobuf/internal/Helpers.kt @@ -130,7 +130,7 @@ internal fun extractProtoId(descriptor: SerialDescriptor, index: Int, zeroBasedD private fun checkFieldNumber(fieldNumber: Int, descriptor: SerialDescriptor) { if (fieldNumber <= 0) { - throw SerializationException("$fieldNumber is not allowed in ProtoNumber for ${descriptor.serialName}, because protobuf support field values in range 1..2147483647") + throw SerializationException("$fieldNumber is not allowed in ProtoNumber for ${descriptor.serialName}, because protobuf support field numbers in range 1..${Int.MAX_VALUE}}") } } diff --git a/formats/protobuf/commonMain/src/kotlinx/serialization/protobuf/internal/ProtobufDecoding.kt b/formats/protobuf/commonMain/src/kotlinx/serialization/protobuf/internal/ProtobufDecoding.kt index f7584917e..48cb24a47 100644 --- a/formats/protobuf/commonMain/src/kotlinx/serialization/protobuf/internal/ProtobufDecoding.kt +++ b/formats/protobuf/commonMain/src/kotlinx/serialization/protobuf/internal/ProtobufDecoding.kt @@ -48,7 +48,7 @@ internal open class ProtobufDecoder( * * Since the library allows the use of fields with proto ID 0, * it is necessary to initialize all elements, because there will always be one extra element - * in the fast path array, which misses in the descriptor + * in the fast path array, which is missing from the descriptor */ val cache = IntArray(elements + 1) { -1 } for (i in 0 until elements) { From 18b4846fb7d2642b5c9d6d9c5a2952bba9937655 Mon Sep 17 00:00:00 2001 From: "Sergey.Shanshin" Date: Fri, 23 Aug 2024 17:35:37 +0200 Subject: [PATCH 4/9] ~review fixes --- .../serialization/protobuf/internal/Helpers.kt | 8 ++++---- .../protobuf/internal/ProtobufDecoding.kt | 4 ++-- .../serialization/protobuf/AutoAssignIdsTest.kt | 11 +++++++++++ .../serialization/protobuf/InvalidFieldNumberTest.kt | 10 +++++----- 4 files changed, 22 insertions(+), 11 deletions(-) diff --git a/formats/protobuf/commonMain/src/kotlinx/serialization/protobuf/internal/Helpers.kt b/formats/protobuf/commonMain/src/kotlinx/serialization/protobuf/internal/Helpers.kt index 865c43c31..aa380aa73 100644 --- a/formats/protobuf/commonMain/src/kotlinx/serialization/protobuf/internal/Helpers.kt +++ b/formats/protobuf/commonMain/src/kotlinx/serialization/protobuf/internal/Helpers.kt @@ -87,7 +87,7 @@ internal fun SerialDescriptor.extractParameters(index: Int): ProtoDesc { val annotation = annotations[i] if (annotation is ProtoNumber) { protoId = annotation.number - checkFieldNumber(protoId, this) + checkFieldNumber(protoId, i, this) } else if (annotation is ProtoType) { format = annotation.type } else if (annotation is ProtoPacked) { @@ -121,16 +121,16 @@ internal fun extractProtoId(descriptor: SerialDescriptor, index: Int, zeroBasedD result = annotation.number // 0 or negative numbers are acceptable for enums if (!zeroBasedDefault) { - checkFieldNumber(result, descriptor) + checkFieldNumber(result, i, descriptor) } } } return result } -private fun checkFieldNumber(fieldNumber: Int, descriptor: SerialDescriptor) { +private fun checkFieldNumber(fieldNumber: Int, propertyIndex: Int, descriptor: SerialDescriptor) { if (fieldNumber <= 0) { - throw SerializationException("$fieldNumber is not allowed in ProtoNumber for ${descriptor.serialName}, because protobuf support field numbers in range 1..${Int.MAX_VALUE}}") + throw SerializationException("$fieldNumber is not allowed in ProtoNumber for property '${descriptor.getElementName(propertyIndex)}' of '${descriptor.serialName}', because protobuf support field numbers in range 1..${Int.MAX_VALUE}") } } diff --git a/formats/protobuf/commonMain/src/kotlinx/serialization/protobuf/internal/ProtobufDecoding.kt b/formats/protobuf/commonMain/src/kotlinx/serialization/protobuf/internal/ProtobufDecoding.kt index 48cb24a47..28eae8734 100644 --- a/formats/protobuf/commonMain/src/kotlinx/serialization/protobuf/internal/ProtobufDecoding.kt +++ b/formats/protobuf/commonMain/src/kotlinx/serialization/protobuf/internal/ProtobufDecoding.kt @@ -46,8 +46,8 @@ internal open class ProtobufDecoder( * array for the fast-path. Fast-path implies that elements are not marked with @ProtoId * explicitly or are monotonic and incremental (maybe, 1-indexed) * - * Since the library allows the use of fields with proto ID 0, - * it is necessary to initialize all elements, because there will always be one extra element + * Initialize all elements, because there will always be one extra element as arrays are numbered from 0 + * but in protobuf field number starts from 1. * in the fast path array, which is missing from the descriptor */ val cache = IntArray(elements + 1) { -1 } diff --git a/formats/protobuf/commonTest/src/kotlinx/serialization/protobuf/AutoAssignIdsTest.kt b/formats/protobuf/commonTest/src/kotlinx/serialization/protobuf/AutoAssignIdsTest.kt index 31b3798a1..7b7e11224 100644 --- a/formats/protobuf/commonTest/src/kotlinx/serialization/protobuf/AutoAssignIdsTest.kt +++ b/formats/protobuf/commonTest/src/kotlinx/serialization/protobuf/AutoAssignIdsTest.kt @@ -30,4 +30,15 @@ class AutoAssignIdsTest { assertEquals(w1.a, w2.a) assertEquals(w1.b, w2.b) } + + class NestedClass { + companion object + } + + object X + + @Test + fun testName() { + println(X::class.qualifiedName) + } } diff --git a/formats/protobuf/commonTest/src/kotlinx/serialization/protobuf/InvalidFieldNumberTest.kt b/formats/protobuf/commonTest/src/kotlinx/serialization/protobuf/InvalidFieldNumberTest.kt index 17f5263a9..0ae026082 100644 --- a/formats/protobuf/commonTest/src/kotlinx/serialization/protobuf/InvalidFieldNumberTest.kt +++ b/formats/protobuf/commonTest/src/kotlinx/serialization/protobuf/InvalidFieldNumberTest.kt @@ -42,29 +42,29 @@ class InvalidFieldNumberTest { @Test fun testSerializeZeroProtoNumber() { - assertFailsWithMessage("0 is not allowed in ProtoNumber for kotlinx.serialization.protobuf.InvalidFieldNumberTest.ZeroProtoNumber, because protobuf support field values in range 1..2147483647") { + assertFailsWithMessage("0 is not allowed in ProtoNumber for property 'value' of 'kotlinx.serialization.protobuf.InvalidFieldNumberTest.ZeroProtoNumber', because protobuf support field numbers in range 1..2147483647") { ProtoBuf.encodeToHexString(ZeroProtoNumber(42)) } } @Test fun testDeserializeZeroProtoNumber() { - assertFailsWithMessage("0 is not allowed in ProtoNumber for kotlinx.serialization.protobuf.InvalidFieldNumberTest.ZeroProtoNumber, because protobuf support field values in range 1..2147483647") { + assertFailsWithMessage("0 is not allowed in ProtoNumber for property 'value' of 'kotlinx.serialization.protobuf.InvalidFieldNumberTest.ZeroProtoNumber', because protobuf support field numbers in range 1..2147483647") { ProtoBuf.decodeFromHexString("000f") } } @Test fun testSerializeNegativeProtoNumber() { - assertFailsWithMessage("-5 is not allowed in ProtoNumber for kotlinx.serialization.protobuf.InvalidFieldNumberTest.NegativeProtoNumber, because protobuf support field values in range 1..2147483647") { + assertFailsWithMessage("-5 is not allowed in ProtoNumber for property 'value' of 'kotlinx.serialization.protobuf.InvalidFieldNumberTest.NegativeProtoNumber', because protobuf support field numbers in range 1..2147483647") { ProtoBuf.encodeToHexString(NegativeProtoNumber(42)) } } @Test fun testDeserializeNegativeProtoNumber() { - assertFailsWithMessage("-5 is not allowed in ProtoNumber for kotlinx.serialization.protobuf.InvalidFieldNumberTest.NegativeProtoNumber, because protobuf support field values in range 1..2147483647") { + assertFailsWithMessage("-5 is not allowed in ProtoNumber for property 'value' of 'kotlinx.serialization.protobuf.InvalidFieldNumberTest.NegativeProtoNumber', because protobuf support field numbers in range 1..2147483647") { ProtoBuf.decodeFromHexString("000f") } } -} \ No newline at end of file +} From 27f5ccf6a8c34094843bece9f2ac633a1f08585c Mon Sep 17 00:00:00 2001 From: "Sergey.Shanshin" Date: Fri, 23 Aug 2024 17:44:28 +0200 Subject: [PATCH 5/9] ~fixes --- .../kotlinx/serialization/protobuf/internal/ProtobufReader.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/formats/protobuf/commonMain/src/kotlinx/serialization/protobuf/internal/ProtobufReader.kt b/formats/protobuf/commonMain/src/kotlinx/serialization/protobuf/internal/ProtobufReader.kt index 29177c041..5b8ce1c29 100644 --- a/formats/protobuf/commonMain/src/kotlinx/serialization/protobuf/internal/ProtobufReader.kt +++ b/formats/protobuf/commonMain/src/kotlinx/serialization/protobuf/internal/ProtobufReader.kt @@ -76,7 +76,7 @@ internal class ProtobufReader(private val input: ByteArrayInput) { } fun skipSizeDelimited() { - assertWireType(SIZE_DELIMITED) + assertWireType(ProtoWireType.SIZE_DELIMITED) val length = decode32() checkLength(length) input.skipExactNBytes(length) From d9297f393b470c0398124a1bd4afd9e5e1ecad97 Mon Sep 17 00:00:00 2001 From: "Sergey.Shanshin" Date: Fri, 23 Aug 2024 18:18:22 +0200 Subject: [PATCH 6/9] ~fixes --- .../serialization/protobuf/AutoAssignIdsTest.kt | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/formats/protobuf/commonTest/src/kotlinx/serialization/protobuf/AutoAssignIdsTest.kt b/formats/protobuf/commonTest/src/kotlinx/serialization/protobuf/AutoAssignIdsTest.kt index 7b7e11224..31b3798a1 100644 --- a/formats/protobuf/commonTest/src/kotlinx/serialization/protobuf/AutoAssignIdsTest.kt +++ b/formats/protobuf/commonTest/src/kotlinx/serialization/protobuf/AutoAssignIdsTest.kt @@ -30,15 +30,4 @@ class AutoAssignIdsTest { assertEquals(w1.a, w2.a) assertEquals(w1.b, w2.b) } - - class NestedClass { - companion object - } - - object X - - @Test - fun testName() { - println(X::class.qualifiedName) - } } From 5e6a0682b64eb32c64e7c1ca3c1ce3d8101e6244 Mon Sep 17 00:00:00 2001 From: Sergey Shanshin Date: Fri, 23 Aug 2024 18:20:44 +0200 Subject: [PATCH 7/9] Update formats/protobuf/commonMain/src/kotlinx/serialization/protobuf/internal/Helpers.kt Co-authored-by: Leonid Startsev --- .../src/kotlinx/serialization/protobuf/internal/Helpers.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/formats/protobuf/commonMain/src/kotlinx/serialization/protobuf/internal/Helpers.kt b/formats/protobuf/commonMain/src/kotlinx/serialization/protobuf/internal/Helpers.kt index aa380aa73..ea6d4b682 100644 --- a/formats/protobuf/commonMain/src/kotlinx/serialization/protobuf/internal/Helpers.kt +++ b/formats/protobuf/commonMain/src/kotlinx/serialization/protobuf/internal/Helpers.kt @@ -130,7 +130,7 @@ internal fun extractProtoId(descriptor: SerialDescriptor, index: Int, zeroBasedD private fun checkFieldNumber(fieldNumber: Int, propertyIndex: Int, descriptor: SerialDescriptor) { if (fieldNumber <= 0) { - throw SerializationException("$fieldNumber is not allowed in ProtoNumber for property '${descriptor.getElementName(propertyIndex)}' of '${descriptor.serialName}', because protobuf support field numbers in range 1..${Int.MAX_VALUE}") + throw SerializationException("$fieldNumber is not allowed in ProtoNumber for property '${descriptor.getElementName(propertyIndex)}' of '${descriptor.serialName}', because protobuf supports field numbers in range 1..${Int.MAX_VALUE}") } } From 79b8c12cd66d4a5bf6d7c235069f655f652ad42b Mon Sep 17 00:00:00 2001 From: "Sergey.Shanshin" Date: Fri, 23 Aug 2024 18:25:16 +0200 Subject: [PATCH 8/9] ~review fixes --- .../kotlinx/serialization/protobuf/internal/ProtobufDecoding.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/formats/protobuf/commonMain/src/kotlinx/serialization/protobuf/internal/ProtobufDecoding.kt b/formats/protobuf/commonMain/src/kotlinx/serialization/protobuf/internal/ProtobufDecoding.kt index 28eae8734..56884b12a 100644 --- a/formats/protobuf/commonMain/src/kotlinx/serialization/protobuf/internal/ProtobufDecoding.kt +++ b/formats/protobuf/commonMain/src/kotlinx/serialization/protobuf/internal/ProtobufDecoding.kt @@ -48,7 +48,6 @@ internal open class ProtobufDecoder( * * Initialize all elements, because there will always be one extra element as arrays are numbered from 0 * but in protobuf field number starts from 1. - * in the fast path array, which is missing from the descriptor */ val cache = IntArray(elements + 1) { -1 } for (i in 0 until elements) { From babc823240ddc0b021928b255771f60d753c87aa Mon Sep 17 00:00:00 2001 From: "Sergey.Shanshin" Date: Fri, 23 Aug 2024 18:47:05 +0200 Subject: [PATCH 9/9] ~fixes --- .../serialization/protobuf/InvalidFieldNumberTest.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/formats/protobuf/commonTest/src/kotlinx/serialization/protobuf/InvalidFieldNumberTest.kt b/formats/protobuf/commonTest/src/kotlinx/serialization/protobuf/InvalidFieldNumberTest.kt index 0ae026082..81e01e42d 100644 --- a/formats/protobuf/commonTest/src/kotlinx/serialization/protobuf/InvalidFieldNumberTest.kt +++ b/formats/protobuf/commonTest/src/kotlinx/serialization/protobuf/InvalidFieldNumberTest.kt @@ -42,28 +42,28 @@ class InvalidFieldNumberTest { @Test fun testSerializeZeroProtoNumber() { - assertFailsWithMessage("0 is not allowed in ProtoNumber for property 'value' of 'kotlinx.serialization.protobuf.InvalidFieldNumberTest.ZeroProtoNumber', because protobuf support field numbers in range 1..2147483647") { + assertFailsWithMessage("0 is not allowed in ProtoNumber for property 'value' of 'kotlinx.serialization.protobuf.InvalidFieldNumberTest.ZeroProtoNumber', because protobuf supports field numbers in range 1..2147483647") { ProtoBuf.encodeToHexString(ZeroProtoNumber(42)) } } @Test fun testDeserializeZeroProtoNumber() { - assertFailsWithMessage("0 is not allowed in ProtoNumber for property 'value' of 'kotlinx.serialization.protobuf.InvalidFieldNumberTest.ZeroProtoNumber', because protobuf support field numbers in range 1..2147483647") { + assertFailsWithMessage("0 is not allowed in ProtoNumber for property 'value' of 'kotlinx.serialization.protobuf.InvalidFieldNumberTest.ZeroProtoNumber', because protobuf supports field numbers in range 1..2147483647") { ProtoBuf.decodeFromHexString("000f") } } @Test fun testSerializeNegativeProtoNumber() { - assertFailsWithMessage("-5 is not allowed in ProtoNumber for property 'value' of 'kotlinx.serialization.protobuf.InvalidFieldNumberTest.NegativeProtoNumber', because protobuf support field numbers in range 1..2147483647") { + assertFailsWithMessage("-5 is not allowed in ProtoNumber for property 'value' of 'kotlinx.serialization.protobuf.InvalidFieldNumberTest.NegativeProtoNumber', because protobuf supports field numbers in range 1..2147483647") { ProtoBuf.encodeToHexString(NegativeProtoNumber(42)) } } @Test fun testDeserializeNegativeProtoNumber() { - assertFailsWithMessage("-5 is not allowed in ProtoNumber for property 'value' of 'kotlinx.serialization.protobuf.InvalidFieldNumberTest.NegativeProtoNumber', because protobuf support field numbers in range 1..2147483647") { + assertFailsWithMessage("-5 is not allowed in ProtoNumber for property 'value' of 'kotlinx.serialization.protobuf.InvalidFieldNumberTest.NegativeProtoNumber', because protobuf supports field numbers in range 1..2147483647") { ProtoBuf.decodeFromHexString("000f") } }