]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: check that defer/go frames are empty
authorAustin Clements <austin@google.com>
Tue, 30 Mar 2021 18:45:00 +0000 (14:45 -0400)
committerAustin Clements <austin@google.com>
Tue, 30 Mar 2021 21:20:51 +0000 (21:20 +0000)
With GOEXPERIMENT=regabidefer, these frames should always be empty.
Check that.

For #40724.

Change-Id: Id8e418a9e06b4f94543cb16b868a7e10e013c2d9
Reviewed-on: https://go-review.googlesource.com/c/go/+/306009
Trust: Austin Clements <austin@google.com>
Run-TryBot: Austin Clements <austin@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Than McIntosh <thanm@google.com>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
src/runtime/panic.go
src/runtime/proc.go
src/runtime/regabidefer_off.go [new file with mode: 0644]
src/runtime/regabidefer_on.go [new file with mode: 0644]

index b5133fa5b491dd07540fe2decfbc58156bf0b803..c265a5af79e8b0793e4d8ace63a441ccbfa88669 100644 (file)
@@ -228,6 +228,11 @@ func deferproc(siz int32, fn *funcval) { // arguments of fn follow fn
                throw("defer on system stack")
        }
 
+       if experimentRegabiDefer && siz != 0 {
+               // TODO: Make deferproc just take a func().
+               throw("defer with non-empty frame")
+       }
+
        // the arguments of fn are in a perilous state. The stack map
        // for deferproc does not describe them. So we can't let garbage
        // collection or stack copying trigger until we've copied them out
@@ -280,6 +285,9 @@ func deferprocStack(d *_defer) {
                // go code on the system stack can't defer
                throw("defer on system stack")
        }
+       if experimentRegabiDefer && d.siz != 0 {
+               throw("defer with non-empty frame")
+       }
        // siz and fn are already set.
        // The other fields are junk on entry to deferprocStack and
        // are initialized here.
@@ -824,6 +832,9 @@ func runOpenDeferFrame(gp *g, d *_defer) bool {
                argWidth, fd = readvarintUnsafe(fd)
                closureOffset, fd = readvarintUnsafe(fd)
                nArgs, fd = readvarintUnsafe(fd)
+               if experimentRegabiDefer && argWidth != 0 {
+                       throw("defer with non-empty frame")
+               }
                if deferBits&(1<<i) == 0 {
                        for j := uint32(0); j < nArgs; j++ {
                                _, fd = readvarintUnsafe(fd)
index c2edb40948d822fbca9d8eef55b1648f0b7ba5c9..d868c596bfadc2bc99267c7e100c9295ad0893d9 100644 (file)
@@ -4019,6 +4019,12 @@ func malg(stacksize int32) *g {
 //
 //go:nosplit
 func newproc(siz int32, fn *funcval) {
+       if experimentRegabiDefer && siz != 0 {
+               // TODO: When we commit to experimentRegabiDefer,
+               // rewrite newproc's comment, since it will no longer
+               // have a funny stack layout or need to be nosplit.
+               throw("go with non-empty frame")
+       }
        argp := add(unsafe.Pointer(&fn), sys.PtrSize)
        gp := getg()
        pc := getcallerpc()
diff --git a/src/runtime/regabidefer_off.go b/src/runtime/regabidefer_off.go
new file mode 100644 (file)
index 0000000..72e3cf9
--- /dev/null
@@ -0,0 +1,10 @@
+// Copyright 2021 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.
+
+//go:build !goexperiment.regabidefer
+// +build !goexperiment.regabidefer
+
+package runtime
+
+const experimentRegabiDefer = false
diff --git a/src/runtime/regabidefer_on.go b/src/runtime/regabidefer_on.go
new file mode 100644 (file)
index 0000000..281694b
--- /dev/null
@@ -0,0 +1,10 @@
+// Copyright 2021 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.
+
+//go:build goexperiment.regabidefer
+// +build goexperiment.regabidefer
+
+package runtime
+
+const experimentRegabiDefer = true