-
Notifications
You must be signed in to change notification settings - Fork 61
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Decouple time.Time parsing from empty interface behavior. #503
Decouple time.Time parsing from empty interface behavior. #503
Conversation
@@ -3759,7 +3773,7 @@ func TestDecodeInvalidTagTime(t *testing.T) { | |||
name: "Tag 1 with negative integer overflow", | |||
data: hexDecode("c13bffffffffffffffff"), | |||
decodeToTypes: []reflect.Type{typeIntf, typeTime}, | |||
wantErrorMsg: "cbor: cannot unmarshal tag into Go value of type time.Time", | |||
wantErrorMsg: "cbor: cannot unmarshal negative integer into Go value of type time.Time (-18446744073709551616 overflows Go's int64)", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My understanding is that overflow was causing parse to return math.Big
in these cases, so the previous error came from the default case of the type switch in parseToTime.
DefaultByteStringType: reflect.TypeOf(""), | ||
}, | ||
data: hexDecode("54323031332d30332d32315432303a30343a30305a"), | ||
wantErrorMsg: "cbor: cannot unmarshal byte string into Go value of type time.Time", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This reproduces #501 (on master, a nil error is returned instead).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for opening this PR! Looks great!
I left a comment about the need to handle decoding CBOR null and CBOR undefined to time.Time{}
.
decode.go
Outdated
if val == math.MaxUint64 { | ||
// Maximum absolute value representable by negative integer is 2^64, | ||
// not 2^64-1, so it overflows uint64. | ||
return time.Time{}, &UnmarshalTypeError{ | ||
CBORType: t.String(), | ||
GoType: typeTime.String(), | ||
errorMsg: fmt.Sprintf("-18446744073709551616 overflows Go's int64"), | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for preventing overflow 👍
42e1c7c
to
c6e1f39
Compare
@fxamacker Thanks for the discussion in #503 (comment)! I've added tests for those edge cases and resolved them according to your suggested behaviors. PTAL! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for updating this PR and adding detailed documentation!
I left a comment related to skipping data before returning from parseToTime()
.
// and fractional seconds since January 1, 1970 UTC. As a special case, Infinite | ||
// and NaN float values decode to time.Time's zero value. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for adding the comment about special case! 👍
// TimeTag specifies whether or not untagged data items, or tags other | ||
// than tag 0 and tag 1, can be decoded to time.Time. If tag 0 or tag 1 | ||
// appears in an input, the type of its content is always validated as | ||
// specified in RFC 8949. That behavior is not controlled by this | ||
// option. The behavior of the supported modes are: | ||
// | ||
// DecTagIgnored (default): Untagged text strings and text strings | ||
// enclosed in tags other than 0 and 1 are decoded as though enclosed | ||
// in tag 0. Untagged unsigned integers, negative integers, and | ||
// floating-point numbers (or those enclosed in tags other than 0 and | ||
// 1) are decoded as though enclosed in tag 1. Decoding a tag other | ||
// than 0 or 1 enclosing simple values null or undefined into a | ||
// time.Time does not modify the destination value. | ||
// | ||
// DecTagOptional: Untagged text strings are decoded as though | ||
// enclosed in tag 0. Untagged unsigned integers, negative integers, | ||
// and floating-point numbers are decoded as though enclosed in tag | ||
// 1. Tags other than 0 and 1 will produce an error on attempts to | ||
// decode them into a time.Time. | ||
// | ||
// DecTagRequired: Only tags 0 and 1 can be decoded to time.Time. Any | ||
// other input will produce an error. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks so much for improving the documentation! 👍
Due to an implementation detail, options controlling decodes into empty interface values could in some cases affect the behavior of decoding into time.Time. That is fixed. This patch also clarifies the documentation and reconciles a couple edge-case behaviors: 1. In TimeTag mode DecTagIgnored, decoding a null or undefined simple value enclosed in a tag other than 0 or 1 to time.Time is now a no-op. This is the same as the existing behavior when decoding an untagged null or undefined. 2. The content type enclosed by tags 0 and 1 were not being validated if enclosed within an unrecognized tag. This has been fixed. Signed-off-by: Ben Luddy <bluddy@redhat.com>
c6e1f39
to
865ac96
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great! Thanks so much for contributing this PR! 👍
Description
PR Was Proposed and Welcomed in Currently Open Issue
time.Time
is allowed if decoding optionDefaultByteStringType
is set toreflect.TypeOf("")
#501time.Time
is allowed if decoding optionDefaultByteStringType
is set toreflect.TypeOf("")
#501Checklist (for code PR only, ignore for docs PR)
Last line of each commit message should be in this format:
Signed-off-by: Firstname Lastname firstname.lastname@example.com
(see next section).
Certify the Developer's Certificate of Origin 1.1
the Developer Certificate of Origin 1.1.