aboutsummaryrefslogtreecommitdiff
path: root/src/runtime/testdata
diff options
context:
space:
mode:
authordoujiang24 <doujiang24@gmail.com>2023-08-25 17:06:31 +0000
committerGopher Robot <gobot@golang.org>2023-08-25 17:39:23 +0000
commit24b9ef1a7366fe751880ab2098cff630144b8ac8 (patch)
tree0f1de5cac722c84485bdfd9c1cc80f6422d7a037 /src/runtime/testdata
parent1a01cb22f9ab07d55ee61c95a34e1e18e49596c0 (diff)
downloadgo-24b9ef1a7366fe751880ab2098cff630144b8ac8.tar.xz
cmd/cgo: add #cgo noescape/nocallback annotations
When passing pointers of Go objects from Go to C, the cgo command generate _Cgo_use(pN) for the unsafe.Pointer type arguments, so that the Go compiler will escape these object to heap. Since the C function may callback to Go, then the Go stack might grow/shrink, that means the pointers that the C function have will be invalid. After adding the #cgo noescape annotation for a C function, the cgo command won't generate _Cgo_use(pN), and the Go compiler won't force the object escape to heap. After adding the #cgo nocallback annotation for a C function, which means the C function won't callback to Go, if it do callback to Go, the Go process will crash. Fixes #56378 Change-Id: Ifdca070584e0d349c7b12276270e50089e481f7a GitHub-Last-Rev: f1a17b08b0590eca2670e404bbfedad5461df72f GitHub-Pull-Request: golang/go#60399 Reviewed-on: https://go-review.googlesource.com/c/go/+/497837 Reviewed-by: Ian Lance Taylor <iant@google.com> Reviewed-by: Bryan Mills <bcmills@google.com> Run-TryBot: Bryan Mills <bcmills@google.com> Auto-Submit: Bryan Mills <bcmills@google.com> TryBot-Result: Gopher Robot <gobot@golang.org>
Diffstat (limited to 'src/runtime/testdata')
-rw-r--r--src/runtime/testdata/testprogcgo/cgonocallback.c9
-rw-r--r--src/runtime/testdata/testprogcgo/cgonocallback.go32
-rw-r--r--src/runtime/testdata/testprogcgo/cgonoescape.go84
3 files changed, 125 insertions, 0 deletions
diff --git a/src/runtime/testdata/testprogcgo/cgonocallback.c b/src/runtime/testdata/testprogcgo/cgonocallback.c
new file mode 100644
index 0000000000..465a484361
--- /dev/null
+++ b/src/runtime/testdata/testprogcgo/cgonocallback.c
@@ -0,0 +1,9 @@
+// Copyright 2023 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.
+
+#include "_cgo_export.h"
+
+void runCShouldNotCallback() {
+ CallbackToGo();
+}
diff --git a/src/runtime/testdata/testprogcgo/cgonocallback.go b/src/runtime/testdata/testprogcgo/cgonocallback.go
new file mode 100644
index 0000000000..8cbbfd1957
--- /dev/null
+++ b/src/runtime/testdata/testprogcgo/cgonocallback.go
@@ -0,0 +1,32 @@
+// Copyright 2023 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 main
+
+// #cgo nocallback annotations for a C function means it should not callback to Go.
+// But it do callback to go in this test, Go should crash here.
+
+/*
+#cgo nocallback runCShouldNotCallback
+
+extern void runCShouldNotCallback();
+*/
+import "C"
+
+import (
+ "fmt"
+)
+
+func init() {
+ register("CgoNoCallback", CgoNoCallback)
+}
+
+//export CallbackToGo
+func CallbackToGo() {
+}
+
+func CgoNoCallback() {
+ C.runCShouldNotCallback()
+ fmt.Println("OK")
+}
diff --git a/src/runtime/testdata/testprogcgo/cgonoescape.go b/src/runtime/testdata/testprogcgo/cgonoescape.go
new file mode 100644
index 0000000000..056be44889
--- /dev/null
+++ b/src/runtime/testdata/testprogcgo/cgonoescape.go
@@ -0,0 +1,84 @@
+// Copyright 2023 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 main
+
+// #cgo noescape annotations for a C function means its arguments won't escape to heap.
+
+// We assume that there won't be 100 new allocated heap objects in other places,
+// i.e. runtime.ReadMemStats or other runtime background works.
+// So, the tests are:
+// 1. at least 100 new allocated heap objects after invoking withoutNoEscape 100 times.
+// 2. less than 100 new allocated heap objects after invoking withoutNoEscape 100 times.
+
+/*
+#cgo noescape runCWithNoEscape
+
+void runCWithNoEscape(void *p) {
+}
+void runCWithoutNoEscape(void *p) {
+}
+*/
+import "C"
+
+import (
+ "fmt"
+ "runtime"
+ "runtime/debug"
+ "unsafe"
+)
+
+const num = 100
+
+func init() {
+ register("CgoNoEscape", CgoNoEscape)
+}
+
+//go:noinline
+func withNoEscape() {
+ var str string
+ C.runCWithNoEscape(unsafe.Pointer(&str))
+}
+
+//go:noinline
+func withoutNoEscape() {
+ var str string
+ C.runCWithoutNoEscape(unsafe.Pointer(&str))
+}
+
+func CgoNoEscape() {
+ // make GC stop to see the heap objects allocated
+ debug.SetGCPercent(-1)
+
+ var stats runtime.MemStats
+ runtime.ReadMemStats(&stats)
+ preHeapObjects := stats.HeapObjects
+
+ for i := 0; i < num; i++ {
+ withNoEscape()
+ }
+
+ runtime.ReadMemStats(&stats)
+ nowHeapObjects := stats.HeapObjects
+
+ if nowHeapObjects-preHeapObjects >= num {
+ fmt.Printf("too many heap objects allocated, pre: %v, now: %v\n", preHeapObjects, nowHeapObjects)
+ }
+
+ runtime.ReadMemStats(&stats)
+ preHeapObjects = stats.HeapObjects
+
+ for i := 0; i < num; i++ {
+ withoutNoEscape()
+ }
+
+ runtime.ReadMemStats(&stats)
+ nowHeapObjects = stats.HeapObjects
+
+ if nowHeapObjects-preHeapObjects < num {
+ fmt.Printf("too few heap objects allocated, pre: %v, now: %v\n", preHeapObjects, nowHeapObjects)
+ }
+
+ fmt.Println("OK")
+}