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:
		| @@ -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) | ||||||
|   | |||||||
| @@ -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") |  | ||||||
| 					} | 					} | ||||||
| 				}, | 				}), | ||||||
| 			}, | 			}, | ||||||
| 		}) | 		}) | ||||||
|  |  | ||||||
|   | |||||||
| @@ -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) | ||||||
| 				} | 				} | ||||||
| 			}) | 			}) | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Kubernetes Prow Robot
					Kubernetes Prow Robot