summaryrefslogtreecommitdiff
path: root/libgo/go/cmd/cgo/out.go
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/go/cmd/cgo/out.go')
-rw-r--r--libgo/go/cmd/cgo/out.go103
1 files changed, 64 insertions, 39 deletions
diff --git a/libgo/go/cmd/cgo/out.go b/libgo/go/cmd/cgo/out.go
index 92fad5d31a7..10d4b74b6ee 100644
--- a/libgo/go/cmd/cgo/out.go
+++ b/libgo/go/cmd/cgo/out.go
@@ -17,6 +17,7 @@ import (
"io"
"os"
"path/filepath"
+ "regexp"
"sort"
"strings"
)
@@ -78,7 +79,7 @@ func (p *Package) writeDefs() {
// Write second Go output: definitions of _C_xxx.
// In a separate file so that the import of "unsafe" does not
// pollute the original file.
- fmt.Fprintf(fgo2, "// Created by cgo - DO NOT EDIT\n\n")
+ fmt.Fprintf(fgo2, "// Code generated by cmd/cgo; DO NOT EDIT.\n\n")
fmt.Fprintf(fgo2, "package %s\n\n", p.PackageName)
fmt.Fprintf(fgo2, "import \"unsafe\"\n\n")
if !*gccgo && *importRuntimeCgo {
@@ -277,10 +278,7 @@ func dynimport(obj string) {
}
}
}
- sym, err := f.ImportedSymbols()
- if err != nil {
- fatalf("cannot load imported symbols from ELF file %s: %v", obj, err)
- }
+ sym, _ := f.ImportedSymbols()
for _, s := range sym {
targ := s.Name
if s.Version != "" {
@@ -288,10 +286,7 @@ func dynimport(obj string) {
}
fmt.Fprintf(stdout, "//go:cgo_import_dynamic %s %s %q\n", s.Name, targ, s.Library)
}
- lib, err := f.ImportedLibraries()
- if err != nil {
- fatalf("cannot load imported libraries from ELF file %s: %v", obj, err)
- }
+ lib, _ := f.ImportedLibraries()
for _, l := range lib {
fmt.Fprintf(stdout, "//go:cgo_import_dynamic _ _ %q\n", l)
}
@@ -299,20 +294,14 @@ func dynimport(obj string) {
}
if f, err := macho.Open(obj); err == nil {
- sym, err := f.ImportedSymbols()
- if err != nil {
- fatalf("cannot load imported symbols from Mach-O file %s: %v", obj, err)
- }
+ sym, _ := f.ImportedSymbols()
for _, s := range sym {
if len(s) > 0 && s[0] == '_' {
s = s[1:]
}
fmt.Fprintf(stdout, "//go:cgo_import_dynamic %s %s %q\n", s, s, "")
}
- lib, err := f.ImportedLibraries()
- if err != nil {
- fatalf("cannot load imported libraries from Mach-O file %s: %v", obj, err)
- }
+ lib, _ := f.ImportedLibraries()
for _, l := range lib {
fmt.Fprintf(stdout, "//go:cgo_import_dynamic _ _ %q\n", l)
}
@@ -320,10 +309,7 @@ func dynimport(obj string) {
}
if f, err := pe.Open(obj); err == nil {
- sym, err := f.ImportedSymbols()
- if err != nil {
- fatalf("cannot load imported symbols from PE file %s: %v", obj, err)
- }
+ sym, _ := f.ImportedSymbols()
for _, s := range sym {
ss := strings.Split(s, ":")
name := strings.Split(ss[0], "@")[0]
@@ -559,8 +545,8 @@ func (p *Package) writeOutput(f *File, srcfile string) {
p.GccFiles = append(p.GccFiles, base+".cgo2.c")
// Write Go output: Go input with rewrites of C.xxx to _C_xxx.
- fmt.Fprintf(fgo1, "// Created by cgo - DO NOT EDIT\n\n")
- fmt.Fprintf(fgo1, "//line %s:1\n", srcfile)
+ fmt.Fprintf(fgo1, "// Code generated by cmd/cgo; DO NOT EDIT.\n\n")
+ fmt.Fprintf(fgo1, "//line %s:1:1\n", srcfile)
fgo1.Write(f.Edit.Bytes())
// While we process the vars and funcs, also write gcc output.
@@ -569,6 +555,7 @@ func (p *Package) writeOutput(f *File, srcfile string) {
fmt.Fprintf(fgcc, "%s\n", f.Preamble)
fmt.Fprintf(fgcc, "%s\n", gccProlog)
fmt.Fprintf(fgcc, "%s\n", tsanProlog)
+ fmt.Fprintf(fgcc, "%s\n", msanProlog)
for _, key := range nameKeys(f.Name) {
n := f.Name[key]
@@ -632,14 +619,14 @@ func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) {
// We're trying to write a gcc struct that matches gc's layout.
// Use packed attribute to force no padding in this struct in case
// gcc has different packing requirements.
- fmt.Fprintf(fgcc, "\t%s %v *a = v;\n", ctype, p.packedAttribute())
+ fmt.Fprintf(fgcc, "\t%s %v *_cgo_a = v;\n", ctype, p.packedAttribute())
if n.FuncType.Result != nil {
// Save the stack top for use below.
- fmt.Fprintf(fgcc, "\tchar *stktop = _cgo_topofstack();\n")
+ fmt.Fprintf(fgcc, "\tchar *_cgo_stktop = _cgo_topofstack();\n")
}
tr := n.FuncType.Result
if tr != nil {
- fmt.Fprintf(fgcc, "\t__typeof__(a->r) r;\n")
+ fmt.Fprintf(fgcc, "\t__typeof__(_cgo_a->r) _cgo_r;\n")
}
fmt.Fprintf(fgcc, "\t_cgo_tsan_acquire();\n")
if n.AddError {
@@ -647,9 +634,9 @@ func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) {
}
fmt.Fprintf(fgcc, "\t")
if tr != nil {
- fmt.Fprintf(fgcc, "r = ")
+ fmt.Fprintf(fgcc, "_cgo_r = ")
if c := tr.C.String(); c[len(c)-1] == '*' {
- fmt.Fprint(fgcc, "(__typeof__(a->r)) ")
+ fmt.Fprint(fgcc, "(__typeof__(_cgo_a->r)) ")
}
}
if n.Kind == "macro" {
@@ -660,7 +647,7 @@ func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) {
if i > 0 {
fmt.Fprintf(fgcc, ", ")
}
- fmt.Fprintf(fgcc, "a->p%d", i)
+ fmt.Fprintf(fgcc, "_cgo_a->p%d", i)
}
fmt.Fprintf(fgcc, ");\n")
}
@@ -671,9 +658,19 @@ func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) {
if n.FuncType.Result != nil {
// The cgo call may have caused a stack copy (via a callback).
// Adjust the return value pointer appropriately.
- fmt.Fprintf(fgcc, "\ta = (void*)((char*)a + (_cgo_topofstack() - stktop));\n")
+ fmt.Fprintf(fgcc, "\t_cgo_a = (void*)((char*)_cgo_a + (_cgo_topofstack() - _cgo_stktop));\n")
// Save the return value.
- fmt.Fprintf(fgcc, "\ta->r = r;\n")
+ fmt.Fprintf(fgcc, "\t_cgo_a->r = _cgo_r;\n")
+ // The return value is on the Go stack. If we are using msan,
+ // and if the C value is partially or completely uninitialized,
+ // the assignment will mark the Go stack as uninitialized.
+ // The Go compiler does not update msan for changes to the
+ // stack. It is possible that the stack will remain
+ // uninitialized, and then later be used in a way that is
+ // visible to msan, possibly leading to a false positive.
+ // Mark the stack space as written, to avoid this problem.
+ // See issue 26209.
+ fmt.Fprintf(fgcc, "\t_cgo_msan_write(&_cgo_a->r, sizeof(_cgo_a->r));\n")
}
if n.AddError {
fmt.Fprintf(fgcc, "\treturn _cgo_errno;\n")
@@ -708,12 +705,12 @@ func (p *Package) writeGccgoOutputFunc(fgcc *os.File, n *Name) {
fmt.Fprintf(fgcc, ")\n")
fmt.Fprintf(fgcc, "{\n")
if t := n.FuncType.Result; t != nil {
- fmt.Fprintf(fgcc, "\t%s r;\n", t.C.String())
+ fmt.Fprintf(fgcc, "\t%s _cgo_r;\n", t.C.String())
}
fmt.Fprintf(fgcc, "\t_cgo_tsan_acquire();\n")
fmt.Fprintf(fgcc, "\t")
if t := n.FuncType.Result; t != nil {
- fmt.Fprintf(fgcc, "r = ")
+ fmt.Fprintf(fgcc, "_cgo_r = ")
// Cast to void* to avoid warnings due to omitted qualifiers.
if c := t.C.String(); c[len(c)-1] == '*' {
fmt.Fprintf(fgcc, "(void*)")
@@ -739,7 +736,7 @@ func (p *Package) writeGccgoOutputFunc(fgcc *os.File, n *Name) {
if c := t.C.String(); c[len(c)-1] == '*' {
fmt.Fprintf(fgcc, "(void*)")
}
- fmt.Fprintf(fgcc, "r;\n")
+ fmt.Fprintf(fgcc, "_cgo_r;\n")
}
fmt.Fprintf(fgcc, "}\n")
fmt.Fprintf(fgcc, "\n")
@@ -748,7 +745,7 @@ func (p *Package) writeGccgoOutputFunc(fgcc *os.File, n *Name) {
// packedAttribute returns host compiler struct attribute that will be
// used to match gc's struct layout. For example, on 386 Windows,
// gcc wants to 8-align int64s, but gc does not.
-// Use __gcc_struct__ to work around http://gcc.gnu.org/PR52991 on x86,
+// Use __gcc_struct__ to work around https://gcc.gnu.org/PR52991 on x86,
// and https://golang.org/issue/5603.
func (p *Package) packedAttribute() string {
s := "__attribute__((__packed__"
@@ -763,7 +760,7 @@ func (p *Package) packedAttribute() string {
func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
p.writeExportHeader(fgcch)
- fmt.Fprintf(fgcc, "/* Created by cgo - DO NOT EDIT. */\n")
+ fmt.Fprintf(fgcc, "/* Code generated by cmd/cgo; DO NOT EDIT. */\n\n")
fmt.Fprintf(fgcc, "#include <stdlib.h>\n")
fmt.Fprintf(fgcc, "#include \"_cgo_export.h\"\n\n")
@@ -772,6 +769,7 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
fmt.Fprintf(fgcc, "extern void _cgo_release_context(__SIZE_TYPE__);\n\n")
fmt.Fprintf(fgcc, "extern char* _cgo_topofstack(void);")
fmt.Fprintf(fgcc, "%s\n", tsanProlog)
+ fmt.Fprintf(fgcc, "%s\n", msanProlog)
for _, exp := range p.ExpFunc {
fn := exp.Func
@@ -1004,11 +1002,12 @@ func (p *Package) writeGccgoExports(fgo2, fm, fgcc, fgcch io.Writer) {
p.writeExportHeader(fgcch)
- fmt.Fprintf(fgcc, "/* Created by cgo - DO NOT EDIT. */\n")
+ fmt.Fprintf(fgcc, "/* Code generated by cmd/cgo; DO NOT EDIT. */\n\n")
fmt.Fprintf(fgcc, "#include \"_cgo_export.h\"\n")
fmt.Fprintf(fgcc, "%s\n", gccgoExportFileProlog)
fmt.Fprintf(fgcc, "%s\n", tsanProlog)
+ fmt.Fprintf(fgcc, "%s\n", msanProlog)
for _, exp := range p.ExpFunc {
fn := exp.Func
@@ -1170,7 +1169,7 @@ func (p *Package) writeGccgoExports(fgo2, fm, fgcc, fgcch io.Writer) {
// writeExportHeader writes out the start of the _cgo_export.h file.
func (p *Package) writeExportHeader(fgcch io.Writer) {
- fmt.Fprintf(fgcch, "/* Created by \"go tool cgo\" - DO NOT EDIT. */\n\n")
+ fmt.Fprintf(fgcch, "/* Code generated by cmd/cgo; DO NOT EDIT. */\n\n")
pkg := *importPath
if pkg == "" {
pkg = p.PackagePath
@@ -1178,8 +1177,15 @@ func (p *Package) writeExportHeader(fgcch io.Writer) {
fmt.Fprintf(fgcch, "/* package %s */\n\n", pkg)
fmt.Fprintf(fgcch, "%s\n", builtinExportProlog)
+ // Remove absolute paths from #line comments in the preamble.
+ // They aren't useful for people using the header file,
+ // and they mean that the header files change based on the
+ // exact location of GOPATH.
+ re := regexp.MustCompile(`(?m)^(#line\s+[0-9]+\s+")[^"]*[/\\]([^"]*")`)
+ preamble := re.ReplaceAllString(p.Preamble, "$1$2")
+
fmt.Fprintf(fgcch, "/* Start of preamble from import \"C\" comments. */\n\n")
- fmt.Fprintf(fgcch, "%s\n", p.Preamble)
+ fmt.Fprintf(fgcch, "%s\n", preamble)
fmt.Fprintf(fgcch, "\n/* End of preamble from import \"C\" comments. */\n\n")
fmt.Fprintf(fgcch, "%s\n", p.gccExportHeaderProlog())
@@ -1414,6 +1420,25 @@ static void _cgo_tsan_release() {
// Set to yesTsanProlog if we see -fsanitize=thread in the flags for gcc.
var tsanProlog = noTsanProlog
+// noMsanProlog is a prologue defining an MSAN function in C.
+// This is used when not compiling with -fsanitize=memory.
+const noMsanProlog = `
+#define _cgo_msan_write(addr, sz)
+`
+
+// yesMsanProlog is a prologue defining an MSAN function in C.
+// This is used when compiling with -fsanitize=memory.
+// See the comment above where _cgo_msan_write is called.
+const yesMsanProlog = `
+extern void __msan_unpoison(const volatile void *, size_t);
+
+#define _cgo_msan_write(addr, sz) __msan_unpoison((addr), (sz))
+`
+
+// msanProlog is set to yesMsanProlog if we see -fsanitize=memory in the flags
+// for the C compiler.
+var msanProlog = noMsanProlog
+
const builtinProlog = `
#line 1 "cgo-builtin-prolog"
#include <stddef.h> /* for ptrdiff_t and size_t below */