summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Griesemer <gri@golang.org>2016-07-15 16:46:50 -0700
committerRobert Griesemer <gri@golang.org>2016-08-16 17:07:03 +0000
commitc7b9bd745642677c8d4b3b76803a39b4e50b4d81 (patch)
treec840ff43e81f1b19f2ccb80b631ef4eea7c6b106
parent56752eb2b8cc52311c346f986a0f6e2a9577bfe4 (diff)
downloadgo-git-c7b9bd745642677c8d4b3b76803a39b4e50b4d81.tar.gz
cmd/compile: don't crash when exporting self-recursive interfaces
For #16369. Change-Id: I4c9f5a66b95558adcc1bcface164b9b2b4382d2f Reviewed-on: https://go-review.googlesource.com/24979 Reviewed-by: Alan Donovan <adonovan@google.com>
-rw-r--r--src/cmd/compile/internal/gc/bexport.go33
-rw-r--r--src/go/types/stdlib_test.go1
-rw-r--r--test/fixedbugs/issue16369.go13
3 files changed, 46 insertions, 1 deletions
diff --git a/src/cmd/compile/internal/gc/bexport.go b/src/cmd/compile/internal/gc/bexport.go
index 38e035edc8..4c28a68443 100644
--- a/src/cmd/compile/internal/gc/bexport.go
+++ b/src/cmd/compile/internal/gc/bexport.go
@@ -197,6 +197,9 @@ type exporter struct {
written int // bytes written
indent int // for p.trace
trace bool
+
+ // work-around for issue #16369 only
+ nesting int // amount of "nesting" of interface types
}
// export writes the exportlist for localpkg to out and returns the number of bytes written.
@@ -790,11 +793,39 @@ func (p *exporter) typ(t *Type) {
case TINTER:
p.tag(interfaceTag)
-
// gc doesn't separate between embedded interfaces
// and methods declared explicitly with an interface
p.int(0) // no embedded interfaces
+
+ // Because the compiler flattens interfaces containing
+ // embedded interfaces, it is possible to create interface
+ // types that recur through an unnamed type.
+ // If trackAllTypes is disabled, such recursion is not
+ // detected, leading to a stack overflow during export
+ // (issue #16369).
+ // As a crude work-around we terminate deep recursion
+ // through interface types with an empty interface and
+ // report an error.
+ // This will catch endless recursion, but is unlikely
+ // to trigger for valid, deeply nested types given the
+ // high threshold.
+ // It would be ok to continue without reporting an error
+ // since the export format is valid. But a subsequent
+ // import would import an incorrect type. The textual
+ // exporter does not report an error but importing the
+ // resulting package will lead to a syntax error during
+ // import.
+ // TODO(gri) remove this once we have a permanent fix
+ // for the issue.
+ if p.nesting > 100 {
+ p.int(0) // 0 methods to indicate empty interface
+ yyerrorl(t.Lineno, "cannot export unnamed recursive interface")
+ break
+ }
+
+ p.nesting++
p.methodList(t)
+ p.nesting--
case TMAP:
p.tag(mapTag)
diff --git a/src/go/types/stdlib_test.go b/src/go/types/stdlib_test.go
index bd5afafe39..1c6d7b5299 100644
--- a/src/go/types/stdlib_test.go
+++ b/src/go/types/stdlib_test.go
@@ -156,6 +156,7 @@ func TestStdFixed(t *testing.T) {
"issue7746.go", // large constants - consumes too much memory
"issue11362.go", // canonical import path check
"issue15002.go", // uses Mmap; testTestDir should consult build tags
+ "issue16369.go", // go/types handles this correctly - not an issue
)
}
diff --git a/test/fixedbugs/issue16369.go b/test/fixedbugs/issue16369.go
new file mode 100644
index 0000000000..bd03fbc6c9
--- /dev/null
+++ b/test/fixedbugs/issue16369.go
@@ -0,0 +1,13 @@
+// errorcheck
+
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package p
+
+type T interface {
+ M(interface {
+ T
+ }) // ERROR "cannot export unnamed recursive interface"
+}