Skip to content

Commit 7a0f671

Browse files
Throw SerializationException instead of IllegalStateException in Enum… (#1325)
* Throw SerializationException instead of IllegalStateException in EnumSerializer * Fix (almost) infinite loop in readVarintSlowPath on JS Because of shift+=7 addition and strict condition shift != 64, the loop never ends. This resulted in test timeout fail on JS. On JVM and Native, due to shift overflow, the test eventually came out of the loop (but that took quite a big amount of time, about million overflows). Fixes #1303 Co-authored-by: Leonid Startsev <sandwwraith@gmail.com>
1 parent 358dc0b commit 7a0f671

File tree

4 files changed

+53
-34
lines changed

4 files changed

+53
-34
lines changed

core/commonMain/src/kotlinx/serialization/internal/Enums.kt

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -67,16 +67,22 @@ internal class EnumSerializer<T : Enum<T>>(
6767

6868
override fun serialize(encoder: Encoder, value: T) {
6969
val index = values.indexOf(value)
70-
check(index != -1) {
71-
"$value is not a valid enum ${descriptor.serialName}, must be one of ${values.contentToString()}"
70+
if (index == -1) {
71+
throw SerializationException(
72+
"$value is not a valid enum ${descriptor.serialName}, " +
73+
"must be one of ${values.contentToString()}"
74+
)
7275
}
7376
encoder.encodeEnum(descriptor, index)
7477
}
7578

7679
override fun deserialize(decoder: Decoder): T {
7780
val index = decoder.decodeEnum(descriptor)
78-
check(index in values.indices) {
79-
"$index is not among valid $${descriptor.serialName} enum values, values size is ${values.size}"
81+
if (index !in values.indices) {
82+
throw SerializationException(
83+
"$index is not among valid ${descriptor.serialName} enum values, " +
84+
"values size is ${values.size}"
85+
)
8086
}
8187
return values[index]
8288
}

formats/protobuf/commonMain/src/kotlinx/serialization/protobuf/internal/Streams.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -97,29 +97,29 @@ internal class ByteArrayInput(private var array: ByteArray, private val endIndex
9797
private fun readVarint64SlowPath(): Long {
9898
var result = 0L
9999
var shift = 0
100-
while (shift != 64) {
100+
while (shift < 64) {
101101
val byte = read()
102102
result = result or ((byte and 0x7F).toLong() shl shift)
103103
if (byte and 0x80 == 0) {
104104
return result
105105
}
106106
shift += 7
107107
}
108-
throw SerializationException("Varint too long: exceeded 64 bits")
108+
throw SerializationException("Input stream is malformed: Varint too long (exceeded 64 bits)")
109109
}
110110

111111
private fun readVarint32SlowPath(): Int {
112112
var result = 0
113113
var shift = 0
114-
while (shift != 32) {
114+
while (shift < 32) {
115115
val byte = read()
116116
result = result or ((byte and 0x7F) shl shift)
117117
if (byte and 0x80 == 0) {
118118
return result
119119
}
120120
shift += 7
121121
}
122-
throw SerializationException("Varint too long: exceeded 32 bits")
122+
throw SerializationException("Input stream is malformed: Varint too long (exceeded 32 bits)")
123123
}
124124
}
125125

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/*
2+
* Copyright 2017-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
3+
*/
4+
5+
package kotlinx.serialization.protobuf
6+
7+
import kotlinx.serialization.*
8+
import kotlin.test.*
9+
10+
class ProtobufEnumTest {
11+
12+
enum class SomeEnum { ALPHA, BETA, GAMMA }
13+
14+
@Serializable
15+
data class EnumWithUnion(@ProtoNumber(5) val s: String,
16+
@ProtoNumber(6) val e: SomeEnum = SomeEnum.ALPHA,
17+
@ProtoNumber(7) val i: Int = 42)
18+
19+
@Test
20+
fun testEnumWithUnion() {
21+
val data = EnumWithUnion("foo", SomeEnum.BETA)
22+
val hex = ProtoBuf.encodeToHexString(EnumWithUnion.serializer(), data)
23+
val restored = ProtoBuf.decodeFromHexString(EnumWithUnion.serializer(), hex)
24+
assertEquals(data, restored)
25+
}
26+
27+
@Serializable
28+
class EnumHolder(val e: SomeEnum)
29+
30+
@Test
31+
fun testUnknownValue() {
32+
val bytes = ProtoBuf.encodeToByteArray(EnumHolder(SomeEnum.ALPHA))
33+
bytes[1] = 3
34+
assertFailsWith<SerializationException> { ProtoBuf.decodeFromByteArray<EnumHolder>(bytes) }
35+
bytes[1] = -1
36+
assertFailsWith<SerializationException> { ProtoBuf.decodeFromByteArray<EnumHolder>(bytes) }
37+
38+
}
39+
}

formats/protobuf/commonTest/src/kotlinx/serialization/protobuf/ProtobufUnionEnumTest.kt

Lines changed: 0 additions & 26 deletions
This file was deleted.

0 commit comments

Comments
 (0)