Skip to content

Commit

Permalink
Fail on primitive type overflow during JsonElement deserialization
Browse files Browse the repository at this point in the history
Fixes #1300
  • Loading branch information
qwwdfsad committed Jan 20, 2021
1 parent 5eb6fa8 commit b334fb9
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -102,8 +102,18 @@ private sealed class AbstractJsonTreeDecoder(
}
}

override fun decodeTaggedByte(tag: String) = getValue(tag).primitive("byte") { int.toByte() }
override fun decodeTaggedShort(tag: String) = getValue(tag).primitive("short") { int.toShort() }
override fun decodeTaggedByte(tag: String) = getValue(tag).primitive("byte") {
val result = int
if (result in Byte.MIN_VALUE..Byte.MAX_VALUE) result.toByte()
else null
}

override fun decodeTaggedShort(tag: String) = getValue(tag).primitive("short") {
val result = int
if (result in Short.MIN_VALUE..Short.MAX_VALUE) result.toShort()
else null
}

override fun decodeTaggedInt(tag: String) = getValue(tag).primitive("int") { int }
override fun decodeTaggedLong(tag: String) = getValue(tag).primitive("long") { long }

Expand All @@ -123,14 +133,18 @@ private sealed class AbstractJsonTreeDecoder(

override fun decodeTaggedChar(tag: String): Char = getValue(tag).primitive("char") { content.single() }

private inline fun <T: Any> JsonPrimitive.primitive(primitive: String, block: JsonPrimitive.() -> T): T {
private inline fun <T: Any> JsonPrimitive.primitive(primitive: String, block: JsonPrimitive.() -> T?): T {
try {
return block()
return block() ?: unparsedPrimitive(primitive)
} catch (e: IllegalArgumentException) {
throw JsonDecodingException(-1, "Failed to parse '$primitive'", currentObject().toString())
unparsedPrimitive(primitive)
}
}

private fun unparsedPrimitive(primitive: String): Nothing {
throw JsonDecodingException(-1, "Failed to parse '$primitive'", currentObject().toString())
}

override fun decodeTaggedString(tag: String): String {
val value = getValue(tag)
if (!json.configuration.isLenient) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,14 @@ class JsonParserFailureModesTest : JsonTestBase() {
it
)
}
// 9223372036854775807 is Long.MAX_VALUE
assertFailsWith<JsonDecodingException> {
default.decodeFromString(
Holder.serializer(),
"""{"id":922337203685477580700}""",
it
)
}
assertFailsWith<JsonDecodingException> { default.decodeFromString(Holder.serializer(), """{"id"}""", it) }
assertFailsWith<JsonDecodingException> { default.decodeFromString(Holder.serializer(), """{"id}""", it) }
assertFailsWith<JsonDecodingException> { default.decodeFromString(Holder.serializer(), """{"i}""", it) }
Expand All @@ -70,7 +78,49 @@ class JsonParserFailureModesTest : JsonTestBase() {

@Test
fun testBoolean() = parametrizedTest {
assertFailsWith<JsonDecodingException> { default.decodeFromString(BooleanHolder.serializer(), """{"b": fals}""", it) }
assertFailsWith<JsonDecodingException> { default.decodeFromString(BooleanHolder.serializer(), """{"b": 123}""", it) }
assertFailsWith<JsonDecodingException> {
default.decodeFromString(
BooleanHolder.serializer(),
"""{"b": fals}""",
it
)
}
assertFailsWith<JsonDecodingException> {
default.decodeFromString(
BooleanHolder.serializer(),
"""{"b": 123}""",
it
)
}
}

@Serializable
class PrimitiveHolder(
val b: Byte = 0, val s: Short = 0, val i: Int = 0
)

@Test
fun testOverflow() = parametrizedTest {
// Byte overflow
assertFailsWith<JsonDecodingException> { default.decodeFromString<PrimitiveHolder>("""{"b": 128}""", it) }
// Short overflow
assertFailsWith<JsonDecodingException> { default.decodeFromString<PrimitiveHolder>("""{"s": 32768}""", it) }
// Int overflow
assertFailsWith<JsonDecodingException> {
default.decodeFromString<PrimitiveHolder>(
"""{"i": 2147483648}""",
it
)
}
}

@Test
fun testNoOverflow() = parametrizedTest {
default.decodeFromString<PrimitiveHolder>("""{"b": ${Byte.MAX_VALUE}}""", it)
default.decodeFromString<PrimitiveHolder>("""{"b": ${Byte.MIN_VALUE}}""", it)
default.decodeFromString<PrimitiveHolder>("""{"s": ${Short.MAX_VALUE}}""", it)
default.decodeFromString<PrimitiveHolder>("""{"s": ${Short.MIN_VALUE}}""", it)
default.decodeFromString<PrimitiveHolder>("""{"i": ${Int.MAX_VALUE}}""", it)
default.decodeFromString<PrimitiveHolder>("""{"i": ${Int.MIN_VALUE}}""", it)
}
}

0 comments on commit b334fb9

Please sign in to comment.