Skip to content

Instantly share code, notes, and snippets.

@jtolio
Last active August 29, 2015 14:22
Show Gist options
  • Save jtolio/83a8cf059d496586709f to your computer and use it in GitHub Desktop.
Save jtolio/83a8cf059d496586709f to your computer and use it in GitHub Desktop.
Temporary fix for Go issue #10303 against Go 1.4.2
diff --git a/api/go1.4.txt b/api/go1.4.txt
index 08cb17f..9101909 100644
--- a/api/go1.4.txt
+++ b/api/go1.4.txt
@@ -389,6 +389,9 @@ pkg sync/atomic, method (*Value) Load() interface{}
pkg sync/atomic, method (*Value) Store(interface{})
pkg sync/atomic, type Value struct
+# Fixing Go issue 10303
+# This is absolutely the wrong place to put this. It shouldn't be in
+# syscall and it shouldn't be exported. I failed to get go:linkname
+# to work, so here we are, in a puddle of my incompetence.
+pkg syscall, func CgoUse(unsafe.Pointer)
+
# CL 126190043 syscall: support UID/GID map files for Linux user namespaces, Mrunal Patel <[email protected]>
pkg syscall (linux-386), type SysProcAttr struct, GidMappings []SysProcIDMap
pkg syscall (linux-386), type SysProcAttr struct, UidMappings []SysProcIDMap
diff --git a/src/cmd/cgo/gcc.go b/src/cmd/cgo/gcc.go
index abdd369..10d8c42 100644
--- a/src/cmd/cgo/gcc.go
+++ b/src/cmd/cgo/gcc.go
@@ -1094,6 +1094,27 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
c.m[dtype] = t
switch dt := dtype.(type) {
+ case *dwarf.BoolType, *dwarf.CharType, *dwarf.EnumType, *dwarf.FloatType,
+ *dwarf.ComplexType, *dwarf.IntType, *dwarf.UcharType, *dwarf.UintType:
+ t.ByValue = true
+ case *dwarf.StructType:
+ // TODO: is this the right thing to do? what if the struct has pointers?
+ // needed for some tests.
+ t.ByValue = true
+ case *dwarf.TypedefType:
+ switch dt.Name {
+ case "_GoString_", "_GoBytes_":
+ // no
+ default:
+ // should we really just turn all C types into byvalue types? if we
+ // whitelist here we have to whitelist stuff like socklen_t, size_t,
+ // __uid_t, etc.
+ // maybe the field "ByValue" itself is named wrong, and it should really
+ // be named "HeapEscapeUnecessary" or "OkayToMoveAround" or something.
+ t.ByValue = true
+ }
+ }
+
+ switch dt := dtype.(type) {
default:
fatalf("%s: unexpected type: %s", lineno(pos), dtype)
diff --git a/src/cmd/cgo/main.go b/src/cmd/cgo/main.go
index 17b0cdd..388a952 100644
--- a/src/cmd/cgo/main.go
+++ b/src/cmd/cgo/main.go
@@ -114,6 +114,7 @@ type Type struct {
Go ast.Expr
EnumValues map[string]int64
Typedef string
+ ByValue bool // true if the value passed to C avoids memory references
}
// A FuncType collects information about a function type in both the C and Go worlds.
diff --git a/src/cmd/cgo/out.go b/src/cmd/cgo/out.go
index d92bed9..b491edf 100644
--- a/src/cmd/cgo/out.go
+++ b/src/cmd/cgo/out.go
@@ -15,11 +15,29 @@ import (
"go/token"
"os"
"sort"
+ "strconv"
"strings"
)
var conf = printer.Config{Mode: printer.SourcePos, Tabwidth: 8}
+var (
+ // This allows you to set OUTPUT_UNESCAPED_CGO=1 in the environment during
+ // a build and find out if we're not forcing something to the heap we should
+ // be, or vice versa with OUTPUT_ESCAPED_CGO=1
+ outputUnescapedCgo = getEnv("OUTPUT_UNESCAPED_CGO")
+ outputEscapedCgo = getEnv("OUTPUT_ESCAPED_CGO")
+)
+
+func getEnv(name string) bool {
+ env := os.Getenv(name)
+ if env == "" {
+ return false
+ }
+ rv, err := strconv.ParseBool(env)
+ if err != nil {
+ panic(err)
+ }
+ return rv
+}
+
// writeDefs creates output files to be compiled by 6g, 6c, and gcc.
// (The comments here say 6g and 6c but the code applies to the 8 and 5 tools too.)
func (p *Package) writeDefs() {
@@ -65,6 +83,7 @@ func (p *Package) writeDefs() {
if *importSyscall {
fmt.Fprintf(fgo2, "import \"syscall\"\n\n")
fmt.Fprintf(fgo2, "var _ syscall.Errno\n")
+ fmt.Fprintf(fgo2, "var _Cgo_use = syscall.CgoUse\n\n")
}
fmt.Fprintf(fgo2, "func _Cgo_ptr(ptr unsafe.Pointer) unsafe.Pointer { return ptr }\n\n")
@@ -432,10 +451,73 @@ func (p *Package) writeDefsFunc(fc, fgo2 *os.File, n *Name) {
if n.AddError {
fmt.Fprintf(fgo2, "\tif errno != 0 { r2 = syscall.Errno(errno) }\n")
}
+ for i, param := range d.Type.Params.List {
+ if !p.byValue(param.Type) {
+ if outputEscapedCgo {
+ fmt.Printf("type %#v forced to heap in %s\n", param.Type, name)
+ }
+ fmt.Fprintf(fgo2, "\t_Cgo_use(unsafe.Pointer(p%d))\n", i)
+ } else if outputUnescapedCgo {
+ fmt.Printf("type %#v not forced to heap in %s\n", param.Type, name)
+ }
+ }
fmt.Fprintf(fgo2, "\treturn\n")
fmt.Fprintf(fgo2, "}\n")
}
+// byValue returns true if this type avoids memory references
+func (p *Package) byValue(e ast.Expr) bool {
+ switch t := e.(type) {
+ case *ast.ArrayType:
+ if t.Len == nil {
+ // it's a slice
+ return false
+ }
+ case *ast.StructType:
+ // TODO
+ case *ast.StarExpr, *ast.FuncType, *ast.InterfaceType, *ast.MapType,
+ *ast.ChanType:
+ return false
+ case *ast.Ident:
+ // Look up the type in the top level declarations.
+ // TODO: Handle types defined within a function.
+ for _, d := range p.Decl {
+ gd, ok := d.(*ast.GenDecl)
+ if !ok || gd.Tok != token.TYPE {
+ continue
+ }
+ for _, spec := range gd.Specs {
+ ts, ok := spec.(*ast.TypeSpec)
+ if !ok {
+ continue
+ }
+ if ts.Name.Name == t.Name {
+ return p.byValue(ts.Type)
+ }
+ }
+ }
+ if def := typedef[t.Name]; def != nil {
+ return def.ByValue
+ }
+ switch t.Name {
+ case "uintptr", "string", "error", "unsafe.Pointer":
+ return false
+ }
+ if r, ok := goTypes[t.Name]; ok {
+ return r.ByValue
+ }
+ error_(e.Pos(), "unrecognized Go type %s", t.Name)
+ return false
+ case *ast.SelectorExpr:
+ id, ok := t.X.(*ast.Ident)
+ if ok && id.Name == "unsafe" && t.Sel.Name == "Pointer" {
+ return false
+ }
+ }
+ error_(e.Pos(), "Go type not supported here: %s", gofmt(e))
+ return false
+}
+
// writeOutput creates stubs for a specific source file to be compiled by 6g
// (The comments here say 6g and 6c but the code applies to the 8 and 5 tools too.)
func (p *Package) writeOutput(f *File, srcfile string) {
@@ -1030,23 +1112,23 @@ func c(repr string, args ...interface{}) *TypeRepr {
// Map predeclared Go types to Type.
var goTypes = map[string]*Type{
- "bool": {Size: 1, Align: 1, C: c("GoUint8")},
- "byte": {Size: 1, Align: 1, C: c("GoUint8")},
- "int": {Size: 0, Align: 0, C: c("GoInt")},
- "uint": {Size: 0, Align: 0, C: c("GoUint")},
- "rune": {Size: 4, Align: 4, C: c("GoInt32")},
- "int8": {Size: 1, Align: 1, C: c("GoInt8")},
- "uint8": {Size: 1, Align: 1, C: c("GoUint8")},
- "int16": {Size: 2, Align: 2, C: c("GoInt16")},
- "uint16": {Size: 2, Align: 2, C: c("GoUint16")},
- "int32": {Size: 4, Align: 4, C: c("GoInt32")},
- "uint32": {Size: 4, Align: 4, C: c("GoUint32")},
- "int64": {Size: 8, Align: 8, C: c("GoInt64")},
- "uint64": {Size: 8, Align: 8, C: c("GoUint64")},
- "float32": {Size: 4, Align: 4, C: c("GoFloat32")},
- "float64": {Size: 8, Align: 8, C: c("GoFloat64")},
- "complex64": {Size: 8, Align: 8, C: c("GoComplex64")},
- "complex128": {Size: 16, Align: 16, C: c("GoComplex128")},
+ "bool": {Size: 1, Align: 1, C: c("GoUint8"), ByValue: true},
+ "byte": {Size: 1, Align: 1, C: c("GoUint8"), ByValue: true},
+ "int": {Size: 0, Align: 0, C: c("GoInt"), ByValue: true},
+ "uint": {Size: 0, Align: 0, C: c("GoUint"), ByValue: true},
+ "rune": {Size: 4, Align: 4, C: c("GoInt32"), ByValue: true},
+ "int8": {Size: 1, Align: 1, C: c("GoInt8"), ByValue: true},
+ "uint8": {Size: 1, Align: 1, C: c("GoUint8"), ByValue: true},
+ "int16": {Size: 2, Align: 2, C: c("GoInt16"), ByValue: true},
+ "uint16": {Size: 2, Align: 2, C: c("GoUint16"), ByValue: true},
+ "int32": {Size: 4, Align: 4, C: c("GoInt32"), ByValue: true},
+ "uint32": {Size: 4, Align: 4, C: c("GoUint32"), ByValue: true},
+ "int64": {Size: 8, Align: 8, C: c("GoInt64"), ByValue: true},
+ "uint64": {Size: 8, Align: 8, C: c("GoUint64"), ByValue: true},
+ "float32": {Size: 4, Align: 4, C: c("GoFloat32"), ByValue: true},
+ "float64": {Size: 8, Align: 8, C: c("GoFloat64"), ByValue: true},
+ "complex64": {Size: 8, Align: 8, C: c("GoComplex64"), ByValue: true},
+ "complex128": {Size: 16, Align: 16, C: c("GoComplex128"), ByValue: true},
}
// Map an ast type to a Type.
diff --git a/src/syscall/cgo.go b/src/syscall/cgo.go
new file mode 100644
index 0000000..6f7b4cc
--- /dev/null
+++ b/src/syscall/cgo.go
@@ -0,0 +1,5 @@
+package syscall
+
+import "unsafe"
+
+func CgoUse(unsafe.Pointer)
diff --git a/src/syscall/cgoasm.s b/src/syscall/cgoasm.s
new file mode 100644
index 0000000..11497bd
--- /dev/null
+++ b/src/syscall/cgoasm.s
@@ -0,0 +1,4 @@
+#include "textflag.h"
+
+TEXT ·CgoUse(SB),NOSPLIT,$0
+ RET
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment