44 "bytes"
55 "encoding/binary"
66 "io"
7+ "math"
78
89 "github.com/cockroachdb/errors"
910)
@@ -209,6 +210,21 @@ func encodeTxnRollbackRecord() []byte {
209210}
210211
211212func readTxnField (r * bytes.Reader , n uint64 , truncatedMessage string ) ([]byte , error ) {
213+ // Fast-path zero-length fields.
214+ if n == 0 {
215+ return nil , nil
216+ }
217+
218+ // Ensure the requested length does not exceed the remaining reader length.
219+ if n > uint64 (r .Len ()) {
220+ return nil , errors .New (truncatedMessage )
221+ }
222+
223+ // Guard against uint64 -> int overflow / excessively large allocations.
224+ if n > uint64 (math .MaxInt ) {
225+ return nil , errors .New ("transaction field size overflows int" )
226+ }
227+
212228 b , err := readTxnSizedBytes (r , n )
213229 if err == nil {
214230 return b , nil
@@ -224,23 +240,12 @@ func readTxnSizedBytes(r *bytes.Reader, n uint64) ([]byte, error) {
224240 return nil , nil
225241 }
226242
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 --
243+ // At this point, callers are expected to have validated that n is safe to
244+ // convert to int and does not exceed the remaining reader length.
245+ size := int (n )
246+ out := make ([]byte , size )
247+ if _ , err := io .ReadFull (r , out ); err != nil {
248+ return nil , errors .WithStack (err )
244249 }
245250 return out , nil
246251}
0 commit comments