Merge pull request #125420 from benluddy/cbor-bignum-bigint

KEP-4222: Reject math/big.Int on encode and bignum tags on decode for CBOR.
This commit is contained in:
Kubernetes Prow Robot
2024-06-24 15:46:38 -07:00
committed by GitHub
5 changed files with 32 additions and 24 deletions

View File

@@ -121,7 +121,6 @@ func TestAppendixA(t *testing.T) {
{ {
example: hex("c249010000000000000000"), example: hex("c249010000000000000000"),
reject: "decoding tagged positive bigint value to interface{} can't reproduce this value without losing distinction between float and integer", reject: "decoding tagged positive bigint value to interface{} can't reproduce this value without losing distinction between float and integer",
fixme: "decoding bigint to interface{} must not produce math/big.Int",
}, },
{ {
example: hex("3bffffffffffffffff"), example: hex("3bffffffffffffffff"),
@@ -130,7 +129,6 @@ func TestAppendixA(t *testing.T) {
{ {
example: hex("c349010000000000000000"), example: hex("c349010000000000000000"),
reject: "-18446744073709551617 overflows int64 and falling back to float64 (as with JSON) loses distinction between float and integer", reject: "-18446744073709551617 overflows int64 and falling back to float64 (as with JSON) loses distinction between float and integer",
fixme: "decoding negative bigint to interface{} must not produce math/big.Int",
}, },
{ {
example: hex("20"), example: hex("20"),

View File

@@ -96,6 +96,10 @@ var Decode cbor.DecMode = func() cbor.DecMode {
// representation (RFC 8259 Section 6). // representation (RFC 8259 Section 6).
NaN: cbor.NaNDecodeForbidden, NaN: cbor.NaNDecodeForbidden,
Inf: cbor.InfDecodeForbidden, Inf: cbor.InfDecodeForbidden,
// Reject the arbitrary-precision integer tags because they can't be faithfully
// roundtripped through the allowable Unstructured types.
BignumTag: cbor.BignumTagForbidden,
}.DecMode() }.DecMode()
if err != nil { if err != nil {
panic(err) panic(err)

View File

@@ -739,29 +739,25 @@ func TestDecode(t *testing.T) {
group(t, "unsigned bignum", []test{ group(t, "unsigned bignum", []test{
{ {
name: "rejected", name: "rejected",
in: hex("c249010000000000000000"), // 2(18446744073709551616) in: hex("c249010000000000000000"), // 2(18446744073709551616)
fixme: "decoding cbor data tagged with 2 produces big.Int instead of rejecting", assertOnError: assertOnConcreteError(func(t *testing.T, e *cbor.UnacceptableDataItemError) {
assertOnError: func(t *testing.T, e error) { if diff := cmp.Diff(&cbor.UnacceptableDataItemError{CBORType: "tag", Message: "bignum"}, e); diff != "" {
// TODO: Once this can pass, make the assertion stronger. t.Errorf("unexpected error diff:\n%s", diff)
if e == nil {
t.Error("expected non-nil error")
} }
}, }),
}, },
}) })
group(t, "negative bignum", []test{ group(t, "negative bignum", []test{
{ {
name: "rejected", name: "rejected",
in: hex("c349010000000000000000"), // 3(-18446744073709551617) in: hex("c349010000000000000000"), // 3(-18446744073709551617)
fixme: "decoding cbor data tagged with 3 produces big.Int instead of rejecting", assertOnError: assertOnConcreteError(func(t *testing.T, e *cbor.UnacceptableDataItemError) {
assertOnError: func(t *testing.T, e error) { if diff := cmp.Diff(&cbor.UnacceptableDataItemError{CBORType: "tag", Message: "bignum"}, e); diff != "" {
// TODO: Once this can pass, make the assertion stronger. t.Errorf("unexpected error diff:\n%s", diff)
if e == nil {
t.Error("expected non-nil error")
} }
}, }),
}, },
}) })

View File

@@ -37,11 +37,10 @@ var Encode cbor.EncMode = func() cbor.EncMode {
NaNConvert: cbor.NaNConvertReject, NaNConvert: cbor.NaNConvertReject,
InfConvert: cbor.InfConvertReject, InfConvert: cbor.InfConvertReject,
// Prefer encoding math/big.Int to one of the 64-bit integer types if it fits. When // Error on attempt to encode math/big.Int values, which can't be faithfully
// later decoded into Unstructured, the set of allowable concrete numeric types is // roundtripped through Unstructured in general (the dynamic numeric types allowed
// limited to int64 and float64, so the distinction between big integer and integer // in Unstructured are limited to float64 and int64).
// can't be preserved. BigIntConvert: cbor.BigIntConvertReject,
BigIntConvert: cbor.BigIntConvertShortest,
// MarshalJSON for time.Time writes RFC3339 with nanos. // MarshalJSON for time.Time writes RFC3339 with nanos.
Time: cbor.TimeRFC3339Nano, Time: cbor.TimeRFC3339Nano,

View File

@@ -18,6 +18,8 @@ package modes_test
import ( import (
"fmt" "fmt"
"math/big"
"reflect"
"testing" "testing"
"github.com/fxamacker/cbor/v2" "github.com/fxamacker/cbor/v2"
@@ -53,6 +55,15 @@ func TestEncode(t *testing.T) {
want: []byte{0xa1, 0x41, 0x41, 0x02}, // {"A": 2} want: []byte{0xa1, 0x41, 0x41, 0x02}, // {"A": 2}
assertOnError: assertNilError, assertOnError: assertNilError,
}, },
{
name: "math/big.Int values are rejected",
in: big.NewInt(1),
assertOnError: assertOnConcreteError(func(t *testing.T, got *cbor.UnsupportedTypeError) {
if want := (&cbor.UnsupportedTypeError{Type: reflect.TypeFor[big.Int]()}); *want != *got {
t.Errorf("unexpected error, got %#v (%q), want %#v (%q)", got, got.Error(), want, want.Error())
}
}),
},
} { } {
encModes := tc.modes encModes := tc.modes
if len(encModes) == 0 { if len(encModes) == 0 {
@@ -68,7 +79,7 @@ func TestEncode(t *testing.T) {
t.Run(fmt.Sprintf("mode=%s/%s", modeName, tc.name), func(t *testing.T) { t.Run(fmt.Sprintf("mode=%s/%s", modeName, tc.name), func(t *testing.T) {
out, err := encMode.Marshal(tc.in) out, err := encMode.Marshal(tc.in)
tc.assertOnError(t, err) tc.assertOnError(t, err)
if diff := cmp.Diff(tc.want, out); diff != "" { if diff := cmp.Diff(tc.want, out, cmp.Comparer(func(a, b reflect.Type) bool { return a == b })); diff != "" {
t.Errorf("unexpected output:\n%s", diff) t.Errorf("unexpected output:\n%s", diff)
} }
}) })