Skip to content
This repository was archived by the owner on May 11, 2020. It is now read-only.

Commit 171acf9

Browse files
laizytwitchyliquid64
authored andcommitted
leb128:add ReadVarUint64 function and fix overflow corner case (#176)
1 parent b7c7ff9 commit 171acf9

File tree

2 files changed

+30
-4
lines changed

2 files changed

+30
-4
lines changed

wasm/leb128/read.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ func readVarUint(r io.Reader, n uint) (uint64, error) {
2727
}
2828
b := uint64(p[0])
2929
switch {
30-
case b < 1<<7 && b < 1<<n:
30+
// note: can not use b < 1<<n, when n == 64, 1<<n will overflow to 0
31+
case b < 1<<7 && b <= 1<<n-1:
3132
res += (1 << shift) * b
3233
return res, nil
3334
case b >= 1<<7 && n > 7:
@@ -98,3 +99,9 @@ func ReadVarint32(r io.Reader) (int32, error) {
9899
func ReadVarint64(r io.Reader) (int64, error) {
99100
return readVarint(r, 64)
100101
}
102+
103+
// ReadVarUint64 reads a LEB128 encoded unsigned 64-bit integer from r, and
104+
// returns the integer value, and the error (if any).
105+
func ReadVarUint64(r io.Reader) (uint64, error) {
106+
return readVarUint(r, 64)
107+
}

wasm/leb128/read_test.go

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,20 @@ func TestReadVarUint32(t *testing.T) {
3636
}
3737
}
3838

39+
func TestReadVarUint64(t *testing.T) {
40+
for _, c := range casesUint {
41+
t.Run(fmt.Sprint(c.v), func(t *testing.T) {
42+
n, err := ReadVarUint64(bytes.NewReader(c.b))
43+
if err != nil {
44+
t.Fatal(err)
45+
}
46+
if n != uint64(c.v) {
47+
t.Fatalf("got = %d; want = %d", n, c.v)
48+
}
49+
})
50+
}
51+
}
52+
3953
func TestReadVarUint32Err(t *testing.T) {
4054
_, err := ReadVarUint32(bytes.NewReader(nil))
4155
if got, want := err, io.EOF; got != want {
@@ -192,6 +206,8 @@ func TestCompareReadVarUint(t *testing.T) {
192206
}
193207
}
194208

209+
// a less efficent recursive version but matches the spec defined in https://webassembly.github.io/spec/core/binary/values.html#integers
210+
// to make sure the correctness of readVarUint
195211
func readVarUintRecur(r io.Reader, n uint) (uint64, error) {
196212
if n > 64 {
197213
panic(errors.New("leb128: n must <= 64"))
@@ -203,10 +219,11 @@ func readVarUintRecur(r io.Reader, n uint) (uint64, error) {
203219
}
204220
b := uint64(p[0])
205221
switch {
206-
case b < 1<<7 && b < 1<<n:
222+
// note: can not use b < 1<<n, when n == 64, 1<<n will overflow to 0
223+
case b < 1<<7 && b <= 1<<n-1:
207224
return b, nil
208225
case b >= 1<<7 && n > 7:
209-
m, err := readVarUint(r, n-7)
226+
m, err := readVarUintRecur(r, n-7)
210227
if err != nil {
211228
return 0, err
212229
}
@@ -217,6 +234,8 @@ func readVarUintRecur(r io.Reader, n uint) (uint64, error) {
217234
}
218235
}
219236

237+
// a less efficent recursive version but matches the spec defined in https://webassembly.github.io/spec/core/binary/values.html#integers
238+
// to make sure the correctness of readVarint
220239
func readVarintRecur(r io.Reader, n uint) (int64, error) {
221240
if n > 64 {
222241
panic(errors.New("leb128: n must <= 64"))
@@ -233,7 +252,7 @@ func readVarintRecur(r io.Reader, n uint) (int64, error) {
233252
case b >= 1<<6 && b < 1<<7 && uint64(b)+1<<(n-1) >= 1<<7:
234253
return b - 1<<7, nil
235254
case b >= 1<<7 && n > 7:
236-
m, err := readVarint(r, n-7)
255+
m, err := readVarintRecur(r, n-7)
237256
if err != nil {
238257
return 0, err
239258
}

0 commit comments

Comments
 (0)