Skip to content

Commit 0b25e97

Browse files
ALTreeandybons
authored andcommitted
[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 <[email protected]> Run-TryBot: Robert Griesemer <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Robert Griesemer <[email protected]> Reviewed-on: https://go-review.googlesource.com/88322 Run-TryBot: Andrew Bonventre <[email protected]>
1 parent 3618ac2 commit 0b25e97

File tree

2 files changed

+22
-2
lines changed

2 files changed

+22
-2
lines changed

src/math/big/int_test.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1536,6 +1536,26 @@ func TestSqrt(t *testing.T) {
15361536
}
15371537
}
15381538

1539+
// We can't test this together with the other Exp tests above because
1540+
// it requires a different receiver setup.
1541+
func TestIssue22830(t *testing.T) {
1542+
one := new(Int).SetInt64(1)
1543+
base, _ := new(Int).SetString("84555555300000000000", 10)
1544+
mod, _ := new(Int).SetString("66666670001111111111", 10)
1545+
want, _ := new(Int).SetString("17888885298888888889", 10)
1546+
1547+
var tests = []int64{
1548+
0, 1, -1,
1549+
}
1550+
1551+
for _, n := range tests {
1552+
m := NewInt(n)
1553+
if got := m.Exp(base, one, mod); got.Cmp(want) != 0 {
1554+
t.Errorf("(%v).Exp(%s, 1, %s) = %s, want %s", n, base, mod, got, want)
1555+
}
1556+
}
1557+
}
1558+
15391559
func BenchmarkSqrt(b *testing.B) {
15401560
n, _ := new(Int).SetString("1"+strings.Repeat("0", 1001), 10)
15411561
b.ResetTimer()

src/math/big/nat.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -566,8 +566,8 @@ func (z nat) divLarge(u, uIn, v nat) (q, r nat) {
566566
// determine if z can be reused
567567
// TODO(gri) should find a better solution - this if statement
568568
// is very costly (see e.g. time pidigits -s -n 10000)
569-
if alias(z, uIn) || alias(z, v) {
570-
z = nil // z is an alias for uIn or v - cannot reuse
569+
if alias(z, u) || alias(z, uIn) || alias(z, v) {
570+
z = nil // z is an alias for u or uIn or v - cannot reuse
571571
}
572572
q = z.make(m + 1)
573573

0 commit comments

Comments
 (0)