Skip to content

Commit

Permalink
fix: overflow when parsing a huge uint64 number (#751)
Browse files Browse the repository at this point in the history
Such as 1<<64 - 1, math.MaxInt64 + 1, etc.
Sending these values to task arguments will cause a panic. These values are legal golang uint64 values.
  • Loading branch information
apocelipes committed Oct 12, 2023
1 parent 3dfcfdd commit bdb94a9
Show file tree
Hide file tree
Showing 4 changed files with 24 additions and 10 deletions.
11 changes: 6 additions & 5 deletions v1/tasks/reflect.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"encoding/json"
"fmt"
"reflect"
"strconv"
"strings"
)

Expand Down Expand Up @@ -288,21 +289,21 @@ func getIntValue(theType string, value interface{}) (int64, error) {
}

func getUintValue(theType string, value interface{}) (uint64, error) {
// We use https://golang.org/pkg/encoding/json/#Decoder.UseNumber when unmarshaling signatures.
// This is because JSON only supports 64-bit floating point numbers and we could lose precision
// when converting from float64 to unsigned integer
// Losing precision only happens in receiving a JSON number from a language like js,
// and receiving a large uint number from golang or python could cause json.Number.Int64 be turned into a panic.
// So we use strconv.ParseUint to correctly parse a uint value.
if strings.HasPrefix(fmt.Sprintf("%T", value), "json.Number") {
n, ok := value.(json.Number)
if !ok {
return 0, typeConversionError(value, typesMap[theType].String())
}

intVal, err := n.Int64()
uintVal, err := strconv.ParseUint(string(n), 10, 64)
if err != nil {
return 0, err
}

return uint64(intVal), nil
return uintVal, nil
}

var n uint64
Expand Down
6 changes: 6 additions & 0 deletions v1/tasks/reflect_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,12 @@ var (
expectedType: "uint64",
expectedValue: uint64(185135722552891243),
},
{
name: "uint64",
value: json.Number("9223372036854775808"), // math.MaxInt64 + 1
expectedType: "uint64",
expectedValue: uint64(9223372036854775808),
},
{
name: "float32",
value: json.Number("0.5"),
Expand Down
11 changes: 6 additions & 5 deletions v2/tasks/reflect.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"encoding/json"
"fmt"
"reflect"
"strconv"
"strings"
)

Expand Down Expand Up @@ -288,21 +289,21 @@ func getIntValue(theType string, value interface{}) (int64, error) {
}

func getUintValue(theType string, value interface{}) (uint64, error) {
// We use https://golang.org/pkg/encoding/json/#Decoder.UseNumber when unmarshaling signatures.
// This is because JSON only supports 64-bit floating point numbers and we could lose precision
// when converting from float64 to unsigned integer
// Losing precision only happens in receiving a JSON number from a language like js,
// and receiving a large uint number from golang or python could cause json.Number.Int64 be turned into a panic.
// So we use strconv.ParseUint to correctly parse a uint value.
if strings.HasPrefix(fmt.Sprintf("%T", value), "json.Number") {
n, ok := value.(json.Number)
if !ok {
return 0, typeConversionError(value, typesMap[theType].String())
}

intVal, err := n.Int64()
uintVal, err := strconv.ParseUint(string(n), 10, 64)
if err != nil {
return 0, err
}

return uint64(intVal), nil
return uintVal, nil
}

var n uint64
Expand Down
6 changes: 6 additions & 0 deletions v2/tasks/reflect_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,12 @@ var (
expectedType: "uint64",
expectedValue: uint64(185135722552891243),
},
{
name: "uint64",
value: json.Number("9223372036854775808"), // math.MaxInt64 + 1
expectedType: "uint64",
expectedValue: uint64(9223372036854775808),
},
{
name: "float32",
value: json.Number("0.5"),
Expand Down

0 comments on commit bdb94a9

Please sign in to comment.