-
Notifications
You must be signed in to change notification settings - Fork 17.5k
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
x/time/rate: Limiter depends on implementation-defined float to int conversion #18762
Comments
@AudriusButkevicius Sorry, I'm confused: are you expecting "ok" or "broken"? |
Well it depends. It's either a bug in all arches apart from arm64, as the code does not behave as x/time/rate documents... I've tested this on amd64, 386, arm, arm64. I've raised #18763 in case it's arm64 being broken, in which case there should also be a fix for the library. |
Ok, thanks for the explanation. |
It seems that the difference comes from an +Inf to int64 conversion. On AMD64, it results in a big negative int64, whereas on ARM64 it results in a big positive int64. As far as I know, the spec doesn't require any particular value should results in this case. So it seems the compiler is ok. The conversion is https://go.googlesource.com/time/+/master/rate/rate.go#364, which passed to waitDuration in https://go.googlesource.com/time/+/master/rate/rate.go#305, then compared with 0. |
This appears to be an artifact of the hardware conversion -- arm64 and ppc64 convert +/-Inf into the largest/smallest integer values; amd64 converts both +Inf and -Inf to the smallest integer value. |
@griesemer - do you have opinions on this? |
The spec actually says (https://golang.org/ref/spec#Conversions) So I think the library's implementation is problematic -- it depends on implementation-defined behavior, which may vary on different platforms. |
@dr2chase: @cherrymui said it all. The spec doesn't say anything specific here. |
@cherrymui Please avoid saying "undefined behavior", as that has a different meaning for people who read standards and language specs (https://en.wikipedia.org/wiki/Undefined_behavior). The problem here is that library depends on "implementation-defined behavior". |
Thanks. I edited my comment. |
Unassign myself as I'm not familiar with this package. |
As the documentation of
The expected behavior should be not allowed, here's a more detailed test: package main
import "time"
func main() {
limiter := NewLimiter(0, 1)
limiter.AllowN(time.Now(), 1)
for i := 0; i < 10000; i++ {
allow := limiter.AllowN(time.Now(), 1)
if allow {
panic("should not happen")
}
}
} |
And this has been fixed in Use the latest version could solve this issue, for example:
Or here's a workaround for this issue: limiter := NewLimiter(math.SmallestNonzeroFloat64, 1) |
What version of Go are you using (
go version
)?What operating system and processor architecture are you using (
go env
)?What did you do?
Compile two binaries using the following:
Compile as:
Run them on arm64 device (Pixel XL):
Run the same code on amd64 device:
What did you expect to see?
The behaviour between the binaries on should be the same.
I suspect it's related to how floats are handled between the arches.
What did you see instead?
Binaries return different results based on how they were compiled.
The text was updated successfully, but these errors were encountered: