libgo: update to Go 1.15.5 release
Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/272146
This commit is contained in:
parent
82e5048e70
commit
dec42fe4e3
9 changed files with 312 additions and 8 deletions
|
@ -1,4 +1,4 @@
|
|||
b483d0e0a289ba5fcdbd0388cbc75393367ca870
|
||||
36a7b789130b415c2fe7f8e3fc62ffbca265e3aa
|
||||
|
||||
The first line of this file holds the git revision number of the last
|
||||
merge done from the gofrontend repository.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
0e953add9656c32a788e06438cd7b533e968b7f8
|
||||
c53315d6cf1b4bfea6ff356b4a1524778c683bb9
|
||||
|
||||
The first line of this file holds the git revision number of the
|
||||
last merge done from the master library sources.
|
||||
|
|
|
@ -1 +1 @@
|
|||
go1.15.4
|
||||
go1.15.5
|
||||
|
|
|
@ -341,6 +341,8 @@ func dynimport(obj string) {
|
|||
if s.Version != "" {
|
||||
targ += "#" + s.Version
|
||||
}
|
||||
checkImportSymName(s.Name)
|
||||
checkImportSymName(targ)
|
||||
fmt.Fprintf(stdout, "//go:cgo_import_dynamic %s %s %q\n", s.Name, targ, s.Library)
|
||||
}
|
||||
lib, _ := f.ImportedLibraries()
|
||||
|
@ -356,6 +358,7 @@ func dynimport(obj string) {
|
|||
if len(s) > 0 && s[0] == '_' {
|
||||
s = s[1:]
|
||||
}
|
||||
checkImportSymName(s)
|
||||
fmt.Fprintf(stdout, "//go:cgo_import_dynamic %s %s %q\n", s, s, "")
|
||||
}
|
||||
lib, _ := f.ImportedLibraries()
|
||||
|
@ -370,6 +373,8 @@ func dynimport(obj string) {
|
|||
for _, s := range sym {
|
||||
ss := strings.Split(s, ":")
|
||||
name := strings.Split(ss[0], "@")[0]
|
||||
checkImportSymName(name)
|
||||
checkImportSymName(ss[0])
|
||||
fmt.Fprintf(stdout, "//go:cgo_import_dynamic %s %s %q\n", name, ss[0], strings.ToLower(ss[1]))
|
||||
}
|
||||
return
|
||||
|
@ -387,6 +392,7 @@ func dynimport(obj string) {
|
|||
// Go symbols.
|
||||
continue
|
||||
}
|
||||
checkImportSymName(s.Name)
|
||||
fmt.Fprintf(stdout, "//go:cgo_import_dynamic %s %s %q\n", s.Name, s.Name, s.Library)
|
||||
}
|
||||
lib, err := f.ImportedLibraries()
|
||||
|
@ -402,6 +408,23 @@ func dynimport(obj string) {
|
|||
fatalf("cannot parse %s as ELF, Mach-O, PE or XCOFF", obj)
|
||||
}
|
||||
|
||||
// checkImportSymName checks a symbol name we are going to emit as part
|
||||
// of a //go:cgo_import_dynamic pragma. These names come from object
|
||||
// files, so they may be corrupt. We are going to emit them unquoted,
|
||||
// so while they don't need to be valid symbol names (and in some cases,
|
||||
// involving symbol versions, they won't be) they must contain only
|
||||
// graphic characters and must not contain Go comments.
|
||||
func checkImportSymName(s string) {
|
||||
for _, c := range s {
|
||||
if !unicode.IsGraphic(c) || unicode.IsSpace(c) {
|
||||
fatalf("dynamic symbol %q contains unsupported character", s)
|
||||
}
|
||||
}
|
||||
if strings.Index(s, "//") >= 0 || strings.Index(s, "/*") >= 0 {
|
||||
fatalf("dynamic symbol %q contains Go comment")
|
||||
}
|
||||
}
|
||||
|
||||
// Construct a gcc struct matching the gc argument frame.
|
||||
// Assumes that in gcc, char is 1 byte, short 2 bytes, int 4 bytes, long long 8 bytes.
|
||||
// These assumptions are checked by the gccProlog.
|
||||
|
|
|
@ -2723,6 +2723,66 @@ func (b *Builder) cgo(a *Action, cgoExe, objdir string, pcCFLAGS, pcLDFLAGS, cgo
|
|||
noCompiler()
|
||||
}
|
||||
|
||||
// Double check the //go:cgo_ldflag comments in the generated files.
|
||||
// The compiler only permits such comments in files whose base name
|
||||
// starts with "_cgo_". Make sure that the comments in those files
|
||||
// are safe. This is a backstop against people somehow smuggling
|
||||
// such a comment into a file generated by cgo.
|
||||
if cfg.BuildToolchainName == "gc" && !cfg.BuildN {
|
||||
var flags []string
|
||||
for _, f := range outGo {
|
||||
if !strings.HasPrefix(filepath.Base(f), "_cgo_") {
|
||||
continue
|
||||
}
|
||||
|
||||
src, err := ioutil.ReadFile(f)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
const cgoLdflag = "//go:cgo_ldflag"
|
||||
idx := bytes.Index(src, []byte(cgoLdflag))
|
||||
for idx >= 0 {
|
||||
// We are looking at //go:cgo_ldflag.
|
||||
// Find start of line.
|
||||
start := bytes.LastIndex(src[:idx], []byte("\n"))
|
||||
if start == -1 {
|
||||
start = 0
|
||||
}
|
||||
|
||||
// Find end of line.
|
||||
end := bytes.Index(src[idx:], []byte("\n"))
|
||||
if end == -1 {
|
||||
end = len(src)
|
||||
} else {
|
||||
end += idx
|
||||
}
|
||||
|
||||
// Check for first line comment in line.
|
||||
// We don't worry about /* */ comments,
|
||||
// which normally won't appear in files
|
||||
// generated by cgo.
|
||||
commentStart := bytes.Index(src[start:], []byte("//"))
|
||||
commentStart += start
|
||||
// If that line comment is //go:cgo_ldflag,
|
||||
// it's a match.
|
||||
if bytes.HasPrefix(src[commentStart:], []byte(cgoLdflag)) {
|
||||
// Pull out the flag, and unquote it.
|
||||
// This is what the compiler does.
|
||||
flag := string(src[idx+len(cgoLdflag) : end])
|
||||
flag = strings.TrimSpace(flag)
|
||||
flag = strings.Trim(flag, `"`)
|
||||
flags = append(flags, flag)
|
||||
}
|
||||
src = src[end:]
|
||||
idx = bytes.Index(src, []byte(cgoLdflag))
|
||||
}
|
||||
}
|
||||
if err := checkLinkerFlags("LDFLAGS", "go:cgo_ldflag", flags); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return outGo, outObj, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -42,8 +42,8 @@ import (
|
|||
var re = lazyregexp.New
|
||||
|
||||
var validCompilerFlags = []*lazyregexp.Regexp{
|
||||
re(`-D([A-Za-z_].*)`),
|
||||
re(`-U([A-Za-z_]*)`),
|
||||
re(`-D([A-Za-z_][A-Za-z0-9_]*)(=[^@\-]*)?`),
|
||||
re(`-U([A-Za-z_][A-Za-z0-9_]*)`),
|
||||
re(`-F([^@\-].*)`),
|
||||
re(`-I([^@\-].*)`),
|
||||
re(`-O`),
|
||||
|
@ -51,8 +51,8 @@ var validCompilerFlags = []*lazyregexp.Regexp{
|
|||
re(`-W`),
|
||||
re(`-W([^@,]+)`), // -Wall but not -Wa,-foo.
|
||||
re(`-Wa,-mbig-obj`),
|
||||
re(`-Wp,-D([A-Za-z_].*)`),
|
||||
re(`-Wp,-U([A-Za-z_]*)`),
|
||||
re(`-Wp,-D([A-Za-z_][A-Za-z0-9_]*)(=[^@,\-]*)?`),
|
||||
re(`-Wp,-U([A-Za-z_][A-Za-z0-9_]*)`),
|
||||
re(`-ansi`),
|
||||
re(`-f(no-)?asynchronous-unwind-tables`),
|
||||
re(`-f(no-)?blocks`),
|
||||
|
|
|
@ -13,6 +13,7 @@ var goodCompilerFlags = [][]string{
|
|||
{"-DFOO"},
|
||||
{"-Dfoo=bar"},
|
||||
{"-Ufoo"},
|
||||
{"-Ufoo1"},
|
||||
{"-F/Qt"},
|
||||
{"-I/"},
|
||||
{"-I/etc/passwd"},
|
||||
|
@ -24,6 +25,8 @@ var goodCompilerFlags = [][]string{
|
|||
{"-Wall"},
|
||||
{"-Wp,-Dfoo=bar"},
|
||||
{"-Wp,-Ufoo"},
|
||||
{"-Wp,-Dfoo1"},
|
||||
{"-Wp,-Ufoo1"},
|
||||
{"-fobjc-arc"},
|
||||
{"-fno-objc-arc"},
|
||||
{"-fomit-frame-pointer"},
|
||||
|
@ -78,6 +81,8 @@ var badCompilerFlags = [][]string{
|
|||
{"-O@1"},
|
||||
{"-Wa,-foo"},
|
||||
{"-W@foo"},
|
||||
{"-Wp,-DX,-D@X"},
|
||||
{"-Wp,-UX,-U@X"},
|
||||
{"-g@gdb"},
|
||||
{"-g-gdb"},
|
||||
{"-march=@dawn"},
|
||||
|
|
|
@ -928,7 +928,7 @@ func (z nat) divRecursiveStep(u, v nat, depth int, tmp *nat, temps []*nat) {
|
|||
|
||||
// Now u < (v<<B), compute lower bits in the same way.
|
||||
// Choose shift = B-1 again.
|
||||
s := B
|
||||
s := B - 1
|
||||
qhat := *temps[depth]
|
||||
qhat.clear()
|
||||
qhat.divRecursiveStep(u[s:].norm(), v[s:], depth+1, tmp, temps)
|
||||
|
|
216
libgo/misc/cgo/errors/badsym_test.go
Normal file
216
libgo/misc/cgo/errors/badsym_test.go
Normal file
|
@ -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))
|
||||
}
|
Loading…
Add table
Reference in a new issue