Fix LibP2P varint implementation to follow latest specification. (#65)

* Fix LibP2P varint implementation to decode only minimal valus.
This commit is contained in:
Eugene Kabanov 2020-01-28 17:29:42 +02:00 committed by Jacek Sieka
parent d42833947a
commit d902127595
2 changed files with 59 additions and 15 deletions

View File

@ -21,6 +21,7 @@ type
Success,
Overflow,
Incomplete,
Overlong,
Overrun
PB* = object
@ -99,6 +100,13 @@ proc getUVarint*[T: PB|LP](vtype: typedesc[T],
outlen = 0
outval = cast[type(outval)](0)
when vtype is LP:
if result == VarintStatus.Success:
if outlen != vsizeof(outval):
outval = cast[type(outval)](0)
outlen = 0
result = VarintStatus.Overlong
proc putUVarint*[T: PB|LP](vtype: typedesc[T],
pbytes: var openarray[byte],
outlen: var int,
@ -242,18 +250,3 @@ proc encodeVarint*(vtype: typedesc[LP],
result.setLen(outsize)
else:
raise newException(VarintError, "Error '" & $res & "'")
proc decodeSVarint*(data: openarray[byte]): int {.inline.} =
## Decode signed integer from array ``data`` and return it as result.
var outsize = 0
let res = getSVarint(data, outsize, result)
if res != VarintStatus.Success:
raise newException(VarintError, "Error '" & $res & "'")
proc decodeUVarint*[T: PB|LP](vtype: typedesc[T],
data: openarray[byte]): uint {.inline.} =
## Decode unsigned integer from array ``data`` and return it as result.
var outsize = 0
let res = vtype.getUVarint(data, outsize, result)
if res != VarintStatus.Success:
raise newException(VarintError, "Error '" & $res & "'")

View File

@ -216,3 +216,54 @@ suite "Variable integer test suite":
0x8000_0000_0000_0000'u64) == VarintStatus.Overflow
LP.putUVarint(buffer, length,
0xFFFF_FFFF_FFFF_FFFF'u64) == VarintStatus.Overflow
test "[LibP2P] Overlong values test":
const OverlongValues = [
# Zero bytes at the end
@[0x81'u8, 0x00'u8],
@[0x81'u8, 0x80'u8, 0x00'u8],
@[0x81'u8, 0x80'u8, 0x80'u8, 0x00'u8],
@[0x81'u8, 0x80'u8, 0x80'u8, 0x80'u8, 0x00'u8],
@[0x81'u8, 0x80'u8, 0x80'u8, 0x80'u8, 0x80'u8, 0x00'u8],
@[0x81'u8, 0x80'u8, 0x80'u8, 0x80'u8, 0x80'u8, 0x80'u8, 0x00'u8],
@[0x81'u8, 0x80'u8, 0x80'u8, 0x80'u8, 0x80'u8, 0x80'u8, 0x80'u8,
0x00'u8],
@[0x81'u8, 0x80'u8, 0x80'u8, 0x80'u8, 0x80'u8, 0x80'u8, 0x80'u8,
0x80'u8, 0x00'u8],
# Zero bytes at the middle and zero byte at the end
@[0x81'u8, 0x80'u8, 0x81'u8, 0x00'u8],
@[0x81'u8, 0x80'u8, 0x80'u8, 0x81'u8, 0x00'u8],
@[0x81'u8, 0x80'u8, 0x80'u8, 0x80'u8, 0x81'u8, 0x00'u8],
@[0x81'u8, 0x80'u8, 0x80'u8, 0x80'u8, 0x80'u8, 0x81'u8, 0x00'u8],
@[0x81'u8, 0x80'u8, 0x80'u8, 0x80'u8, 0x80'u8, 0x80'u8, 0x81'u8,
0x00'u8],
@[0x81'u8, 0x80'u8, 0x80'u8, 0x80'u8, 0x80'u8, 0x80'u8, 0x80'u8,
0x81'u8, 0x00'u8],
# Zero bytes at the middle and zero bytes at the end
@[0x81'u8, 0x80'u8, 0x80'u8, 0x81'u8, 0x80'u8, 0x00'u8],
@[0x81'u8, 0x80'u8, 0x80'u8, 0x81'u8, 0x80'u8, 0x80'u8, 0x00'u8],
@[0x81'u8, 0x80'u8, 0x80'u8, 0x80'u8, 0x81'u8, 0x80'u8, 0x80'u8,
0x00'u8],
@[0x81'u8, 0x80'u8, 0x80'u8, 0x80'u8, 0x80'u8, 0x81'u8, 0x80'u8,
0x80'u8, 0x00'u8],
]
var length = 0
var value = 0'u64
for item in OverlongValues:
check:
LP.getUVarint(item, length, value) == VarintStatus.Overlong
length == 0
value == 0
# We still should be able to decode zero value
check:
LP.getUVarint(@[0x00'u8], length, value) == VarintStatus.Success
length == 1
value == 0
# But not overlonged zero value
check:
LP.getUVarint(@[0x80'u8, 0x00'u8], length, value) == VarintStatus.Overlong
length == 0
value == 0