summaryrefslogtreecommitdiff
path: root/libgo/go/cmd/cgo
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/go/cmd/cgo')
-rw-r--r--libgo/go/cmd/cgo/ast.go3
-rw-r--r--libgo/go/cmd/cgo/doc.go50
-rw-r--r--libgo/go/cmd/cgo/gcc.go147
-rw-r--r--libgo/go/cmd/cgo/godefs.go2
-rw-r--r--libgo/go/cmd/cgo/main.go27
-rw-r--r--libgo/go/cmd/cgo/out.go103
-rw-r--r--libgo/go/cmd/cgo/util.go4
7 files changed, 272 insertions, 64 deletions
diff --git a/libgo/go/cmd/cgo/ast.go b/libgo/go/cmd/cgo/ast.go
index 58e0ee78cb7..4462136bf4b 100644
--- a/libgo/go/cmd/cgo/ast.go
+++ b/libgo/go/cmd/cgo/ast.go
@@ -95,7 +95,7 @@ func (f *File) ParseGo(name string, src []byte) {
}
}
if !sawC {
- error_(token.NoPos, `cannot find import "C"`)
+ error_(ast1.Package, `cannot find import "C"`)
}
// In ast2, strip the import "C" line.
@@ -356,6 +356,7 @@ func (f *File) walk(x interface{}, context astContext, visit func(*File, interfa
case *ast.BadExpr:
case *ast.Ident:
case *ast.Ellipsis:
+ f.walk(&n.Elt, ctxType, visit)
case *ast.BasicLit:
case *ast.FuncLit:
f.walk(n.Type, ctxType, visit)
diff --git a/libgo/go/cmd/cgo/doc.go b/libgo/go/cmd/cgo/doc.go
index c16b63a313b..157cd94d653 100644
--- a/libgo/go/cmd/cgo/doc.go
+++ b/libgo/go/cmd/cgo/doc.go
@@ -64,6 +64,11 @@ a full argument: to allow -mfoo=bar, use CGO_CFLAGS_ALLOW='-mfoo.*',
not just CGO_CFLAGS_ALLOW='-mfoo'. Similarly named variables control
the allowed CPPFLAGS, CXXFLAGS, FFLAGS, and LDFLAGS.
+Also for security reasons, only a limited set of characters are
+permitted, notably alphanumeric characters and a few symbols, such as
+'.', that will not be interpreted in unexpected ways. Attempts to use
+forbidden characters will get a "malformed #cgo argument" error.
+
When building, the CGO_CFLAGS, CGO_CPPFLAGS, CGO_CXXFLAGS, CGO_FFLAGS and
CGO_LDFLAGS environment variables are added to the flags derived from
these directives. Package-specific flags should be set using the
@@ -99,17 +104,24 @@ compiled with the C compiler. Any .cc, .cpp, or .cxx files will be
compiled with the C++ compiler. Any .f, .F, .for or .f90 files will be
compiled with the fortran compiler. Any .h, .hh, .hpp, or .hxx files will
not be compiled separately, but, if these header files are changed,
-the C and C++ files will be recompiled. The default C and C++
-compilers may be changed by the CC and CXX environment variables,
-respectively; those environment variables may include command line
-options.
+the package (including its non-Go source files) will be recompiled.
+Note that changes to files in other directories do not cause the package
+to be recompiled, so all non-Go source code for the package should be
+stored in the package directory, not in subdirectories.
+The default C and C++ compilers may be changed by the CC and CXX
+environment variables, respectively; those environment variables
+may include command line options.
The cgo tool is enabled by default for native builds on systems where
it is expected to work. It is disabled by default when
cross-compiling. You can control this by setting the CGO_ENABLED
environment variable when running the go tool: set it to 1 to enable
the use of cgo, and to 0 to disable it. The go tool will set the
-build constraint "cgo" if cgo is enabled.
+build constraint "cgo" if cgo is enabled. The special import "C"
+implies the "cgo" build constraint, as though the file also said
+"// +build cgo". Therefore, if cgo is disabled, files that import
+"C" will not be built by the go tool. (For more about build constraints
+see https://golang.org/pkg/go/build/#hdr-Build_Constraints).
When cross-compiling, you must specify a C cross-compiler for cgo to
use. You can do this by setting the generic CC_FOR_TARGET or the
@@ -219,6 +231,26 @@ C compilers are aware of this calling convention and adjust
the call accordingly, but Go cannot. In Go, you must pass
the pointer to the first element explicitly: C.f(&C.x[0]).
+Calling variadic C functions is not supported. It is possible to
+circumvent this by using a C function wrapper. For example:
+
+ package main
+
+ // #include <stdio.h>
+ // #include <stdlib.h>
+ //
+ // static void myprint(char* s) {
+ // printf("%s\n", s);
+ // }
+ import "C"
+ import "unsafe"
+
+ func main() {
+ cs := C.CString("Hello from stdio")
+ C.myprint(cs)
+ C.free(unsafe.Pointer(cs))
+ }
+
A few special functions convert between Go and C types
by making copies of the data. In pseudo-Go definitions:
@@ -348,6 +380,14 @@ and of course there is nothing stopping the C code from doing anything
it likes. However, programs that break these rules are likely to fail
in unexpected and unpredictable ways.
+Note: the current implementation has a bug. While Go code is permitted
+to write nil or a C pointer (but not a Go pointer) to C memory, the
+current implementation may sometimes cause a runtime error if the
+contents of the C memory appear to be a Go pointer. Therefore, avoid
+passing uninitialized C memory to Go code if the Go code is going to
+store pointer values in it. Zero out the memory in C before passing it
+to Go.
+
Special cases
A few special C types which would normally be represented by a pointer
diff --git a/libgo/go/cmd/cgo/gcc.go b/libgo/go/cmd/cgo/gcc.go
index 534fba17eb4..2a2d0080d5e 100644
--- a/libgo/go/cmd/cgo/gcc.go
+++ b/libgo/go/cmd/cgo/gcc.go
@@ -183,9 +183,29 @@ func (p *Package) Translate(f *File) {
cref.Name.C = cname(cref.Name.Go)
}
p.loadDefines(f)
- needType := p.guessKinds(f)
- if len(needType) > 0 {
- p.loadDWARF(f, needType)
+ p.typedefs = map[string]bool{}
+ p.typedefList = nil
+ numTypedefs := -1
+ for len(p.typedefs) > numTypedefs {
+ numTypedefs = len(p.typedefs)
+ // Also ask about any typedefs we've seen so far.
+ for _, a := range p.typedefList {
+ f.Name[a] = &Name{
+ Go: a,
+ C: a,
+ }
+ }
+ needType := p.guessKinds(f)
+ if len(needType) > 0 {
+ p.loadDWARF(f, needType)
+ }
+
+ // In godefs mode we're OK with the typedefs, which
+ // will presumably also be defined in the file, we
+ // don't want to resolve them to their base types.
+ if *godefs {
+ break
+ }
}
if p.rewriteCalls(f) {
// Add `import _cgo_unsafe "unsafe"` after the package statement.
@@ -570,6 +590,7 @@ func (p *Package) loadDWARF(f *File, names []*Name) {
fatalf("malformed __cgo__ name: %s", name)
}
types[i] = t.Type
+ p.recordTypedefs(t.Type)
}
if e.Tag != dwarf.TagCompileUnit {
r.SkipChildren()
@@ -605,7 +626,25 @@ func (p *Package) loadDWARF(f *File, names []*Name) {
}
}
case "fconst":
- if i < len(floats) {
+ if i >= len(floats) {
+ break
+ }
+ switch base(types[i]).(type) {
+ case *dwarf.IntType, *dwarf.UintType:
+ // This has an integer type so it's
+ // not really a floating point
+ // constant. This can happen when the
+ // C compiler complains about using
+ // the value as an integer constant,
+ // but not as a general constant.
+ // Treat this as a variable of the
+ // appropriate type, not a constant,
+ // to get C-style type handling,
+ // avoiding the problem that C permits
+ // uint64(-1) but Go does not.
+ // See issue 26066.
+ n.Kind = "var"
+ default:
n.Const = fmt.Sprintf("%f", floats[i])
}
case "sconst":
@@ -618,6 +657,47 @@ func (p *Package) loadDWARF(f *File, names []*Name) {
}
}
+// recordTypedefs remembers in p.typedefs all the typedefs used in dtypes and its children.
+func (p *Package) recordTypedefs(dtype dwarf.Type) {
+ p.recordTypedefs1(dtype, map[dwarf.Type]bool{})
+}
+func (p *Package) recordTypedefs1(dtype dwarf.Type, visited map[dwarf.Type]bool) {
+ if dtype == nil {
+ return
+ }
+ if visited[dtype] {
+ return
+ }
+ visited[dtype] = true
+ switch dt := dtype.(type) {
+ case *dwarf.TypedefType:
+ if strings.HasPrefix(dt.Name, "__builtin") {
+ // Don't look inside builtin types. There be dragons.
+ return
+ }
+ if !p.typedefs[dt.Name] {
+ p.typedefs[dt.Name] = true
+ p.typedefList = append(p.typedefList, dt.Name)
+ p.recordTypedefs1(dt.Type, visited)
+ }
+ case *dwarf.PtrType:
+ p.recordTypedefs1(dt.Type, visited)
+ case *dwarf.ArrayType:
+ p.recordTypedefs1(dt.Type, visited)
+ case *dwarf.QualType:
+ p.recordTypedefs1(dt.Type, visited)
+ case *dwarf.FuncType:
+ p.recordTypedefs1(dt.ReturnType, visited)
+ for _, a := range dt.ParamType {
+ p.recordTypedefs1(a, visited)
+ }
+ case *dwarf.StructType:
+ for _, f := range dt.Field {
+ p.recordTypedefs1(f.Type, visited)
+ }
+ }
+}
+
// mangleName does name mangling to translate names
// from the original Go source files to the names
// used in the final Go files generated by cgo.
@@ -1373,7 +1453,7 @@ func (p *Package) gccDebug(stdin []byte, nnames int) (d *dwarf.Data, ints []int6
if len(data) <= strlen {
fatalf("invalid string literal")
}
- strs[n] = string(data[:strlen])
+ strs[n] = data[:strlen]
}
}
@@ -1754,6 +1834,7 @@ type typeConv struct {
// Map from types to incomplete pointers to those types.
ptrs map[dwarf.Type][]*Type
// Keys of ptrs in insertion order (deterministic worklist)
+ // ptrKeys contains exactly the keys in ptrs.
ptrKeys []dwarf.Type
// Type names X for which there exists an XGetTypeID function with type func() CFTypeID.
@@ -1896,14 +1977,15 @@ func (c *typeConv) FinishType(pos token.Pos) {
for len(c.ptrKeys) > 0 {
dtype := c.ptrKeys[0]
c.ptrKeys = c.ptrKeys[1:]
+ ptrs := c.ptrs[dtype]
+ delete(c.ptrs, dtype)
// Note Type might invalidate c.ptrs[dtype].
t := c.Type(dtype, pos)
- for _, ptr := range c.ptrs[dtype] {
+ for _, ptr := range ptrs {
ptr.Go.(*ast.StarExpr).X = t.Go
ptr.C.Set("%s*", t.C)
}
- c.ptrs[dtype] = nil // retain the map key
}
}
@@ -2180,6 +2262,10 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
s := *sub
s.Go = c.uintptr
sub = &s
+ // Make sure we update any previously computed type.
+ if oldType := typedef[name.Name]; oldType != nil {
+ oldType.Go = sub.Go
+ }
}
t.Go = name
if unionWithPointer[sub.Go] {
@@ -2341,7 +2427,7 @@ func (c *typeConv) FuncArg(dtype dwarf.Type, pos token.Pos) *Type {
}
// ...or the typedef is one in which we expect bad pointers.
// It will be a uintptr instead of *X.
- if c.badPointerTypedef(dt) {
+ if c.baseBadPointerTypedef(dt) {
break
}
@@ -2693,6 +2779,19 @@ func (c *typeConv) badPointerTypedef(dt *dwarf.TypedefType) bool {
return false
}
+// baseBadPointerTypedef reports whether the base of a chain of typedefs is a bad typedef
+// as badPointerTypedef reports.
+func (c *typeConv) baseBadPointerTypedef(dt *dwarf.TypedefType) bool {
+ for {
+ if t, ok := dt.Type.(*dwarf.TypedefType); ok {
+ dt = t
+ continue
+ }
+ break
+ }
+ return c.badPointerTypedef(dt)
+}
+
func (c *typeConv) badCFType(dt *dwarf.TypedefType) bool {
// The real bad types are CFNumberRef and CFDateRef.
// Sometimes non-pointers are stored in these types.
@@ -2781,13 +2880,31 @@ func (c *typeConv) badJNI(dt *dwarf.TypedefType) bool {
}
}
- // Check that the typedef is:
- // struct _jobject;
- // typedef struct _jobject *jobject;
+ // Check that the typedef is either:
+ // 1:
+ // struct _jobject;
+ // typedef struct _jobject *jobject;
+ // 2: (in NDK16 in C++)
+ // class _jobject {};
+ // typedef _jobject* jobject;
+ // 3: (in NDK16 in C)
+ // typedef void* jobject;
if ptr, ok := w.Type.(*dwarf.PtrType); ok {
- if str, ok := ptr.Type.(*dwarf.StructType); ok {
- if str.StructName == "_jobject" && str.Kind == "struct" && len(str.Field) == 0 && str.Incomplete {
- return true
+ switch v := ptr.Type.(type) {
+ case *dwarf.VoidType:
+ return true
+ case *dwarf.StructType:
+ if v.StructName == "_jobject" && len(v.Field) == 0 {
+ switch v.Kind {
+ case "struct":
+ if v.Incomplete {
+ return true
+ }
+ case "class":
+ if !v.Incomplete {
+ return true
+ }
+ }
}
}
}
@@ -2796,7 +2913,7 @@ func (c *typeConv) badJNI(dt *dwarf.TypedefType) bool {
}
// jniTypes maps from JNI types that we want to be uintptrs, to the underlying type to which
-// they are mapped. The base "jobject" maps to the empty string.
+// they are mapped. The base "jobject" maps to the empty string.
var jniTypes = map[string]string{
"jobject": "",
"jclass": "jobject",
diff --git a/libgo/go/cmd/cgo/godefs.go b/libgo/go/cmd/cgo/godefs.go
index 6d638f06442..6720945cddd 100644
--- a/libgo/go/cmd/cgo/godefs.go
+++ b/libgo/go/cmd/cgo/godefs.go
@@ -19,7 +19,7 @@ import (
func (p *Package) godefs(f *File, srcfile string) string {
var buf bytes.Buffer
- fmt.Fprintf(&buf, "// Created by cgo -godefs - DO NOT EDIT\n")
+ fmt.Fprintf(&buf, "// Code generated by cmd/cgo -godefs; DO NOT EDIT.\n")
fmt.Fprintf(&buf, "// %s %s\n", filepath.Base(os.Args[0]), strings.Join(os.Args[1:], " "))
fmt.Fprintf(&buf, "\n")
diff --git a/libgo/go/cmd/cgo/main.go b/libgo/go/cmd/cgo/main.go
index 890a365ceef..1238016418e 100644
--- a/libgo/go/cmd/cgo/main.go
+++ b/libgo/go/cmd/cgo/main.go
@@ -17,6 +17,7 @@ import (
"go/ast"
"go/printer"
"go/token"
+ "io"
"io/ioutil"
"os"
"path/filepath"
@@ -42,9 +43,11 @@ type Package struct {
Name map[string]*Name // accumulated Name from Files
ExpFunc []*ExpFunc // accumulated ExpFunc from Files
Decl []ast.Decl
- GoFiles []string // list of Go files
- GccFiles []string // list of gcc output files
- Preamble string // collected preamble for _cgo_export.h
+ GoFiles []string // list of Go files
+ GccFiles []string // list of gcc output files
+ Preamble string // collected preamble for _cgo_export.h
+ typedefs map[string]bool // type names that appear in the types of the objects we're interested in
+ typedefList []string
}
// A File collects information about a single Go input file.
@@ -278,6 +281,9 @@ func main() {
if arg == "-fsanitize=thread" {
tsanProlog = yesTsanProlog
}
+ if arg == "-fsanitize=memory" {
+ msanProlog = yesMsanProlog
+ }
}
p := newPackage(args[:i])
@@ -297,6 +303,7 @@ func main() {
// concern is other cgo wrappers for the same functions.
// Use the beginning of the md5 of the input to disambiguate.
h := md5.New()
+ io.WriteString(h, *importPath)
fs := make([]*File, len(goFiles))
for i, input := range goFiles {
if *srcDir != "" {
@@ -410,6 +417,14 @@ func (p *Package) Record(f *File) {
for k, v := range f.Name {
if p.Name[k] == nil {
p.Name[k] = v
+ } else if p.incompleteTypedef(p.Name[k].Type) {
+ p.Name[k] = v
+ } else if p.incompleteTypedef(v.Type) {
+ // Nothing to do.
+ } else if _, ok := nameToC[k]; ok {
+ // Names we predefine may appear inconsistent
+ // if some files typedef them and some don't.
+ // Issue 26743.
} else if !reflect.DeepEqual(p.Name[k], v) {
error_(token.NoPos, "inconsistent definitions for C.%s", fixGo(k))
}
@@ -422,3 +437,9 @@ func (p *Package) Record(f *File) {
}
p.Decl = append(p.Decl, f.AST.Decls...)
}
+
+// incompleteTypedef reports whether t appears to be an incomplete
+// typedef definition.
+func (p *Package) incompleteTypedef(t *Type) bool {
+ return t == nil || (t.Size == 0 && t.Align == -1)
+}
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 */
diff --git a/libgo/go/cmd/cgo/util.go b/libgo/go/cmd/cgo/util.go
index 4f5c48864e9..921306b7aab 100644
--- a/libgo/go/cmd/cgo/util.go
+++ b/libgo/go/cmd/cgo/util.go
@@ -59,6 +59,8 @@ func run(stdin []byte, argv []string) (stdout, stderr []byte, ok bool) {
var bout, berr bytes.Buffer
p.Stdout = &bout
p.Stderr = &berr
+ // Disable escape codes in clang error messages.
+ p.Env = append(os.Environ(), "TERM=dumb")
err := p.Run()
if _, ok := err.(*exec.ExitError); err != nil && !ok {
fatalf("%s", err)
@@ -97,6 +99,8 @@ func error_(pos token.Pos, msg string, args ...interface{}) {
nerrors++
if pos.IsValid() {
fmt.Fprintf(os.Stderr, "%s: ", fset.Position(pos).String())
+ } else {
+ fmt.Fprintf(os.Stderr, "cgo: ")
}
fmt.Fprintf(os.Stderr, msg, args...)
fmt.Fprintf(os.Stderr, "\n")