-
Notifications
You must be signed in to change notification settings - Fork 17.8k
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
time: Integer overflow in Date #56909
Comments
See previously #5923, #6617, #32501, #36202. That said, I don't foresee any realistic programs trying to work with dates 500 billion years in the future, and unlike with (Arguably |
In my opinion the problem is in the |
I investigated this issue and I found that year 292277024628 is the border which results wrong time.After. And -292277024626 year is the border which results wrong time.Before. https://go.dev/play/p/pVxa94ZL6t9 I think the reason is that time's seconds from 292277024628 year since Jan 1 year 1 is overflown. After function uses this issue is related?🤔 I tried to handle this like below(with tests). Maybe, this is not smart enough and makes a little confusing. I thought there's a way to make panic when passing overflown year. What do you think? const (
maxYear = 292277024627
minYear = -292277024626
)
func Date(year int, month Month, day, hour, min, sec, nsec int, loc *Location) Time {
if loc == nil {
panic("time: missing Location in call to Date")
}
// Normalize month, overflowing into year.
m := int(month) - 1
year, m = norm(year, m, 12)
// add these
if year >= maxYear {
year = maxYear
} else if year <= minYear {
year = minYear
} ps: When passing negative year to time.Date, up to -292277022399 holds negative information, but -292277022400 year went positive value (292277026853). This changes minYear like below (or parse negative year to zero?) minYear = -292277022399 |
Change https://go.dev/cl/453475 mentions this issue: |
Ideally we would have the invariant that for a That invariant is not possible to provide with the current
It would be possible to expand that range to without increasing the size of the And it doesn't seem worth making the We could consider instead the invariant that a call to Even then, it's not at all obvious to me that that invariant would be intuitive or useful for most Go users — and if callers explicitly want behavior equivalent to the So it seems to me that the most straightforward solution is to define that t := time.Date(year, month, day, hour, min, second, nsec, loc)
if t.IsZero() && t.Year() != year { // Just t.Year() != year would suffice, but IsZero is cheaper.
… // Date out of range.
} Then the caller could easily decide what to do about the problem: they could explicitly choose whether to return an error, panic, cap to arbitrary limits, or fall back to the |
Thank you for advise and I learned a lot. This sounds great, but what about comparing two times? t1 := time.Date(292277024628, 1, 1, 0, 0, 0, 0, time.UTC) // overflown years
t2 := time.Date(1, 1, 1, 0, 0, 0, 0, time.UTC)
fmt.Printf("after: %v", t1.After(t2)) // -> false ? ps: |
If the caller doesn't already know that their parameters are in a reasonable range, they must check that the result from For example, consider a similar program comparing two very-far-future dates: t1 := time.Date(292277024629, 1, 1, 0, 0, 0, 0, time.UTC)
t2 := time.Date(292277024628, 1, 1, 0, 0, 0, 0, time.UTC)
fmt.Printf("after: %v", t1.After(t2)) // false‽ |
yes, exactly |
We can do what Python does, we can define |
To be honest, I think it's better to return maxYear after overflow, that big number gives more idea of what have happened than zero time. ps: |
What version of Go are you using (
go version
)?Does this issue reproduce with the latest release?
Yes
What operating system and processor architecture are you using (
go env
)?go env
OutputWhat did you do?
The function
Date
of packagetime
has an integer overflow. The year number is used to compute the number of days since epoch and then multiply be the number of second in a day: https://cs.opensource.google/go/go/+/refs/tags/go1.19.3:src/time/time.go;l=1496;drc=4b43b741710eb87cbae25f19cbde7eb733b08df1 without check. If the year number is above 549755813887 it overflows the number of second and the year number is negative.Proof of concept: https://go.dev/play/p/9dteWLSkjdn
It seems to be related to the issue #20678 but the integer overflow is reached with values on 39 bits only. It allows to have date far in the future seeing in the past.
What did you expect to see?
A positive date and
true
as output or an error.What did you see instead?
-34798235367-01-21 16:59:44 +0000 UTC false
The text was updated successfully, but these errors were encountered: