-
Notifications
You must be signed in to change notification settings - Fork 671
Description
Describe the bug
Direct byte encoding/decoding of Kotlin unsigned primitives is currently two’s-complement via signed primitive, which round-trips within the library, but doesn’t match the CBOR representation. CBOR has native signed and native unsigned Integer types and those should be used
Context:
While working on structured CBOR and pondering extensions/shorthands for numbers other than Long I noticed that unsigned primitives must not take the detour through signed types, because CBOR represents signed and unsigned types with a different header/mask. This is perfectly fine for the newly introducedCborInteger, because it stores a numbers signum and magnitude separately.
Problem:
When rebasing onto dev I noticed range checks got introduced to the CBOR decoder and it clicked:
Kotlin’s built-in serializers for UByte/UShort/UInt/ULong are inline wrappers over the signed primitives (Byte/Short/Int/Long) and literally call encodeByte(value.toByte()), decodeByte().toUByte(), etc. (core/commonMain/src/kotlinx/serialization/internal/ValueClasses.kt).
- CBOR’s “unsigned integer” is major type 0 (0..2⁶⁴-1). So for example UByte(200) “should” be encoded as CBOR unsigned integer 200.
- With the range checks (pulled from dev) in CborReader.decodeByte/decodeShort/decodeInt, decoding a CBOR unsigned integer 200 into a Byte now throws (since 200 is not within [-128..127]). That means UByte decoding via the standard serializer also fails for values > 127 even though an unsigned CBOR Int up to 255 would be within range.
- Encoding is also flawed: UByte(200).toByte() is -56, so the default encodeByte path emits a CBOR negative integer, not an unsigned 200.
To Reproduce
See Testcase that always fails.
Expected behavior
Unsigned Kotlin number types should always be encoded as Major Type 0
Environment
- Kotlin version: any
- Library version: any
- Kotlin platforms: all
- Gradle version: any
- Other relevant context: Was always there and the range checks made it even worse, which helped discover the issue