borer-core Reader.longCompare computes the comparison via math.signum(long - value).toInt. When long and value straddle the Long range (e.g. Long.MaxValue vs Long.MinValue), the subtraction overflows and the sign is inverted.
Reproducer (scala-cli):
//> using scala 3.8.3
//> using dep io.bullet::borer-core:1.16.1
import io.bullet.borer.*
@main def repro070(): Unit =
val encoded = Cbor.encode(Long.MaxValue).toByteArray
val reader = Cbor.reader(encoded)
reader.dataItem()
val cmp = reader.longCompare(Long.MinValue)
println(s"longCompare(Long.MinValue) when holding Long.MaxValue = $cmp")
Output (borer 1.16.1, Scala 3.8.3):
longCompare(Long.MinValue) when holding Long.MaxValue = -1
i.e. the reader claims Long.MaxValue < Long.MinValue. Reversing the test (reader holds Long.MinValue, compare against Long.MaxValue) returns +1, claiming the opposite.
Source
|
def longCompare(value: Long): Int = |
|
if (hasLong) |
|
val long = if (hasInt) receptacle.intValue.toLong else receptacle.longValue |
|
math.signum(long - value).toInt |
|
else Int.MaxValue |
def longCompare(value: Long): Int =
if (hasLong)
val long = if (hasInt) receptacle.intValue.toLong else receptacle.longValue
math.signum(long - value).toInt
else Int.MaxValue
Long.MaxValue - Long.MinValue overflows to -1, and math.signum(-1) = -1. The same shape would affect tryReadLongCompare.
Suggested fix
Use java.lang.Long.compare(long, value) — it doesn't compute the difference and handles the full Long range:
def longCompare(value: Long): Int =
if (hasLong)
val long = if (hasInt) receptacle.intValue.toLong else receptacle.longValue
java.lang.Long.compare(long, value)
else Int.MaxValue
The existing tests don't cover extreme Long comparisons, which is presumably how this slipped through. Happy to PR with a regression test.
Versions
borer-core 1.16.1 / 1.16.2, Scala 3.8.3.
borer-coreReader.longComparecomputes the comparison viamath.signum(long - value).toInt. Whenlongandvaluestraddle the Long range (e.g.Long.MaxValuevsLong.MinValue), the subtraction overflows and the sign is inverted.Reproducer (scala-cli):
Output (borer 1.16.1, Scala 3.8.3):
i.e. the reader claims
Long.MaxValue < Long.MinValue. Reversing the test (reader holdsLong.MinValue, compare againstLong.MaxValue) returns+1, claiming the opposite.Source
borer/core/src/main/scala/io/bullet/borer/Reader.scala
Lines 161 to 165 in 91f21d8
Long.MaxValue - Long.MinValueoverflows to -1, andmath.signum(-1) = -1. The same shape would affecttryReadLongCompare.Suggested fix
Use
java.lang.Long.compare(long, value)— it doesn't compute the difference and handles the full Long range:The existing tests don't cover extreme Long comparisons, which is presumably how this slipped through. Happy to PR with a regression test.
Versions
borer-core 1.16.1 / 1.16.2, Scala 3.8.3.