aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2022-01-06 12:20:14 -0500
committerRuss Cox <rsc@golang.org>2022-01-07 00:15:59 +0000
commit07525e16ba9fcb8924ed872b015dc217d1b01b6b (patch)
tree61c324c7aab2eafa9b108293f5f62a5a9767df77 /src
parentc295137ad8e5e947205d060a26164cb71952c1bb (diff)
downloadgo-07525e16ba9fcb8924ed872b015dc217d1b01b6b.tar.gz
go-07525e16ba9fcb8924ed872b015dc217d1b01b6b.zip
math/big: fix spurious race in Rat.Denom, Float.SetRat
Rat maintains the invariant that x.b.neg is always false, but Rat.Denom was writing x.b.neg = false itself too. That makes Rat.Denom a writing operation, when it should be a read-only operation. That in turn makes it unsafe to use from multiple goroutines, which is highly unexpected. Make it read-only and therefore race-free again. Fixes #50473. Change-Id: I97b87913954511e5200c0665d16b9ed63422e505 Reviewed-on: https://go-review.googlesource.com/c/go/+/375935 Trust: Russ Cox <rsc@golang.org> Run-TryBot: Russ Cox <rsc@golang.org> Reviewed-by: Robert Griesemer <gri@golang.org>
Diffstat (limited to 'src')
-rw-r--r--src/math/big/rat.go2
-rw-r--r--src/math/big/rat_test.go18
2 files changed, 19 insertions, 1 deletions
diff --git a/src/math/big/rat.go b/src/math/big/rat.go
index d35cd4cbd1..731a979ff7 100644
--- a/src/math/big/rat.go
+++ b/src/math/big/rat.go
@@ -418,7 +418,7 @@ func (x *Rat) Num() *Int {
// If the result is a reference to x's denominator it
// may change if a new value is assigned to x, and vice versa.
func (x *Rat) Denom() *Int {
- x.b.neg = false // the result is always >= 0
+ // Note that x.b.neg is guaranteed false.
if len(x.b.abs) == 0 {
// Note: If this proves problematic, we could
// panic instead and require the Rat to
diff --git a/src/math/big/rat_test.go b/src/math/big/rat_test.go
index 02569c1b16..d98c89b357 100644
--- a/src/math/big/rat_test.go
+++ b/src/math/big/rat_test.go
@@ -726,3 +726,21 @@ func TestIssue34919(t *testing.T) {
}
}
}
+
+func TestDenomRace(t *testing.T) {
+ x := NewRat(1, 2)
+ const N = 3
+ c := make(chan bool, N)
+ for i := 0; i < N; i++ {
+ go func() {
+ // Denom (also used by Float.SetRat) used to mutate x unnecessarily,
+ // provoking race reports when run in the race detector.
+ x.Denom()
+ new(Float).SetRat(x)
+ c <- true
+ }()
+ }
+ for i := 0; i < N; i++ {
+ <-c
+ }
+}