mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-07 03:03:59 +00:00
Reject math/big.Int on encode and bignum tags on decode for CBOR.
Although CBOR can roundtrip arbitrary precision integers, they don't roundtrip properly through Unstructured because Unstructured is limited to the dynamic numeric types int64 and float64. Rather than serializing them (and potentially losing information), reject them explicitly with an error.
This commit is contained in:
parent
fbaf9b0353
commit
61654e9f5d
@ -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"),
|
||||||
|
@ -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)
|
||||||
|
@ -741,13 +741,11 @@ func TestDecode(t *testing.T) {
|
|||||||
{
|
{
|
||||||
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")
|
|
||||||
}
|
}
|
||||||
},
|
}),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -755,13 +753,11 @@ func TestDecode(t *testing.T) {
|
|||||||
{
|
{
|
||||||
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")
|
|
||||||
}
|
}
|
||||||
},
|
}),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -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,
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
Loading…
Reference in New Issue
Block a user