Skip to content

Commit 14a5936

Browse files
committed
Fix int32 and int64 array length decoders
1 parent 7befa1f commit 14a5936

File tree

5 files changed

+261
-28
lines changed

5 files changed

+261
-28
lines changed

proxy/protocol/encoder_decoder_test.go

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,154 @@ func TestEncodeDecodeCompactNullableArray(t *testing.T) {
292292
}
293293
}
294294

295+
func TestEncodeDecodeInt32Array(t *testing.T) {
296+
tt := []struct {
297+
name string
298+
values []int32
299+
}{
300+
{name: "nil array", values: nil},
301+
{name: "empty array", values: []int32{}},
302+
{name: "0", values: []int32{0}},
303+
{name: "0s", values: []int32{0, 0}},
304+
{name: "1", values: []int32{1}},
305+
{name: "1s", values: []int32{1, 1}},
306+
{name: "2", values: []int32{2}},
307+
{name: "3", values: []int32{3}},
308+
{name: "4", values: []int32{4}},
309+
{name: "16", values: []int32{16}},
310+
{name: "63", values: []int32{63}},
311+
{name: "64", values: []int32{64}},
312+
{name: "128", values: []int32{128}},
313+
{name: "8191", values: []int32{8191}},
314+
{name: "8192", values: []int32{8192}},
315+
{name: "32767", values: []int32{math.MaxInt16}},
316+
{name: "32767,-32768", values: []int32{math.MaxInt16, math.MinInt16}},
317+
{name: "2147483647,-2147483648", values: []int32{math.MaxInt32, math.MinInt32}},
318+
{name: "different values", values: []int32{0, 1, 2, 3, 4, -1, 16, 64, 127, 128, 8191, 8192, 8191, 128, 127, -1, 64, 16, 4, 3, 2, 1, -1, 0}},
319+
}
320+
for _, tc := range tt {
321+
request := &Int32ArrayHolder{
322+
values: tc.values,
323+
}
324+
buf, err := Encode(request)
325+
if err != nil {
326+
t.Fatal(err)
327+
}
328+
response := &Int32ArrayHolder{}
329+
err = Decode(buf, response)
330+
if err != nil {
331+
t.Fatal(err)
332+
}
333+
if (request.values == nil && response.values != nil) || (request.values != nil && response.values == nil) {
334+
t.Fatalf("Nils comparison error: expected %v, actual %v", request.values == nil, response.values == nil)
335+
}
336+
if len(request.values) != len(response.values) {
337+
t.Fatalf("Values array lengths differ: expected %v, actual %v", request.values, response.values)
338+
}
339+
for i := range request.values {
340+
if request.values[i] != response.values[i] {
341+
t.Fatalf("Values differ: index %d, expected %v, actual %v", i, request.values[i], response.values[i])
342+
}
343+
}
344+
}
345+
}
346+
347+
func TestEncodeDecodeInt64Array(t *testing.T) {
348+
tt := []struct {
349+
name string
350+
values []int64
351+
}{
352+
{name: "nil array", values: nil},
353+
{name: "empty array", values: []int64{}},
354+
{name: "0", values: []int64{0}},
355+
{name: "0s", values: []int64{0, 0}},
356+
{name: "1", values: []int64{1}},
357+
{name: "1s", values: []int64{1, 1}},
358+
{name: "2", values: []int64{2}},
359+
{name: "3", values: []int64{3}},
360+
{name: "4", values: []int64{4}},
361+
{name: "16", values: []int64{16}},
362+
{name: "63", values: []int64{63}},
363+
{name: "64", values: []int64{64}},
364+
{name: "128", values: []int64{128}},
365+
{name: "8191", values: []int64{8191}},
366+
{name: "8192", values: []int64{8192}},
367+
{name: "32767", values: []int64{math.MaxInt16}},
368+
{name: "32767,-32768", values: []int64{math.MaxInt16, math.MinInt16}},
369+
{name: "2147483647", values: []int64{math.MaxInt32}},
370+
{name: "2147483647,-2147483648", values: []int64{math.MaxInt32, math.MinInt32}},
371+
{name: "max,min", values: []int64{math.MaxInt64, math.MinInt64}},
372+
{name: "different values", values: []int64{0, 1, 2, 3, 4, -1, 16, 64, 127, 128, 8191, 8192, 8191, 128, 127, -1, 64, 16, 4, 3, 2, 1, -1, 0}},
373+
}
374+
for _, tc := range tt {
375+
request := &Int64ArrayHolder{
376+
values: tc.values,
377+
}
378+
buf, err := Encode(request)
379+
if err != nil {
380+
t.Fatal(err)
381+
}
382+
response := &Int64ArrayHolder{}
383+
err = Decode(buf, response)
384+
if err != nil {
385+
t.Fatal(err)
386+
}
387+
if (request.values == nil && response.values != nil) || (request.values != nil && response.values == nil) {
388+
t.Fatalf("%s: Nils comparison error: expected %v, actual %v", tc.name, request.values == nil, response.values == nil)
389+
}
390+
if len(request.values) != len(response.values) {
391+
t.Fatalf("Values array lengths differ: expected %v, actual %v", request.values, response.values)
392+
}
393+
for i := range request.values {
394+
if request.values[i] != response.values[i] {
395+
t.Fatalf("Values differ: index %d, expected %v, actual %v", i, request.values[i], response.values[i])
396+
}
397+
}
398+
}
399+
}
400+
401+
type Int32ArrayHolder struct {
402+
values []int32
403+
}
404+
405+
func (r *Int32ArrayHolder) encode(pe packetEncoder) (err error) {
406+
err = pe.putInt32Array(r.values)
407+
if err != nil {
408+
return err
409+
}
410+
return
411+
}
412+
func (r *Int32ArrayHolder) decode(pd packetDecoder) (err error) {
413+
if r.values, err = pd.getInt32Array(); err != nil {
414+
return err
415+
}
416+
if pd.remaining() != 0 {
417+
return errors.Errorf("remaining bytes %d", pd.remaining())
418+
}
419+
return
420+
}
421+
422+
type Int64ArrayHolder struct {
423+
values []int64
424+
}
425+
426+
func (r *Int64ArrayHolder) encode(pe packetEncoder) (err error) {
427+
err = pe.putInt64Array(r.values)
428+
if err != nil {
429+
return err
430+
}
431+
return
432+
}
433+
func (r *Int64ArrayHolder) decode(pd packetDecoder) (err error) {
434+
if r.values, err = pd.getInt64Array(); err != nil {
435+
return err
436+
}
437+
if pd.remaining() != 0 {
438+
return errors.Errorf("remaining bytes %d", pd.remaining())
439+
}
440+
return
441+
}
442+
295443
type CompactBytesHolder struct {
296444
values [][]byte
297445
}

proxy/protocol/prep_encoder.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,9 @@ func (pe *prepEncoder) putStringArray(in []string) error {
113113
}
114114

115115
func (pe *prepEncoder) putInt32Array(in []int32) error {
116+
if in == nil {
117+
return pe.putArrayLength(-1)
118+
}
116119
err := pe.putArrayLength(len(in))
117120
if err != nil {
118121
return err
@@ -122,6 +125,9 @@ func (pe *prepEncoder) putInt32Array(in []int32) error {
122125
}
123126

124127
func (pe *prepEncoder) putInt64Array(in []int64) error {
128+
if in == nil {
129+
return pe.putArrayLength(-1)
130+
}
125131
err := pe.putArrayLength(len(in))
126132
if err != nil {
127133
return err

proxy/protocol/real_decoder.go

Lines changed: 28 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -192,26 +192,24 @@ func (rd *realDecoder) getNullableString() (*string, error) {
192192
}
193193

194194
func (rd *realDecoder) getInt32Array() ([]int32, error) {
195-
if rd.remaining() < 4 {
196-
rd.off = len(rd.raw)
197-
return nil, ErrInsufficientData
198-
}
199-
n := int(binary.BigEndian.Uint32(rd.raw[rd.off:]))
200-
rd.off += 4
195+
n, err := rd.getArrayLength()
201196

202-
if rd.remaining() < 4*n {
203-
rd.off = len(rd.raw)
204-
return nil, ErrInsufficientData
197+
if err != nil {
198+
return nil, err
205199
}
206-
207-
if n == 0 {
200+
if n == -1 {
208201
return nil, nil
209202
}
210-
211-
if n < 0 {
203+
if n == 0 {
204+
return []int32{}, nil
205+
}
206+
if n < -1 {
212207
return nil, errInvalidArrayLength
213208
}
214-
209+
if rd.remaining() < 4*n {
210+
rd.off = len(rd.raw)
211+
return nil, ErrInsufficientData
212+
}
215213
ret := make([]int32, n)
216214
for i := range ret {
217215
ret[i] = int32(binary.BigEndian.Uint32(rd.raw[rd.off:]))
@@ -221,26 +219,24 @@ func (rd *realDecoder) getInt32Array() ([]int32, error) {
221219
}
222220

223221
func (rd *realDecoder) getInt64Array() ([]int64, error) {
224-
if rd.remaining() < 4 {
225-
rd.off = len(rd.raw)
226-
return nil, ErrInsufficientData
227-
}
228-
n := int(binary.BigEndian.Uint32(rd.raw[rd.off:]))
229-
rd.off += 4
222+
n, err := rd.getArrayLength()
230223

231-
if rd.remaining() < 8*n {
232-
rd.off = len(rd.raw)
233-
return nil, ErrInsufficientData
224+
if err != nil {
225+
return nil, err
234226
}
235-
236-
if n == 0 {
227+
if n == -1 {
237228
return nil, nil
238229
}
239-
240-
if n < 0 {
230+
if n == 0 {
231+
return []int64{}, nil
232+
}
233+
if n < -1 {
241234
return nil, errInvalidArrayLength
242235
}
243-
236+
if rd.remaining() < 8*n {
237+
rd.off = len(rd.raw)
238+
return nil, ErrInsufficientData
239+
}
244240
ret := make([]int64, n)
245241
for i := range ret {
246242
ret[i] = int64(binary.BigEndian.Uint64(rd.raw[rd.off:]))
@@ -260,6 +256,10 @@ func (rd *realDecoder) getStringArray() ([]string, error) {
260256
return nil, nil
261257
}
262258

259+
if n < -1 {
260+
return nil, errInvalidArrayLength
261+
}
262+
263263
ret := make([]string, n)
264264
for i := range ret {
265265
str, err := rd.getString()
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
package protocol
2+
3+
import (
4+
"encoding/hex"
5+
"github.com/stretchr/testify/assert"
6+
"strings"
7+
"testing"
8+
)
9+
10+
func TestGetInt32Array(t *testing.T) {
11+
tt := []struct {
12+
name string
13+
raw string
14+
values []int32
15+
err error
16+
}{
17+
{name: "nil array", raw: "FFFFFFFF", values: nil},
18+
{name: "invalid array length", raw: "FFFFFFFE", err: errInvalidArrayLength},
19+
{name: "insufficient data", raw: "00000001", err: ErrInsufficientData},
20+
{name: "empty array", raw: "00000000", values: []int32{}},
21+
{name: "1 element", raw: "00000001 00000002", values: []int32{2}},
22+
{name: "many elements", raw: "00000003 00001267 FFFFFFFF 7FFFFFFF", values: []int32{4711, -1, 2147483647}},
23+
}
24+
for _, tc := range tt {
25+
a := assert.New(t)
26+
rd := realDecoder{
27+
raw: mustHexDecodeString(tc.raw),
28+
}
29+
values, err := rd.getInt32Array()
30+
if err != nil || tc.err != nil {
31+
a.Equal(tc.err, err)
32+
} else {
33+
a.Equal(tc.values, values)
34+
}
35+
}
36+
}
37+
38+
func TestGetInt64Array(t *testing.T) {
39+
tt := []struct {
40+
name string
41+
raw string
42+
values []int64
43+
err error
44+
}{
45+
{name: "nil array", raw: "FFFFFFFF", values: nil},
46+
{name: "invalid array length", raw: "FFFFFFFE", err: errInvalidArrayLength},
47+
{name: "insufficient data", raw: "00000001", err: ErrInsufficientData},
48+
{name: "empty array", raw: "00000000", values: []int64{}},
49+
{name: "1 element", raw: "00000001 0000000000000002", values: []int64{2}},
50+
{name: "many elements", raw: "00000002 FFFFFFFFFFFFFFFF 7FFFFFFFFFFFFFFF", values: []int64{-1, 9223372036854775807}},
51+
}
52+
for _, tc := range tt {
53+
a := assert.New(t)
54+
rd := realDecoder{
55+
raw: mustHexDecodeString(tc.raw),
56+
}
57+
values, err := rd.getInt64Array()
58+
if err != nil || tc.err != nil {
59+
a.Equal(tc.err, err)
60+
} else {
61+
a.Equal(tc.values, values)
62+
}
63+
}
64+
}
65+
66+
func mustHexDecodeString(s string) []byte {
67+
s = strings.ReplaceAll(s, " ", "")
68+
raw, err := hex.DecodeString(s)
69+
if err != nil {
70+
panic(err)
71+
}
72+
return raw
73+
}

proxy/protocol/real_encoder.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,9 @@ func (re *realEncoder) putStringArray(in []string) error {
112112
}
113113

114114
func (re *realEncoder) putInt32Array(in []int32) error {
115+
if in == nil {
116+
return re.putArrayLength(-1)
117+
}
115118
err := re.putArrayLength(len(in))
116119
if err != nil {
117120
return err
@@ -123,6 +126,9 @@ func (re *realEncoder) putInt32Array(in []int32) error {
123126
}
124127

125128
func (re *realEncoder) putInt64Array(in []int64) error {
129+
if in == nil {
130+
return re.putArrayLength(-1)
131+
}
126132
err := re.putArrayLength(len(in))
127133
if err != nil {
128134
return err

0 commit comments

Comments
 (0)