Skip to content

Commit 40237e0

Browse files
committed
Read txn codec fields in chunks to avoid integer overflows on large lengths
1 parent 53ae9a8 commit 40237e0

1 file changed

Lines changed: 40 additions & 40 deletions

File tree

kv/txn_codec.go

Lines changed: 40 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ package kv
33
import (
44
"bytes"
55
"encoding/binary"
6-
"strconv"
6+
"io"
77

88
"github.com/cockroachdb/errors"
99
)
@@ -14,6 +14,7 @@ const (
1414
txnIntentVersion byte = 1
1515
txnCommitVersion byte = 1
1616
txnRollbackVersion byte = 1
17+
txnReadChunkSize = 4096
1718
)
1819

1920
const txnLockFlagPrimary byte = 0x01
@@ -62,16 +63,9 @@ func DecodeTxnMeta(b []byte) (TxnMeta, error) {
6263
if primaryLen == 0 {
6364
return TxnMeta{PrimaryKey: nil, LockTTLms: ttl, CommitTS: commitTS}, nil
6465
}
65-
plen, err := u64ToInt(primaryLen)
66+
pk, err := readTxnField(r, primaryLen, "txn meta: primary key truncated")
6667
if err != nil {
67-
return TxnMeta{}, errors.WithStack(err)
68-
}
69-
if plen > r.Len() {
70-
return TxnMeta{}, errors.New("txn meta: primary key truncated")
71-
}
72-
pk := make([]byte, plen)
73-
if _, err := r.Read(pk); err != nil {
74-
return TxnMeta{}, errors.WithStack(err)
68+
return TxnMeta{}, err
7569
}
7670
return TxnMeta{PrimaryKey: pk, LockTTLms: ttl, CommitTS: commitTS}, nil
7771
}
@@ -125,16 +119,9 @@ func decodeTxnLock(b []byte) (txnLock, error) {
125119
if err := binary.Read(r, binary.BigEndian, &primaryLen); err != nil {
126120
return txnLock{}, errors.WithStack(err)
127121
}
128-
plen, err := u64ToInt(primaryLen)
122+
primaryKey, err := readTxnField(r, primaryLen, "txn lock: primary key truncated")
129123
if err != nil {
130-
return txnLock{}, errors.WithStack(err)
131-
}
132-
if plen > r.Len() {
133-
return txnLock{}, errors.New("txn lock: primary key truncated")
134-
}
135-
primaryKey := make([]byte, plen)
136-
if _, err := r.Read(primaryKey); err != nil {
137-
return txnLock{}, errors.WithStack(err)
124+
return txnLock{}, err
138125
}
139126
return txnLock{
140127
StartTS: startTS,
@@ -188,19 +175,9 @@ func decodeTxnIntent(b []byte) (txnIntent, error) {
188175
if err := binary.Read(r, binary.BigEndian, &valLen); err != nil {
189176
return txnIntent{}, errors.WithStack(err)
190177
}
191-
vlen, err := u64ToInt(valLen)
178+
val, err := readTxnField(r, valLen, "txn intent: value truncated")
192179
if err != nil {
193-
return txnIntent{}, errors.WithStack(err)
194-
}
195-
if vlen > r.Len() {
196-
return txnIntent{}, errors.New("txn intent: value truncated")
197-
}
198-
var val []byte
199-
if vlen > 0 {
200-
val = make([]byte, vlen)
201-
if _, err := r.Read(val); err != nil {
202-
return txnIntent{}, errors.WithStack(err)
203-
}
180+
return txnIntent{}, err
204181
}
205182
return txnIntent{StartTS: startTS, Op: op, Value: val}, nil
206183
}
@@ -231,16 +208,39 @@ func encodeTxnRollbackRecord() []byte {
231208
return []byte{txnRollbackVersion}
232209
}
233210

234-
func u64ToInt(v uint64) (int, error) {
235-
if strconv.IntSize == 32 && v > uint64(^uint32(0)>>1) {
236-
return 0, errors.New("txn codec: length overflows int32")
211+
func readTxnField(r *bytes.Reader, n uint64, truncatedMessage string) ([]byte, error) {
212+
b, err := readTxnSizedBytes(r, n)
213+
if err == nil {
214+
return b, nil
237215
}
238-
if strconv.IntSize == 64 && v > uint64(^uint(0)>>1) {
239-
return 0, errors.New("txn codec: length overflows int64")
216+
if errors.Is(err, io.EOF) || errors.Is(err, io.ErrUnexpectedEOF) {
217+
return nil, errors.New(truncatedMessage)
240218
}
241-
parsed, err := strconv.Atoi(strconv.FormatUint(v, 10))
242-
if err != nil {
243-
return 0, errors.WithStack(err)
219+
return nil, errors.WithStack(err)
220+
}
221+
222+
func readTxnSizedBytes(r *bytes.Reader, n uint64) ([]byte, error) {
223+
if n == 0 {
224+
return nil, nil
225+
}
226+
227+
var out []byte
228+
var chunkBuf [txnReadChunkSize]byte
229+
remaining := n
230+
for remaining >= txnReadChunkSize {
231+
if _, err := io.ReadFull(r, chunkBuf[:]); err != nil {
232+
return nil, errors.WithStack(err)
233+
}
234+
out = append(out, chunkBuf[:]...)
235+
remaining -= txnReadChunkSize
236+
}
237+
for remaining > 0 {
238+
b, err := r.ReadByte()
239+
if err != nil {
240+
return nil, errors.WithStack(err)
241+
}
242+
out = append(out, b)
243+
remaining--
244244
}
245-
return parsed, nil
245+
return out, nil
246246
}

0 commit comments

Comments
 (0)