aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlberto Donizetti <alb.donizetti@gmail.com>2017-11-21 14:16:04 +0100
committerAndrew Bonventre <andybons@golang.org>2018-01-22 20:25:04 +0000
commit0b25e97d03b520d8507342d3c7df9b98ebcbe2c0 (patch)
tree7a086f34e383a5a1e3dae6a0f409057c75b176af
parent3618ac2ca5020b8ece78e6c5348e091f5b79c5e8 (diff)
downloadgo-0b25e97d03b520d8507342d3c7df9b98ebcbe2c0.tar.gz
go-0b25e97d03b520d8507342d3c7df9b98ebcbe2c0.zip
[release-branch.go1.9] math/big: protect against aliasing in nat.divLarge
In nat.divLarge (having signature (z nat).divLarge(u, uIn, v nat)), we check whether z aliases uIn or v, but aliasing is currently not checked for the u parameter. Unfortunately, z and u aliasing each other can in some cases cause errors in the computation. The q return parameter (which will hold the result's quotient), is unconditionally initialized as q = z.make(m + 1) When cap(z) ≥ m+1, z.make() will reuse z's backing array, causing q and z to share the same backing array. If then z aliases u, setting q during the quotient computation will then corrupt u, which at that point already holds computation state. To fix this, we add an alias(z, u) check at the beginning of the function, taking care of aliasing the same way we already do for uIn and v. Fixes #22830 Change-Id: I3ab81120d5af6db7772a062bb1dfc011de91f7ad Reviewed-on: https://go-review.googlesource.com/78995 Run-TryBot: Alberto Donizetti <alb.donizetti@gmail.com> Run-TryBot: Robert Griesemer <gri@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Robert Griesemer <gri@golang.org> Reviewed-on: https://go-review.googlesource.com/88322 Run-TryBot: Andrew Bonventre <andybons@golang.org>
-rw-r--r--src/math/big/int_test.go20
-rw-r--r--src/math/big/nat.go4
2 files changed, 22 insertions, 2 deletions
diff --git a/src/math/big/int_test.go b/src/math/big/int_test.go
index 42e810b3b8..46e2ff1203 100644
--- a/src/math/big/int_test.go
+++ b/src/math/big/int_test.go
@@ -1536,6 +1536,26 @@ func TestSqrt(t *testing.T) {
}
}
+// We can't test this together with the other Exp tests above because
+// it requires a different receiver setup.
+func TestIssue22830(t *testing.T) {
+ one := new(Int).SetInt64(1)
+ base, _ := new(Int).SetString("84555555300000000000", 10)
+ mod, _ := new(Int).SetString("66666670001111111111", 10)
+ want, _ := new(Int).SetString("17888885298888888889", 10)
+
+ var tests = []int64{
+ 0, 1, -1,
+ }
+
+ for _, n := range tests {
+ m := NewInt(n)
+ if got := m.Exp(base, one, mod); got.Cmp(want) != 0 {
+ t.Errorf("(%v).Exp(%s, 1, %s) = %s, want %s", n, base, mod, got, want)
+ }
+ }
+}
+
func BenchmarkSqrt(b *testing.B) {
n, _ := new(Int).SetString("1"+strings.Repeat("0", 1001), 10)
b.ResetTimer()
diff --git a/src/math/big/nat.go b/src/math/big/nat.go
index 889eacb90f..f2cdbdb909 100644
--- a/src/math/big/nat.go
+++ b/src/math/big/nat.go
@@ -566,8 +566,8 @@ func (z nat) divLarge(u, uIn, v nat) (q, r nat) {
// determine if z can be reused
// TODO(gri) should find a better solution - this if statement
// is very costly (see e.g. time pidigits -s -n 10000)
- if alias(z, uIn) || alias(z, v) {
- z = nil // z is an alias for uIn or v - cannot reuse
+ if alias(z, u) || alias(z, uIn) || alias(z, v) {
+ z = nil // z is an alias for u or uIn or v - cannot reuse
}
q = z.make(m + 1)