aboutsummaryrefslogtreecommitdiff
path: root/misc
diff options
context:
space:
mode:
authorFilippo Valsorda <filippo@golang.org>2021-02-23 21:15:18 +0100
committerFilippo Valsorda <filippo@golang.org>2021-02-23 21:15:18 +0100
commita1902735e113eba35ccec88f2d0f7a9860cc78c9 (patch)
tree2f496be3f665322daed69cab9d71d67cc01e39a4 /misc
parent936829eff438c104d04d1e026999ef488c5832fb (diff)
parentf21be2fdc6f1becdbed1592ea0b245cdeedc5ac8 (diff)
downloadgo-a1902735e113eba35ccec88f2d0f7a9860cc78c9.tar.gz
go-a1902735e113eba35ccec88f2d0f7a9860cc78c9.zip
[dev.boringcrypto.go1.16] all: merge go1.16 into dev.boringcrypto.go1.16
Change-Id: Ie2de5ffb14530857a728cca689475aa2a12941a4
Diffstat (limited to 'misc')
-rw-r--r--misc/cgo/errors/badsym_test.go216
-rw-r--r--misc/cgo/test/issue1435.go80
-rw-r--r--misc/cgo/test/issue42495.go15
-rw-r--r--misc/cgo/test/pkg_test.go2
-rw-r--r--misc/cgo/testcarchive/carchive_test.go5
-rw-r--r--misc/cgo/testplugin/plugin_test.go14
-rw-r--r--misc/cgo/testplugin/testdata/method/main.go26
-rw-r--r--misc/cgo/testplugin/testdata/method/plugin.go13
-rw-r--r--misc/cgo/testsanitizers/msan_test.go1
-rw-r--r--misc/cgo/testsanitizers/testdata/msan7.go38
-rw-r--r--misc/cgo/testshared/shared_test.go8
-rw-r--r--misc/cgo/testshared/testdata/issue44031/a/a.go9
-rw-r--r--misc/cgo/testshared/testdata/issue44031/b/b.go17
-rw-r--r--misc/cgo/testshared/testdata/issue44031/main/main.go20
-rw-r--r--misc/ios/README7
15 files changed, 441 insertions, 30 deletions
diff --git a/misc/cgo/errors/badsym_test.go b/misc/cgo/errors/badsym_test.go
new file mode 100644
index 0000000000..b2701bf922
--- /dev/null
+++ b/misc/cgo/errors/badsym_test.go
@@ -0,0 +1,216 @@
+// Copyright 2020 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 errorstest
+
+import (
+ "bytes"
+ "io/ioutil"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "strings"
+ "testing"
+ "unicode"
+)
+
+// A manually modified object file could pass unexpected characters
+// into the files generated by cgo.
+
+const magicInput = "abcdefghijklmnopqrstuvwxyz0123"
+const magicReplace = "\n//go:cgo_ldflag \"-badflag\"\n//"
+
+const cSymbol = "BadSymbol" + magicInput + "Name"
+const cDefSource = "int " + cSymbol + " = 1;"
+const cRefSource = "extern int " + cSymbol + "; int F() { return " + cSymbol + "; }"
+
+// goSource is the source code for the trivial Go file we use.
+// We will replace TMPDIR with the temporary directory name.
+const goSource = `
+package main
+
+// #cgo LDFLAGS: TMPDIR/cbad.o TMPDIR/cbad.so
+// extern int F();
+import "C"
+
+func main() {
+ println(C.F())
+}
+`
+
+func TestBadSymbol(t *testing.T) {
+ dir := t.TempDir()
+
+ mkdir := func(base string) string {
+ ret := filepath.Join(dir, base)
+ if err := os.Mkdir(ret, 0755); err != nil {
+ t.Fatal(err)
+ }
+ return ret
+ }
+
+ cdir := mkdir("c")
+ godir := mkdir("go")
+
+ makeFile := func(mdir, base, source string) string {
+ ret := filepath.Join(mdir, base)
+ if err := ioutil.WriteFile(ret, []byte(source), 0644); err != nil {
+ t.Fatal(err)
+ }
+ return ret
+ }
+
+ cDefFile := makeFile(cdir, "cdef.c", cDefSource)
+ cRefFile := makeFile(cdir, "cref.c", cRefSource)
+
+ ccCmd := cCompilerCmd(t)
+
+ cCompile := func(arg, base, src string) string {
+ out := filepath.Join(cdir, base)
+ run := append(ccCmd, arg, "-o", out, src)
+ output, err := exec.Command(run[0], run[1:]...).CombinedOutput()
+ if err != nil {
+ t.Log(run)
+ t.Logf("%s", output)
+ t.Fatal(err)
+ }
+ if err := os.Remove(src); err != nil {
+ t.Fatal(err)
+ }
+ return out
+ }
+
+ // Build a shared library that defines a symbol whose name
+ // contains magicInput.
+
+ cShared := cCompile("-shared", "c.so", cDefFile)
+
+ // Build an object file that refers to the symbol whose name
+ // contains magicInput.
+
+ cObj := cCompile("-c", "c.o", cRefFile)
+
+ // Rewrite the shared library and the object file, replacing
+ // magicInput with magicReplace. This will have the effect of
+ // introducing a symbol whose name looks like a cgo command.
+ // The cgo tool will use that name when it generates the
+ // _cgo_import.go file, thus smuggling a magic //go:cgo_ldflag
+ // pragma into a Go file. We used to not check the pragmas in
+ // _cgo_import.go.
+
+ rewrite := func(from, to string) {
+ obj, err := ioutil.ReadFile(from)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if bytes.Count(obj, []byte(magicInput)) == 0 {
+ t.Fatalf("%s: did not find magic string", from)
+ }
+
+ if len(magicInput) != len(magicReplace) {
+ t.Fatalf("internal test error: different magic lengths: %d != %d", len(magicInput), len(magicReplace))
+ }
+
+ obj = bytes.ReplaceAll(obj, []byte(magicInput), []byte(magicReplace))
+
+ if err := ioutil.WriteFile(to, obj, 0644); err != nil {
+ t.Fatal(err)
+ }
+ }
+
+ cBadShared := filepath.Join(godir, "cbad.so")
+ rewrite(cShared, cBadShared)
+
+ cBadObj := filepath.Join(godir, "cbad.o")
+ rewrite(cObj, cBadObj)
+
+ goSourceBadObject := strings.ReplaceAll(goSource, "TMPDIR", godir)
+ makeFile(godir, "go.go", goSourceBadObject)
+
+ makeFile(godir, "go.mod", "module badsym")
+
+ // Try to build our little package.
+ cmd := exec.Command("go", "build", "-ldflags=-v")
+ cmd.Dir = godir
+ output, err := cmd.CombinedOutput()
+
+ // The build should fail, but we want it to fail because we
+ // detected the error, not because we passed a bad flag to the
+ // C linker.
+
+ if err == nil {
+ t.Errorf("go build succeeded unexpectedly")
+ }
+
+ t.Logf("%s", output)
+
+ for _, line := range bytes.Split(output, []byte("\n")) {
+ if bytes.Contains(line, []byte("dynamic symbol")) && bytes.Contains(line, []byte("contains unsupported character")) {
+ // This is the error from cgo.
+ continue
+ }
+
+ // We passed -ldflags=-v to see the external linker invocation,
+ // which should not include -badflag.
+ if bytes.Contains(line, []byte("-badflag")) {
+ t.Error("output should not mention -badflag")
+ }
+
+ // Also check for compiler errors, just in case.
+ // GCC says "unrecognized command line option".
+ // clang says "unknown argument".
+ if bytes.Contains(line, []byte("unrecognized")) || bytes.Contains(output, []byte("unknown")) {
+ t.Error("problem should have been caught before invoking C linker")
+ }
+ }
+}
+
+func cCompilerCmd(t *testing.T) []string {
+ cc := []string{goEnv(t, "CC")}
+
+ out := goEnv(t, "GOGCCFLAGS")
+ quote := '\000'
+ start := 0
+ lastSpace := true
+ backslash := false
+ s := string(out)
+ for i, c := range s {
+ if quote == '\000' && unicode.IsSpace(c) {
+ if !lastSpace {
+ cc = append(cc, s[start:i])
+ lastSpace = true
+ }
+ } else {
+ if lastSpace {
+ start = i
+ lastSpace = false
+ }
+ if quote == '\000' && !backslash && (c == '"' || c == '\'') {
+ quote = c
+ backslash = false
+ } else if !backslash && quote == c {
+ quote = '\000'
+ } else if (quote == '\000' || quote == '"') && !backslash && c == '\\' {
+ backslash = true
+ } else {
+ backslash = false
+ }
+ }
+ }
+ if !lastSpace {
+ cc = append(cc, s[start:])
+ }
+ return cc
+}
+
+func goEnv(t *testing.T, key string) string {
+ out, err := exec.Command("go", "env", key).CombinedOutput()
+ if err != nil {
+ t.Logf("go env %s\n", key)
+ t.Logf("%s", out)
+ t.Fatal(err)
+ }
+ return strings.TrimSpace(string(out))
+}
diff --git a/misc/cgo/test/issue1435.go b/misc/cgo/test/issue1435.go
index 155d33baff..a1c7cacde7 100644
--- a/misc/cgo/test/issue1435.go
+++ b/misc/cgo/test/issue1435.go
@@ -62,28 +62,60 @@ import "C"
// compareStatus is used to confirm the contents of the thread
// specific status files match expectations.
func compareStatus(filter, expect string) error {
- expected := filter + "\t" + expect
+ expected := filter + expect
pid := syscall.Getpid()
fs, err := ioutil.ReadDir(fmt.Sprintf("/proc/%d/task", pid))
if err != nil {
return fmt.Errorf("unable to find %d tasks: %v", pid, err)
}
+ expectedProc := fmt.Sprintf("Pid:\t%d", pid)
+ foundAThread := false
for _, f := range fs {
tf := fmt.Sprintf("/proc/%s/status", f.Name())
d, err := ioutil.ReadFile(tf)
if err != nil {
- return fmt.Errorf("unable to read %q: %v", tf, err)
+ // There are a surprising number of ways this
+ // can error out on linux. We've seen all of
+ // the following, so treat any error here as
+ // equivalent to the "process is gone":
+ // os.IsNotExist(err),
+ // "... : no such process",
+ // "... : bad file descriptor.
+ continue
}
lines := strings.Split(string(d), "\n")
for _, line := range lines {
+ // Different kernel vintages pad differently.
+ line = strings.TrimSpace(line)
+ if strings.HasPrefix(line, "Pid:\t") {
+ // On loaded systems, it is possible
+ // for a TID to be reused really
+ // quickly. As such, we need to
+ // validate that the thread status
+ // info we just read is a task of the
+ // same process PID as we are
+ // currently running, and not a
+ // recently terminated thread
+ // resurfaced in a different process.
+ if line != expectedProc {
+ break
+ }
+ // Fall through in the unlikely case
+ // that filter at some point is
+ // "Pid:\t".
+ }
if strings.HasPrefix(line, filter) {
if line != expected {
- return fmt.Errorf("%s %s (bad)\n", tf, line)
+ return fmt.Errorf("%q got:%q want:%q (bad) [pid=%d file:'%s' %v]\n", tf, line, expected, pid, string(d), expectedProc)
}
+ foundAThread = true
break
}
}
}
+ if !foundAThread {
+ return fmt.Errorf("found no thread /proc/<TID>/status files for process %q", expectedProc)
+ }
return nil
}
@@ -110,34 +142,34 @@ func test1435(t *testing.T) {
fn func() error
filter, expect string
}{
- {call: "Setegid(1)", fn: func() error { return syscall.Setegid(1) }, filter: "Gid:", expect: "0\t1\t0\t1"},
- {call: "Setegid(0)", fn: func() error { return syscall.Setegid(0) }, filter: "Gid:", expect: "0\t0\t0\t0"},
+ {call: "Setegid(1)", fn: func() error { return syscall.Setegid(1) }, filter: "Gid:", expect: "\t0\t1\t0\t1"},
+ {call: "Setegid(0)", fn: func() error { return syscall.Setegid(0) }, filter: "Gid:", expect: "\t0\t0\t0\t0"},
- {call: "Seteuid(1)", fn: func() error { return syscall.Seteuid(1) }, filter: "Uid:", expect: "0\t1\t0\t1"},
- {call: "Setuid(0)", fn: func() error { return syscall.Setuid(0) }, filter: "Uid:", expect: "0\t0\t0\t0"},
+ {call: "Seteuid(1)", fn: func() error { return syscall.Seteuid(1) }, filter: "Uid:", expect: "\t0\t1\t0\t1"},
+ {call: "Setuid(0)", fn: func() error { return syscall.Setuid(0) }, filter: "Uid:", expect: "\t0\t0\t0\t0"},
- {call: "Setgid(1)", fn: func() error { return syscall.Setgid(1) }, filter: "Gid:", expect: "1\t1\t1\t1"},
- {call: "Setgid(0)", fn: func() error { return syscall.Setgid(0) }, filter: "Gid:", expect: "0\t0\t0\t0"},
+ {call: "Setgid(1)", fn: func() error { return syscall.Setgid(1) }, filter: "Gid:", expect: "\t1\t1\t1\t1"},
+ {call: "Setgid(0)", fn: func() error { return syscall.Setgid(0) }, filter: "Gid:", expect: "\t0\t0\t0\t0"},
- {call: "Setgroups([]int{0,1,2,3})", fn: func() error { return syscall.Setgroups([]int{0, 1, 2, 3}) }, filter: "Groups:", expect: "0 1 2 3 "},
- {call: "Setgroups(nil)", fn: func() error { return syscall.Setgroups(nil) }, filter: "Groups:", expect: " "},
- {call: "Setgroups([]int{0})", fn: func() error { return syscall.Setgroups([]int{0}) }, filter: "Groups:", expect: "0 "},
+ {call: "Setgroups([]int{0,1,2,3})", fn: func() error { return syscall.Setgroups([]int{0, 1, 2, 3}) }, filter: "Groups:", expect: "\t0 1 2 3"},
+ {call: "Setgroups(nil)", fn: func() error { return syscall.Setgroups(nil) }, filter: "Groups:", expect: ""},
+ {call: "Setgroups([]int{0})", fn: func() error { return syscall.Setgroups([]int{0}) }, filter: "Groups:", expect: "\t0"},
- {call: "Setregid(101,0)", fn: func() error { return syscall.Setregid(101, 0) }, filter: "Gid:", expect: "101\t0\t0\t0"},
- {call: "Setregid(0,102)", fn: func() error { return syscall.Setregid(0, 102) }, filter: "Gid:", expect: "0\t102\t102\t102"},
- {call: "Setregid(0,0)", fn: func() error { return syscall.Setregid(0, 0) }, filter: "Gid:", expect: "0\t0\t0\t0"},
+ {call: "Setregid(101,0)", fn: func() error { return syscall.Setregid(101, 0) }, filter: "Gid:", expect: "\t101\t0\t0\t0"},
+ {call: "Setregid(0,102)", fn: func() error { return syscall.Setregid(0, 102) }, filter: "Gid:", expect: "\t0\t102\t102\t102"},
+ {call: "Setregid(0,0)", fn: func() error { return syscall.Setregid(0, 0) }, filter: "Gid:", expect: "\t0\t0\t0\t0"},
- {call: "Setreuid(1,0)", fn: func() error { return syscall.Setreuid(1, 0) }, filter: "Uid:", expect: "1\t0\t0\t0"},
- {call: "Setreuid(0,2)", fn: func() error { return syscall.Setreuid(0, 2) }, filter: "Uid:", expect: "0\t2\t2\t2"},
- {call: "Setreuid(0,0)", fn: func() error { return syscall.Setreuid(0, 0) }, filter: "Uid:", expect: "0\t0\t0\t0"},
+ {call: "Setreuid(1,0)", fn: func() error { return syscall.Setreuid(1, 0) }, filter: "Uid:", expect: "\t1\t0\t0\t0"},
+ {call: "Setreuid(0,2)", fn: func() error { return syscall.Setreuid(0, 2) }, filter: "Uid:", expect: "\t0\t2\t2\t2"},
+ {call: "Setreuid(0,0)", fn: func() error { return syscall.Setreuid(0, 0) }, filter: "Uid:", expect: "\t0\t0\t0\t0"},
- {call: "Setresgid(101,0,102)", fn: func() error { return syscall.Setresgid(101, 0, 102) }, filter: "Gid:", expect: "101\t0\t102\t0"},
- {call: "Setresgid(0,102,101)", fn: func() error { return syscall.Setresgid(0, 102, 101) }, filter: "Gid:", expect: "0\t102\t101\t102"},
- {call: "Setresgid(0,0,0)", fn: func() error { return syscall.Setresgid(0, 0, 0) }, filter: "Gid:", expect: "0\t0\t0\t0"},
+ {call: "Setresgid(101,0,102)", fn: func() error { return syscall.Setresgid(101, 0, 102) }, filter: "Gid:", expect: "\t101\t0\t102\t0"},
+ {call: "Setresgid(0,102,101)", fn: func() error { return syscall.Setresgid(0, 102, 101) }, filter: "Gid:", expect: "\t0\t102\t101\t102"},
+ {call: "Setresgid(0,0,0)", fn: func() error { return syscall.Setresgid(0, 0, 0) }, filter: "Gid:", expect: "\t0\t0\t0\t0"},
- {call: "Setresuid(1,0,2)", fn: func() error { return syscall.Setresuid(1, 0, 2) }, filter: "Uid:", expect: "1\t0\t2\t0"},
- {call: "Setresuid(0,2,1)", fn: func() error { return syscall.Setresuid(0, 2, 1) }, filter: "Uid:", expect: "0\t2\t1\t2"},
- {call: "Setresuid(0,0,0)", fn: func() error { return syscall.Setresuid(0, 0, 0) }, filter: "Uid:", expect: "0\t0\t0\t0"},
+ {call: "Setresuid(1,0,2)", fn: func() error { return syscall.Setresuid(1, 0, 2) }, filter: "Uid:", expect: "\t1\t0\t2\t0"},
+ {call: "Setresuid(0,2,1)", fn: func() error { return syscall.Setresuid(0, 2, 1) }, filter: "Uid:", expect: "\t0\t2\t1\t2"},
+ {call: "Setresuid(0,0,0)", fn: func() error { return syscall.Setresuid(0, 0, 0) }, filter: "Uid:", expect: "\t0\t0\t0\t0"},
}
for i, v := range vs {
diff --git a/misc/cgo/test/issue42495.go b/misc/cgo/test/issue42495.go
new file mode 100644
index 0000000000..509a67d9a3
--- /dev/null
+++ b/misc/cgo/test/issue42495.go
@@ -0,0 +1,15 @@
+// Copyright 2020 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 cgotest
+
+// typedef struct { } T42495A;
+// typedef struct { int x[0]; } T42495B;
+import "C"
+
+//export Issue42495A
+func Issue42495A(C.T42495A) {}
+
+//export Issue42495B
+func Issue42495B(C.T42495B) {}
diff --git a/misc/cgo/test/pkg_test.go b/misc/cgo/test/pkg_test.go
index a28ad4ea74..94abaa03e8 100644
--- a/misc/cgo/test/pkg_test.go
+++ b/misc/cgo/test/pkg_test.go
@@ -30,7 +30,7 @@ func TestCrossPackageTests(t *testing.T) {
switch runtime.GOOS {
case "android":
t.Skip("Can't exec cmd/go subprocess on Android.")
- case "darwin", "ios":
+ case "ios":
switch runtime.GOARCH {
case "arm64":
t.Skip("Can't exec cmd/go subprocess on iOS.")
diff --git a/misc/cgo/testcarchive/carchive_test.go b/misc/cgo/testcarchive/carchive_test.go
index 6ed25d8948..6a5adf79ca 100644
--- a/misc/cgo/testcarchive/carchive_test.go
+++ b/misc/cgo/testcarchive/carchive_test.go
@@ -118,11 +118,6 @@ func testMain(m *testing.M) int {
cc = append(cc, s[start:])
}
- if GOOS == "darwin" || GOOS == "ios" {
- // For Darwin/ARM.
- // TODO: do we still need this?
- cc = append(cc, []string{"-framework", "CoreFoundation", "-framework", "Foundation"}...)
- }
if GOOS == "aix" {
// -Wl,-bnoobjreorder is mandatory to keep the same layout
// in .text section.
diff --git a/misc/cgo/testplugin/plugin_test.go b/misc/cgo/testplugin/plugin_test.go
index 2875271c03..9055dbda04 100644
--- a/misc/cgo/testplugin/plugin_test.go
+++ b/misc/cgo/testplugin/plugin_test.go
@@ -196,3 +196,17 @@ func TestIssue25756(t *testing.T) {
})
}
}
+
+func TestMethod(t *testing.T) {
+ // Exported symbol's method must be live.
+ goCmd(t, "build", "-buildmode=plugin", "-o", "plugin.so", "./method/plugin.go")
+ goCmd(t, "build", "-o", "method.exe", "./method/main.go")
+
+ ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
+ defer cancel()
+ cmd := exec.CommandContext(ctx, "./method.exe")
+ out, err := cmd.CombinedOutput()
+ if err != nil {
+ t.Fatalf("%s: %v\n%s", strings.Join(cmd.Args, " "), err, out)
+ }
+}
diff --git a/misc/cgo/testplugin/testdata/method/main.go b/misc/cgo/testplugin/testdata/method/main.go
new file mode 100644
index 0000000000..5e9189b450
--- /dev/null
+++ b/misc/cgo/testplugin/testdata/method/main.go
@@ -0,0 +1,26 @@
+// Copyright 2020 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.
+
+// Issue 42579: methods of symbols exported from plugin must be live.
+
+package main
+
+import (
+ "plugin"
+ "reflect"
+)
+
+func main() {
+ p, err := plugin.Open("plugin.so")
+ if err != nil {
+ panic(err)
+ }
+
+ x, err := p.Lookup("X")
+ if err != nil {
+ panic(err)
+ }
+
+ reflect.ValueOf(x).Elem().MethodByName("M").Call(nil)
+}
diff --git a/misc/cgo/testplugin/testdata/method/plugin.go b/misc/cgo/testplugin/testdata/method/plugin.go
new file mode 100644
index 0000000000..240edd3bc4
--- /dev/null
+++ b/misc/cgo/testplugin/testdata/method/plugin.go
@@ -0,0 +1,13 @@
+// Copyright 2020 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
+
+func main() {}
+
+type T int
+
+func (T) M() { println("M") }
+
+var X T
diff --git a/misc/cgo/testsanitizers/msan_test.go b/misc/cgo/testsanitizers/msan_test.go
index 88b90d3d70..5e2f9759ba 100644
--- a/misc/cgo/testsanitizers/msan_test.go
+++ b/misc/cgo/testsanitizers/msan_test.go
@@ -28,6 +28,7 @@ func TestMSAN(t *testing.T) {
{src: "msan4.go"},
{src: "msan5.go"},
{src: "msan6.go"},
+ {src: "msan7.go"},
{src: "msan_fail.go", wantErr: true},
}
for _, tc := range cases {
diff --git a/misc/cgo/testsanitizers/testdata/msan7.go b/misc/cgo/testsanitizers/testdata/msan7.go
new file mode 100644
index 0000000000..2f29fd21b2
--- /dev/null
+++ b/misc/cgo/testsanitizers/testdata/msan7.go
@@ -0,0 +1,38 @@
+// Copyright 2020 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
+
+// Test passing C struct to exported Go function.
+
+/*
+#include <stdint.h>
+#include <stdlib.h>
+
+// T is a C struct with alignment padding after b.
+// The padding bytes are not considered initialized by MSAN.
+// It is big enough to be passed on stack in C ABI (and least
+// on AMD64).
+typedef struct { char b; uintptr_t x, y; } T;
+
+extern void F(T);
+
+// Use weak as a hack to permit defining a function even though we use export.
+void CF(int x) __attribute__ ((weak));
+void CF(int x) {
+ T *t = malloc(sizeof(T));
+ t->b = (char)x;
+ t->x = x;
+ t->y = x;
+ F(*t);
+}
+*/
+import "C"
+
+//export F
+func F(t C.T) { println(t.b, t.x, t.y) }
+
+func main() {
+ C.CF(C.int(0))
+}
diff --git a/misc/cgo/testshared/shared_test.go b/misc/cgo/testshared/shared_test.go
index 5e0893784b..f52391c6f6 100644
--- a/misc/cgo/testshared/shared_test.go
+++ b/misc/cgo/testshared/shared_test.go
@@ -1063,3 +1063,11 @@ func TestGCData(t *testing.T) {
goCmd(t, "build", "-linkshared", "./gcdata/main")
runWithEnv(t, "running gcdata/main", []string{"GODEBUG=clobberfree=1"}, "./main")
}
+
+// Test that we don't decode type symbols from shared libraries (which has no data,
+// causing panic). See issue 44031.
+func TestIssue44031(t *testing.T) {
+ goCmd(t, "install", "-buildmode=shared", "-linkshared", "./issue44031/a")
+ goCmd(t, "install", "-buildmode=shared", "-linkshared", "./issue44031/b")
+ goCmd(t, "run", "-linkshared", "./issue44031/main")
+}
diff --git a/misc/cgo/testshared/testdata/issue44031/a/a.go b/misc/cgo/testshared/testdata/issue44031/a/a.go
new file mode 100644
index 0000000000..48827e682f
--- /dev/null
+++ b/misc/cgo/testshared/testdata/issue44031/a/a.go
@@ -0,0 +1,9 @@
+// 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.
+
+package a
+
+type ATypeWithALoooooongName interface { // a long name, so the type descriptor symbol name is mangled
+ M()
+}
diff --git a/misc/cgo/testshared/testdata/issue44031/b/b.go b/misc/cgo/testshared/testdata/issue44031/b/b.go
new file mode 100644
index 0000000000..ad3ebec2b9
--- /dev/null
+++ b/misc/cgo/testshared/testdata/issue44031/b/b.go
@@ -0,0 +1,17 @@
+// 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.
+
+package b
+
+import "testshared/issue44031/a"
+
+type T int
+
+func (T) M() {}
+
+var i = a.ATypeWithALoooooongName(T(0))
+
+func F() {
+ i.M()
+}
diff --git a/misc/cgo/testshared/testdata/issue44031/main/main.go b/misc/cgo/testshared/testdata/issue44031/main/main.go
new file mode 100644
index 0000000000..47f2e3a98e
--- /dev/null
+++ b/misc/cgo/testshared/testdata/issue44031/main/main.go
@@ -0,0 +1,20 @@
+// 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.
+
+package main
+
+import "testshared/issue44031/b"
+
+type t int
+
+func (t) m() {}
+
+type i interface{ m() } // test that unexported method is correctly marked
+
+var v interface{} = t(0)
+
+func main() {
+ b.F()
+ v.(i).m()
+}
diff --git a/misc/ios/README b/misc/ios/README
index 433bcdfd8f..0f5e9e335e 100644
--- a/misc/ios/README
+++ b/misc/ios/README
@@ -7,6 +7,13 @@ set to the clang wrapper that invokes clang for iOS. For example, this command r
GOOS=ios GOARCH=amd64 CGO_ENABLED=1 CC_FOR_TARGET=$(pwd)/../misc/ios/clangwrap.sh ./all.bash
+If CC_FOR_TARGET is not set when the toolchain is built (make.bash or all.bash), CC
+can be set on the command line. For example,
+
+ GOOS=ios GOARCH=amd64 CGO_ENABLED=1 CC=$(go env GOROOT)/misc/ios/clangwrap.sh go build
+
+Setting CC is not necessary if the toolchain is built with CC_FOR_TARGET set.
+
To use the go tool to run individual programs and tests, put $GOROOT/bin into PATH to ensure
the go_ios_$GOARCH_exec wrapper is found. For example, to run the archive/tar tests: