]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: abort earlier if stack frame too large
authorKeith Randall <khr@golang.org>
Wed, 11 Oct 2017 00:43:41 +0000 (17:43 -0700)
committerKeith Randall <khr@golang.org>
Wed, 11 Oct 2017 18:24:13 +0000 (18:24 +0000)
If the stack frame is too large, abort immediately.
We used to generate code first, then abort.
In issue 22200, generating code raised a panic
so we got an ICE instead of an error message.

Change the max frame size to 1GB (from 2GB).
Stack frames between 1.1GB and 2GB didn't used to work anyway,
the pcln table generation would have failed and generated an ICE.

Fixes #22200

Change-Id: I1d918ab27ba6ebf5c87ec65d1bccf973f8c8541e
Reviewed-on: https://go-review.googlesource.com/69810
Run-TryBot: Keith Randall <khr@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
12 files changed:
src/cmd/compile/internal/gc/main.go
src/cmd/compile/internal/gc/pgen.go
src/cmd/compile/internal/gc/ssa.go
src/cmd/internal/obj/arm/asm5.go
src/cmd/internal/obj/arm64/asm7.go
src/cmd/internal/obj/link.go
src/cmd/internal/obj/mips/asm0.go
src/cmd/internal/obj/pcln.go
src/cmd/internal/obj/x86/asm6.go
src/go/types/stdlib_test.go
test/fixedbugs/issue22200.go [new file with mode: 0644]
test/fixedbugs/issue22200b.go [new file with mode: 0644]

index 6968d044a449fabcb49216e9c7802fc8b8d4aafe..2dbb8155f5618842d5dbab85ad42fc2f3a198d1a 100644 (file)
@@ -139,6 +139,7 @@ func Main(archInit func(*Arch)) {
 
        Ctxt = obj.Linknew(thearch.LinkArch)
        Ctxt.DiagFunc = yyerror
+       Ctxt.DiagFlush = flusherrors
        Ctxt.Bso = bufio.NewWriter(os.Stdout)
 
        localpkg = types.NewPkg("", "")
@@ -616,7 +617,7 @@ func Main(archInit func(*Arch)) {
                        return largeStackFrames[i].Before(largeStackFrames[j])
                })
                for _, largePos := range largeStackFrames {
-                       yyerrorl(largePos, "stack frame too large (>2GB)")
+                       yyerrorl(largePos, "stack frame too large (>1GB)")
                }
        }
 
index 0db5f369adc511e618b40af1d13f4e1e2ad73c52..84d06a00e73d59b7c08a4f0b8b01f9dd6f0dca12 100644 (file)
@@ -228,23 +228,23 @@ func compilenow() bool {
        return nBackendWorkers == 1 && Debug_compilelater == 0
 }
 
-const maxStackSize = 1 << 31
+const maxStackSize = 1 << 30
 
 // compileSSA builds an SSA backend function,
 // uses it to generate a plist,
 // and flushes that plist to machine code.
 // worker indicates which of the backend workers is doing the processing.
 func compileSSA(fn *Node, worker int) {
-       ssafn := buildssa(fn, worker)
-       pp := newProgs(fn, worker)
-       genssa(ssafn, pp)
-       if pp.Text.To.Offset < maxStackSize {
-               pp.Flush()
-       } else {
+       f := buildssa(fn, worker)
+       if f.Frontend().(*ssafn).stksize >= maxStackSize {
                largeStackFramesMu.Lock()
                largeStackFrames = append(largeStackFrames, fn.Pos)
                largeStackFramesMu.Unlock()
+               return
        }
+       pp := newProgs(fn, worker)
+       genssa(f, pp)
+       pp.Flush()
        // fieldtrack must be called after pp.Flush. See issue 20014.
        fieldtrack(pp.Text.From.Sym, fn.Func.FieldTrack)
        pp.Free()
index 69c56a86ee463e00b16cd96904b348806f0e350a..c633ee4c932f927f44991a7227e0c70d1d4f4573 100644 (file)
@@ -4443,11 +4443,7 @@ func genssa(f *ssa.Func, pp *Progs) {
 
        e := f.Frontend().(*ssafn)
 
-       // Generate GC bitmaps, except if the stack is too large,
-       // in which compilation will fail later anyway (issue 20529).
-       if e.stksize < maxStackSize {
-               s.stackMapIndex = liveness(e, f)
-       }
+       s.stackMapIndex = liveness(e, f)
 
        // Remember where each block starts.
        s.bstart = make([]*obj.Prog, f.NumBlocks())
index 78f39782657f0108aa5274474f5b90e9950a1359..8318966501a6cd6be6185e308caf5d903933f397 100644 (file)
@@ -1577,6 +1577,7 @@ func buildop(ctxt *obj.Link) {
                switch r {
                default:
                        ctxt.Diag("unknown op in build: %v", r)
+                       ctxt.DiagFlush()
                        log.Fatalf("bad code")
 
                case AADD:
index b5bc858d7e21cd39c50f153c933323e12bfb7676..a7f4b010ee62cebe563a2f6644ad5b122774c239 100644 (file)
@@ -1618,6 +1618,7 @@ func buildop(ctxt *obj.Link) {
                switch r {
                default:
                        ctxt.Diag("unknown op in build: %v", r)
+                       ctxt.DiagFlush()
                        log.Fatalf("bad code")
 
                case AADD:
index abd90e34d27c59f52c5860fb6db767a81ef8816c..00453f2d3a3f9e1081d66a665f75d569bcfb205c 100644 (file)
@@ -527,6 +527,7 @@ type Link struct {
        InlTree            InlTree // global inlining tree used by gc/inl.go
        Imports            []string
        DiagFunc           func(string, ...interface{})
+       DiagFlush          func()
        DebugInfo          func(fn *LSym, curfn interface{}) []dwarf.Scope // if non-nil, curfn is a *gc.Node
        Errors             int
 
index 6257e5b83d2a084022c7c92f1f11e99348dd16b8..2dcfa97bf704da7409f0eb005fceb7bd832b1289 100644 (file)
@@ -893,6 +893,7 @@ func buildop(ctxt *obj.Link) {
                switch r {
                default:
                        ctxt.Diag("unknown op in build: %v", r)
+                       ctxt.DiagFlush()
                        log.Fatalf("bad code")
 
                case AABSF:
index b85bb8aca2101fbef5551938373215d8d6129d84..d1d36cf685c42611a831620289c045ca1ecec14f 100644 (file)
@@ -223,6 +223,7 @@ func pctospadj(ctxt *Link, sym *LSym, oldval int32, p *Prog, phase int32, arg in
        }
        if oldval+p.Spadj < -10000 || oldval+p.Spadj > 1100000000 {
                ctxt.Diag("overflow in spadj: %d + %d = %d", oldval, p.Spadj, oldval+p.Spadj)
+               ctxt.DiagFlush()
                log.Fatalf("bad code")
        }
 
@@ -240,6 +241,7 @@ func pctopcdata(ctxt *Link, sym *LSym, oldval int32, p *Prog, phase int32, arg i
        }
        if int64(int32(p.To.Offset)) != p.To.Offset {
                ctxt.Diag("overflow in PCDATA instruction: %v", p)
+               ctxt.DiagFlush()
                log.Fatalf("bad code")
        }
 
index 53bef1cf7831483be06c22486e0f059d702856e6..6044a9d24d81e65793a1bc222073eb296ff31016 100644 (file)
@@ -3892,6 +3892,7 @@ func (asmbuf *AsmBuf) doasm(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog) {
                        case Zcall, Zcallduff:
                                if p.To.Sym == nil {
                                        ctxt.Diag("call without target")
+                                       ctxt.DiagFlush()
                                        log.Fatalf("bad code")
                                }
 
@@ -3932,6 +3933,7 @@ func (asmbuf *AsmBuf) doasm(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog) {
                                if p.To.Sym != nil {
                                        if yt.zcase != Zjmp {
                                                ctxt.Diag("branch to ATEXT")
+                                               ctxt.DiagFlush()
                                                log.Fatalf("bad code")
                                        }
 
@@ -3953,6 +3955,7 @@ func (asmbuf *AsmBuf) doasm(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog) {
 
                                if q == nil {
                                        ctxt.Diag("jmp/branch/loop without target")
+                                       ctxt.DiagFlush()
                                        log.Fatalf("bad code")
                                }
 
@@ -4450,6 +4453,7 @@ func byteswapreg(ctxt *obj.Link, a *obj.Addr) int {
                return REG_DX
        default:
                ctxt.Diag("impossible byte register")
+               ctxt.DiagFlush()
                log.Fatalf("bad code")
                return 0
        }
index 34029b8681bed022290e8630d15ca6525f062de7..ad4c51f74def16e3a870dfb7972c29e45a9de2d9 100644 (file)
@@ -163,15 +163,17 @@ func TestStdFixed(t *testing.T) {
 
        testTestDir(t, filepath.Join(runtime.GOROOT(), "test", "fixedbugs"),
                "bug248.go", "bug302.go", "bug369.go", // complex test instructions - ignore
-               "issue6889.go",  // gc-specific test
-               "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
-               "issue18459.go", // go/types doesn't check validity of //go:xxx directives
-               "issue18882.go", // go/types doesn't check validity of //go:xxx directives
-               "issue20232.go", // go/types handles larger constants than gc
-               "issue20529.go", // go/types does not have constraints on stack size
+               "issue6889.go",   // gc-specific test
+               "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
+               "issue18459.go",  // go/types doesn't check validity of //go:xxx directives
+               "issue18882.go",  // go/types doesn't check validity of //go:xxx directives
+               "issue20232.go",  // go/types handles larger constants than gc
+               "issue20529.go",  // go/types does not have constraints on stack size
+               "issue22200.go",  // go/types does not have constraints on stack size
+               "issue22200b.go", // go/types does not have constraints on stack size
        )
 }
 
diff --git a/test/fixedbugs/issue22200.go b/test/fixedbugs/issue22200.go
new file mode 100644 (file)
index 0000000..66b9538
--- /dev/null
@@ -0,0 +1,20 @@
+// errorcheck
+
+// Copyright 2017 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
+
+func f1(x *[1<<30 - 1e6]byte) byte {
+       for _, b := range *x {
+               return b
+       }
+       return 0
+}
+func f2(x *[1<<30 + 1e6]byte) byte { // ERROR "stack frame too large"
+       for _, b := range *x {
+               return b
+       }
+       return 0
+}
diff --git a/test/fixedbugs/issue22200b.go b/test/fixedbugs/issue22200b.go
new file mode 100644 (file)
index 0000000..ceaae75
--- /dev/null
@@ -0,0 +1,28 @@
+// errorcheck
+
+// Copyright 2017 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.
+
+// +build !386,!amd64p32,!arm,!mips
+
+package p
+
+func f3(x *[1 << 31]byte) byte { // ERROR "stack frame too large"
+       for _, b := range *x {
+               return b
+       }
+       return 0
+}
+func f4(x *[1 << 32]byte) byte { // ERROR "stack frame too large"
+       for _, b := range *x {
+               return b
+       }
+       return 0
+}
+func f5(x *[1 << 33]byte) byte { // ERROR "stack frame too large"
+       for _, b := range *x {
+               return b
+       }
+       return 0
+}