Skip to content

Commit deb4580

Browse files
committed
go/types, types2: prevent unification from recursing endlessly
This is a stop gap solution to avoid panics due to stack overflow during type unification. While this doesn't address the underlying issues (for which we are still investigating the correct approach), it prevents a panic during compilation and reports a (possibly not quite correct) error message. If the programs are correct in the first place, manually providing the desired type arguments is a viable work-around, resulting in code that will continue to work even when the issues here are fixed satisfactorily. For #48619. For #48656. Change-Id: I13bb14552b38b4170b5a1b820e3172d88ff656ec Reviewed-on: https://go-review.googlesource.com/c/go/+/377954 Trust: Robert Griesemer <[email protected]> Run-TryBot: Robert Griesemer <[email protected]> Reviewed-by: Robert Findley <[email protected]>
1 parent 68b3d36 commit deb4580

File tree

6 files changed

+76
-30
lines changed

6 files changed

+76
-30
lines changed

src/cmd/compile/internal/types2/testdata/fixedbugs/issue48619.go2

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,26 @@
22
// Use of this source code is governed by a BSD-style
33
// license that can be found in the LICENSE file.
44

5-
// This issue has been re-opened.
5+
// This issue is still open:
6+
// - the error messages could be better or are incorrect
7+
// - unification fails due to stack overflow that is caught
68

79
package p
810

911
func f[P any](a, _ P) {
10-
// var x int
11-
// f(a, x /* ERROR type int of x does not match P */)
12-
// f(x, a /* ERROR type P of a does not match inferred type int for P */)
12+
var x int
13+
// TODO(gri) these error messages, while correct, could be better
14+
f(a, x /* ERROR type int of x does not match P */)
15+
f(x, a /* ERROR type P of a does not match inferred type int for P */)
1316
}
1417

1518
func g[P any](a, b P) {
16-
// g(a, b)
17-
// g(&a, &b)
18-
// g([]P{}, []P{})
19-
}
19+
g(a, b)
20+
// TODO(gri) these error messages are incorrect because the code is valid
21+
g(&a, & /* ERROR type \*P of &b does not match inferred type \*P for P */ b)
22+
g([]P{}, [ /* ERROR type \[\]P of \[\]P{} does not match inferred type \[\]P for P */ ]P{})
2023

21-
func h[P any](a, b P) {
22-
// h(&a, &b)
23-
// h([]P{a}, []P{b})
24+
// work-around: provide type argument explicitly
25+
g[*P](&a, &b)
26+
g[[]P]([]P{}, []P{})
2427
}

src/cmd/compile/internal/types2/testdata/fixedbugs/issue48656.go2

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,14 @@
22
// Use of this source code is governed by a BSD-style
33
// license that can be found in the LICENSE file.
44

5-
// This issue is still open.
5+
// This issue is still open:
6+
// - the error messages are unclear
7+
// - unification fails due to stack overflow that is caught
68

79
package p
810

9-
func f[P *Q, Q any](p P, q Q) {
10-
// _ = f[P]
11-
// _ = f[/* ERROR cannot infer P */ *P]
11+
func f[P *Q, Q any](P, Q) {
12+
// TODO(gri) these error messages are unclear
13+
_ = f[ /* ERROR P does not match \*Q */ P]
14+
_ = f[ /* ERROR cannot infer P */ *P]
1215
}

src/cmd/compile/internal/types2/unify.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,18 @@ import (
3333
// by setting up one of them (using init) and then assigning its value
3434
// to the other.
3535

36+
// Upper limit for recursion depth. Used to catch infinite recursions
37+
// due to implementation issues (e.g., see issues #48619, #48656).
38+
const unificationDepthLimit = 50
39+
3640
// A unifier maintains the current type parameters for x and y
3741
// and the respective types inferred for each type parameter.
3842
// A unifier is created by calling newUnifier.
3943
type unifier struct {
4044
exact bool
4145
x, y tparamsList // x and y must initialized via tparamsList.init
4246
types []Type // inferred types, shared by x and y
47+
depth int // recursion depth during unification
4348
}
4449

4550
// newUnifier returns a new unifier.
@@ -237,6 +242,18 @@ func (u *unifier) nifyEq(x, y Type, p *ifacePair) bool {
237242
// code the corresponding changes should be made here.
238243
// Must not be called directly from outside the unifier.
239244
func (u *unifier) nify(x, y Type, p *ifacePair) bool {
245+
// Stop gap for cases where unification fails.
246+
if u.depth >= unificationDepthLimit {
247+
if debug {
248+
panic("unification reached recursion depth limit")
249+
}
250+
return false
251+
}
252+
u.depth++
253+
defer func() {
254+
u.depth--
255+
}()
256+
240257
if !u.exact {
241258
// If exact unification is known to fail because we attempt to
242259
// match a type name against an unnamed type literal, consider

src/go/types/testdata/fixedbugs/issue48619.go2

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,26 @@
22
// Use of this source code is governed by a BSD-style
33
// license that can be found in the LICENSE file.
44

5-
// This issue has been re-opened.
5+
// This issue is still open:
6+
// - the error messages could be better or are incorrect
7+
// - unification fails due to stack overflow that is caught
68

79
package p
810

911
func f[P any](a, _ P) {
10-
// var x int
11-
// f(a, x /* ERROR type int of x does not match P */)
12-
// f(x, a /* ERROR type P of a does not match inferred type int for P */)
12+
var x int
13+
// TODO(gri) these error messages, while correct, could be better
14+
f(a, x /* ERROR type int of x does not match P */)
15+
f(x, a /* ERROR type P of a does not match inferred type int for P */)
1316
}
1417

1518
func g[P any](a, b P) {
16-
// g(a, b)
17-
// g(&a, &b)
18-
// g([]P{}, []P{})
19-
}
19+
g(a, b)
20+
// TODO(gri) these error messages are incorrect because the code is valid
21+
g(&a, & /* ERROR type \*P of &b does not match inferred type \*P for P */ b)
22+
g([]P{}, [ /* ERROR type \[\]P of \(\[\]P literal\) does not match inferred type \[\]P for P */ ]P{})
2023

21-
func h[P any](a, b P) {
22-
// h(&a, &b)
23-
// h([]P{a}, []P{b})
24+
// work-around: provide type argument explicitly
25+
g[*P](&a, &b)
26+
g[[]P]([]P{}, []P{})
2427
}

src/go/types/testdata/fixedbugs/issue48656.go2

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,14 @@
22
// Use of this source code is governed by a BSD-style
33
// license that can be found in the LICENSE file.
44

5-
// This issue is still open.
5+
// This issue is still open:
6+
// - the error messages are unclear
7+
// - unification fails due to stack overflow that is caught
68

79
package p
810

9-
func f[P interface{*Q}, Q any](p P, q Q) {
10-
// _ = f[P]
11-
// _ = f[/* ERROR cannot infer P */ *P]
11+
func f[P *Q, Q any](P, Q) {
12+
// TODO(gri) these error messages are unclear
13+
_ = f /* ERROR P does not match \*Q */ [P]
14+
_ = f /* ERROR cannot infer P */ [*P]
1215
}

src/go/types/unify.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,18 @@ import (
3333
// by setting up one of them (using init) and then assigning its value
3434
// to the other.
3535

36+
// Upper limit for recursion depth. Used to catch infinite recursions
37+
// due to implementation issues (e.g., see issues #48619, #48656).
38+
const unificationDepthLimit = 50
39+
3640
// A unifier maintains the current type parameters for x and y
3741
// and the respective types inferred for each type parameter.
3842
// A unifier is created by calling newUnifier.
3943
type unifier struct {
4044
exact bool
4145
x, y tparamsList // x and y must initialized via tparamsList.init
4246
types []Type // inferred types, shared by x and y
47+
depth int // recursion depth during unification
4348
}
4449

4550
// newUnifier returns a new unifier.
@@ -237,6 +242,18 @@ func (u *unifier) nifyEq(x, y Type, p *ifacePair) bool {
237242
// code the corresponding changes should be made here.
238243
// Must not be called directly from outside the unifier.
239244
func (u *unifier) nify(x, y Type, p *ifacePair) bool {
245+
// Stop gap for cases where unification fails.
246+
if u.depth >= unificationDepthLimit {
247+
if debug {
248+
panic("unification reached recursion depth limit")
249+
}
250+
return false
251+
}
252+
u.depth++
253+
defer func() {
254+
u.depth--
255+
}()
256+
240257
if !u.exact {
241258
// If exact unification is known to fail because we attempt to
242259
// match a type name against an unnamed type literal, consider

0 commit comments

Comments
 (0)