Skip to content

Commit

Permalink
Fix RingBuffer panic due to out of bounds index (#282)
Browse files Browse the repository at this point in the history
  • Loading branch information
skmcgrail authored Apr 7, 2021
1 parent 87b7445 commit 481242f
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 13 deletions.
15 changes: 10 additions & 5 deletions io/ringbuffer.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ func (r *RingBuffer) Write(p []byte) (int, error) {
r.end++
r.size++
}
return r.size, nil
return len(p), nil
}

// Read copies the data on the ring buffer into the byte slice provided to the method.
Expand All @@ -60,20 +60,25 @@ func (r *RingBuffer) Read(p []byte) (int, error) {
return readCount, io.EOF
}

if r.start == len(r.slice) {
r.start = 0
}

p[j] = r.slice[r.start]
readCount++
// increment the start pointer for ring buffer
r.start++
// decrement the size of ring buffer
r.size--

if r.start == len(r.slice) {
r.start = 0
}
}
return readCount, nil
}

// Len returns the number of unread bytes in the buffer.
func (r *RingBuffer) Len() int {
return r.size
}

// Bytes returns a copy of the RingBuffer's bytes.
func (r RingBuffer) Bytes() []byte {
var b bytes.Buffer
Expand Down
85 changes: 77 additions & 8 deletions io/ringbuffer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ package io

import (
"bytes"
"github.com/google/go-cmp/cmp"
"io"
"io/ioutil"
"strconv"
"strings"
"testing"
)
Expand Down Expand Up @@ -49,8 +52,8 @@ func TestRingBuffer_Write(t *testing.T) {
expectedWrittenBuffer: []byte(""),
},
}
for _, c := range cases {
t.Run("", func(t *testing.T) {
for name, c := range cases {
t.Run(name, func(t *testing.T) {
byteSlice := make([]byte, c.sliceCapacity)
ringBuffer := NewRingBuffer(byteSlice)
ringBuffer.Write(c.input)
Expand Down Expand Up @@ -84,7 +87,7 @@ func TestRingBuffer_Read(t *testing.T) {
"Read capacity matches Bytes written": {
input: []byte("Hello world"),
numberOfBytesToRead: 11,
expectedStartAfterRead: 0,
expectedStartAfterRead: 11,
expectedEndAfterRead: 11,
expectedSizeOfBufferAfterRead: 0,
expectedReadSlice: []byte("Hello world"),
Expand All @@ -102,7 +105,7 @@ func TestRingBuffer_Read(t *testing.T) {
"Read capacity is more than Bytes written": {
input: []byte("hello world"),
numberOfBytesToRead: 15,
expectedStartAfterRead: 0,
expectedStartAfterRead: 11,
expectedEndAfterRead: 11,
expectedSizeOfBufferAfterRead: 0,
expectedReadSlice: []byte("hello world"),
Expand Down Expand Up @@ -136,9 +139,9 @@ func TestRingBuffer_Read(t *testing.T) {
expectedErrorAfterRead: io.EOF,
},
}
for _, c := range cases {
for name, c := range cases {
byteSlice := make([]byte, 11)
t.Run("", func(t *testing.T) {
t.Run(name, func(t *testing.T) {
ringBuffer := NewRingBuffer(byteSlice)
readSlice := make([]byte, c.numberOfBytesToRead)

Expand Down Expand Up @@ -221,11 +224,11 @@ func TestRingBuffer_forConsecutiveReadWrites(t *testing.T) {
expectedErrorAfterRead: []error{io.EOF, io.EOF},
},
}
for _, c := range cases {
for name, c := range cases {
writeSlice := make([]byte, c.sliceCapacity)
ringBuffer := NewRingBuffer(writeSlice)

t.Run("", func(t *testing.T) {
t.Run(name, func(t *testing.T) {
ringBuffer.Write([]byte(c.input[0]))
if e, a := c.expectedWrittenBuffer[0], string(ringBuffer.slice); !strings.Contains(a, e) {
t.Errorf("Expected %v, got %v", e, a)
Expand Down Expand Up @@ -394,3 +397,69 @@ func TestRingBuffer_Reset(t *testing.T) {
t.Errorf("expected read string to be of length %v, got %v", e, a)
}
}

func TestRingBufferWriteRead(t *testing.T) {
cases := []struct {
Input []byte
BufferSize int
Expected []byte
}{
{
Input: func() []byte {
return []byte(`hello world!`)
}(),
BufferSize: 6,
Expected: []byte(`world!`),
},
{
Input: func() []byte {
return []byte(`hello world!`)
}(),
BufferSize: 12,
Expected: []byte(`hello world!`),
},
{
Input: func() []byte {
return []byte(`hello`)
}(),
BufferSize: 6,
Expected: []byte(`hello`),
},
{
Input: func() []byte {
return []byte(`hello!!`)
}(),
BufferSize: 6,
Expected: []byte(`ello!!`),
},
}

for i, tt := range cases {
t.Run(strconv.Itoa(i), func(t *testing.T) {
dataReader := bytes.NewReader(tt.Input)

ringBuffer := NewRingBuffer(make([]byte, tt.BufferSize))

n, err := io.Copy(ringBuffer, dataReader)
if err != nil {
t.Errorf("unexpected error, %v", err)
return
}

if e, a := int64(len(tt.Input)), n; e != a {
t.Errorf("expect %v, got %v", e, a)
}

actual, err := ioutil.ReadAll(ringBuffer)
if err != nil {
t.Errorf("unexpected error, %v", err)
return
}

if diff := cmp.Diff(tt.Expected, actual); len(diff) > 0 {
t.Error(diff)
return
}
})
}
}

0 comments on commit 481242f

Please sign in to comment.