Merge pull request #43 from goshuirc/ircreader_bug

fix an edge case in IRCReader
This commit is contained in:
Shivaram Lingamneni 2021-03-01 17:54:36 -05:00 committed by GitHub
commit 2c4b83d648
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 71 additions and 2 deletions

@ -66,8 +66,12 @@ func (cc *IRCReader) ReadLine() ([]byte, error) {
return line, nil
}
if cc.start == 0 && len(cc.buf) == cc.maxSize {
return nil, ErrReadQ // out of space, can't expand or slide
// are we out of space? we can read more if any of these are true:
// 1. cc.start != 0, so we can slide the existing data back
// 2. cc.end < len(cc.buf), so we can read data into the end of the buffer
// 3. len(cc.buf) < cc.maxSize, so we can grow the buffer
if cc.start == 0 && cc.end == len(cc.buf) && len(cc.buf) == cc.maxSize {
return nil, ErrReadQ
}
if cc.eof {

@ -4,6 +4,7 @@
package ircreader
import (
"fmt"
"io"
"math/rand"
"reflect"
@ -107,3 +108,67 @@ func TestLineReader(t *testing.T) {
doLineReaderTest(counts, t)
}
}
type mockConnLimits struct {
// simulates the arrival of data via TCP;
// each Read() call will read from at most one of the slices
reads [][]byte
}
func (c *mockConnLimits) Read(b []byte) (n int, err error) {
if len(c.reads) == 0 {
return n, io.EOF
}
readLen := min(len(c.reads[0]), len(b))
copy(b[:readLen], c.reads[0][:readLen])
c.reads[0] = c.reads[0][readLen:]
if len(c.reads[0]) == 0 {
c.reads = c.reads[1:]
}
return readLen, nil
}
func makeLine(length int, ending bool) (result []byte) {
totalLen := length
if ending {
totalLen++
}
result = make([]byte, totalLen)
for i := 0; i < length; i++ {
result[i] = 'a'
}
if ending {
result[len(result)-1] = '\n'
}
return
}
func assertEqual(found, expected interface{}) {
if !reflect.DeepEqual(found, expected) {
panic(fmt.Sprintf("expected %#v, found %#v", expected, found))
}
}
func TestRegression(t *testing.T) {
var c mockConnLimits
// this read fills up the buffer with a terminated line:
c.reads = append(c.reads, makeLine(4605, true))
// this is a large, unterminated read:
c.reads = append(c.reads, makeLine(4095, false))
// this terminates the previous read, within the acceptable limit:
c.reads = append(c.reads, makeLine(500, true))
var cc IRCReader
cc.Initialize(&c, 512, 4096+512)
line, err := cc.ReadLine()
assertEqual(len(line), 4605)
assertEqual(err, nil)
line, err = cc.ReadLine()
assertEqual(len(line), 4595)
assertEqual(err, nil)
line, err = cc.ReadLine()
assertEqual(err, io.EOF)
}