Skip to content

Commit a3ded45

Browse files
authored
fix minor interoperability issues. (#6)
1 parent 9946570 commit a3ded45

File tree

1 file changed

+31
-9
lines changed

1 file changed

+31
-9
lines changed

varint.go

+31-9
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,25 @@ import (
88
)
99

1010
var (
11-
ErrOverflow = errors.New("varints larger than uint64 not yet supported")
11+
ErrOverflow = errors.New("varints larger than uint63 not supported")
1212
ErrUnderflow = errors.New("varints malformed, could not reach the end")
1313
ErrNotMinimal = errors.New("varint not minimally encoded")
1414
)
1515

16+
const (
17+
// MaxLenUvarint63 is the maximum number of bytes representing an uvarint in
18+
// this encoding, supporting a maximum value of 2^63 (uint63), aka
19+
// MaxValueUvarint63.
20+
MaxLenUvarint63 = 9
21+
22+
// MaxValueUvarint63 is the maximum encodable uint63 value.
23+
MaxValueUvarint63 = (1 << 63) - 1
24+
)
25+
1626
// UvarintSize returns the size (in bytes) of `num` encoded as a unsigned varint.
27+
//
28+
// This may return a size greater than MaxUvarintLen63, which would be an
29+
// illegal value, and would be rejected by readers.
1730
func UvarintSize(num uint64) int {
1831
bits := bits.Len64(num)
1932
q, r := bits/7, bits%7
@@ -39,10 +52,14 @@ func FromUvarint(buf []byte) (uint64, int, error) {
3952
var x uint64
4053
var s uint
4154
for i, b := range buf {
55+
if (i == 8 && b >= 0x80) || i >= MaxLenUvarint63 {
56+
// this is the 9th and last byte we're willing to read, but it
57+
// signals there's more (1 in MSB).
58+
// or this is the >= 10th byte, and for some reason we're still here.
59+
return 0, 0, ErrOverflow
60+
}
4261
if b < 0x80 {
43-
if i > 9 || i == 9 && b > 1 {
44-
return 0, 0, ErrOverflow
45-
} else if b == 0 && s > 0 {
62+
if b == 0 && s > 0 {
4663
return 0, 0, ErrNotMinimal
4764
}
4865
return x | uint64(b)<<s, i + 1, nil
@@ -70,12 +87,14 @@ func ReadUvarint(r io.ByteReader) (uint64, error) {
7087
}
7188
return 0, err
7289
}
90+
if (i == 8 && b >= 0x80) || i >= MaxLenUvarint63 {
91+
// this is the 9th and last byte we're willing to read, but it
92+
// signals there's more (1 in MSB).
93+
// or this is the >= 10th byte, and for some reason we're still here.
94+
return 0, ErrOverflow
95+
}
7396
if b < 0x80 {
74-
if i > 9 || i == 9 && b > 1 {
75-
return 0, ErrOverflow
76-
} else if b == 0 && s > 0 {
77-
// we should never _finish_ on a 0 byte if we
78-
// have more than one byte.
97+
if b == 0 && s > 0 {
7998
return 0, ErrNotMinimal
8099
}
81100
return x | uint64(b)<<s, nil
@@ -89,6 +108,9 @@ func ReadUvarint(r io.ByteReader) (uint64, error) {
89108
//
90109
// This is provided for convenience so users of this library can avoid built-in
91110
// varint functions and easily audit code for uses of those functions.
111+
//
112+
// Make sure that x is smaller or equal to MaxValueUvarint63, otherwise this
113+
// function will produce values that may be rejected by readers.
92114
func PutUvarint(buf []byte, x uint64) int {
93115
return binary.PutUvarint(buf, x)
94116
}

0 commit comments

Comments
 (0)