tape: Safely cast when dynamically encoding/decoding

This commit is contained in:
Sasha Koshka 2025-08-29 12:03:39 -04:00
parent 0ea7e222cc
commit 04c352fad6
3 changed files with 20 additions and 4 deletions

View File

@ -171,10 +171,12 @@ func decodeAnyOrError(decoder *Decoder, destination reflect.Value, tag Tag) (n i
if length > uint64(MaxStructureLength) { if length > uint64(MaxStructureLength) {
return 0, ErrTooLong return 0, ErrTooLong
} }
lengthCast, err := Uint64ToIntSafe(length)
if err != nil { return n, err }
oneTag, nn, err := decoder.ReadTag() oneTag, nn, err := decoder.ReadTag()
n += nn; if err != nil { return n, err } n += nn; if err != nil { return n, err }
if destination.Cap() < int(length) { if destination.Cap() < lengthCast {
destination.Grow(int(length) - destination.Cap()) destination.Grow(lengthCast - destination.Cap())
} }
// skip the rest of the array if the one tag doesn't // skip the rest of the array if the one tag doesn't
// match up with the destination // match up with the destination
@ -187,7 +189,7 @@ func decodeAnyOrError(decoder *Decoder, destination reflect.Value, tag Tag) (n i
break break
} }
if err != nil { return n, err } if err != nil { return n, err }
destination.SetLen(int(length)) destination.SetLen(lengthCast)
for index := range length { for index := range length {
nn, err := decodeAny(decoder, destination.Index(int(index)), oneTag) nn, err := decodeAny(decoder, destination.Index(int(index)), oneTag)
n += nn n += nn

View File

@ -2,7 +2,8 @@ package tape
// Error enumerates common errors in this package. // Error enumerates common errors in this package.
type Error string; const ( type Error string; const (
ErrTooLong Error = "data structure too long" ErrTooLong Error = "data structure too long"
ErrTooLarge Error = "number too large"
) )
// Error implements the error interface. // Error implements the error interface.

View File

@ -11,3 +11,16 @@ package tape
// You shouldn't need to change this. If you do, it should only be set once at // You shouldn't need to change this. If you do, it should only be set once at
// the start of the program. // the start of the program.
var MaxStructureLength = 1024 * 1024 var MaxStructureLength = 1024 * 1024
// MaxInt is the maximum value an int can hold. This varies depending on the
// system.
const MaxInt int = int(^uint(0) >> 1)
// Uint64ToIntSafe casts the input to an int if it can be done without overflow,
// or returns an error otherwise.
func Uint64ToIntSafe(input uint64) (int, error) {
if input > uint64(MaxInt) {
return 0, ErrTooLarge
}
return int(input), nil
}