diff --git a/internal/pkg/bulk/opBulk.go b/internal/pkg/bulk/opBulk.go index 437b743a15..49371e19f2 100644 --- a/internal/pkg/bulk/opBulk.go +++ b/internal/pkg/bulk/opBulk.go @@ -9,6 +9,7 @@ import ( "context" "errors" "fmt" + "math" "time" "github.com/elastic/go-elasticsearch/v8/esapi" @@ -59,6 +60,9 @@ func (b *Bulker) waitBulkAction(ctx context.Context, action actionT, index, id s // Serialize request const kSlop = 64 + if len(body) > math.MaxInt-kSlop { + return nil, fmt.Errorf("bulk request body too large") + } blk.buf.Grow(len(body) + kSlop) if err := b.writeBulkMeta(&blk.buf, action.String(), index, id, opt.RetryOnConflict); err != nil { diff --git a/internal/pkg/bulk/opMulti.go b/internal/pkg/bulk/opMulti.go index e6901b9e98..1f0945f740 100644 --- a/internal/pkg/bulk/opMulti.go +++ b/internal/pkg/bulk/opMulti.go @@ -60,7 +60,11 @@ func (b *Bulker) multiWaitBulkOp(ctx context.Context, action actionT, ops []Mult // O(n) Determine how much space we need var byteCnt int for _, op := range ops { - byteCnt += b.calcBulkSz(actionStr, op.Index, op.ID, opt.RetryOnConflict, op.Body) + sz := b.calcBulkSz(actionStr, op.Index, op.ID, opt.RetryOnConflict, op.Body) + if sz > math.MaxInt-byteCnt { + return nil, errors.New("bulk payload too large") + } + byteCnt += sz } // Create one bulk buffer to serialize each piece. diff --git a/internal/pkg/danger/buf.go b/internal/pkg/danger/buf.go index 8b7a4510d8..38d577ea19 100644 --- a/internal/pkg/danger/buf.go +++ b/internal/pkg/danger/buf.go @@ -9,6 +9,7 @@ package danger // Effectively golang's string builder with a Reset option import ( + "math" "unicode/utf8" ) @@ -33,7 +34,31 @@ func (b *Buf) Reset() { } func (b *Buf) grow(n int) { - buf := make([]byte, len(b.buf), 2*cap(b.buf)+n) + if n < 0 { + panic("danger.Buf.grow: negative count") + } + + l := len(b.buf) + c := cap(b.buf) + + if n > math.MaxInt-l { + panic("danger.Buf.grow: size overflow") + } + need := l + n + + var doubled int + if c > math.MaxInt/2 { + doubled = math.MaxInt + } else { + doubled = 2 * c + } + + newCap := need + if doubled > newCap { + newCap = doubled + } + + buf := make([]byte, l, newCap) copy(buf, b.buf) b.buf = buf } @@ -50,6 +75,9 @@ func (b *Buf) Grow(n int) { // Write appends the contents of p to b's buffer. // Write always returns len(p), nil. func (b *Buf) Write(p []byte) (int, error) { + if len(p) > 0 { + b.Grow(len(p)) + } b.buf = append(b.buf, p...) return len(p), nil } @@ -57,6 +85,7 @@ func (b *Buf) Write(p []byte) (int, error) { // WriteByte appends the byte c to b's buffer. // The returned error is always nil. func (b *Buf) WriteByte(c byte) error { + b.Grow(1) b.buf = append(b.buf, c) return nil } @@ -80,6 +109,9 @@ func (b *Buf) WriteRune(r rune) (int, error) { // WriteString appends the contents of s to b's buffer. // It returns the length of s and a nil error. func (b *Buf) WriteString(s string) (int, error) { + if len(s) > 0 { + b.Grow(len(s)) + } b.buf = append(b.buf, s...) return len(s), nil }