]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/cgo: fix check for conversion of ptr to struct field
authorGernot Vormayr <gvormayr@gmail.com>
Sun, 7 Jul 2019 23:27:10 +0000 (01:27 +0200)
committerIan Lance Taylor <iant@golang.org>
Tue, 9 Jul 2019 19:21:43 +0000 (19:21 +0000)
According to the documentation "When passing a pointer to a field in a
struct, the Go memory in question is the memory occupied by the field,
not the entire struct.". checkAddr states that this should also work
with type conversions, which is implemented in isType. However,
ast.StarExpr must be enclosed in ast.ParenExpr according to the go spec
(see example below), which is not considered in the checks.

Example:
    // struct Si { int i; int *p; }; void f(struct I *x) {}
    import "C"
    type S {
        p *int
        i C.struct_Si
    }
    func main() {
        v := &S{new(int)}
        C.f((*C.struct_I)(&v.i)) // <- panic
    }

This example will cause cgo to emit a cgoCheck that checks the whole
struct S instead of just S.i causing the panic "cgo argument has Go
pointer to Go pointer".

This patch fixes this situation by adding support for ast.ParenExpr to
isType and adds a test, that fails without the fix.

Fixes #32970.

Change-Id: I15ea28c98f839e9fa708859ed107a2e5f1483133
Reviewed-on: https://go-review.googlesource.com/c/go/+/185098
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
misc/cgo/errors/ptr_test.go
src/cmd/cgo/gcc.go

index 522ef2adfd289da9d9712132a8c8dd061a813000..4a46b6023bb510ab70e146c80358b7f56bee5f52 100644 (file)
@@ -423,6 +423,15 @@ var ptrTests = []ptrTest{
                body:    `t := reflect.StructOf([]reflect.StructField{{Name: "MyInt38", Type: reflect.TypeOf(MyInt38(0)), Anonymous: true}}); v := reflect.New(t).Elem(); v.Interface().(Getter38).Get()`,
                fail:    false,
        },
+       {
+               // Test that a converted address of a struct field results
+               // in a check for just that field and not the whole struct.
+               name:    "structfieldcast",
+               c:       `struct S40i { int i; int* p; }; void f40(struct S40i* p) {}`,
+               support: `type S40 struct { p *int; a C.struct_S40i }`,
+               body:    `s := &S40{p: new(int)}; C.f40((*C.struct_S40i)(&s.a))`,
+               fail:    false,
+       },
 }
 
 func TestPointerChecks(t *testing.T) {
index d4e8186cab6adbda40a24cbf116abd01be39820c..1bd3e2417ca71e5030f4b93e70ed77c951aa1a43 100644 (file)
@@ -1239,6 +1239,8 @@ func (p *Package) isType(t ast.Expr) bool {
                if strings.HasPrefix(t.Name, "_Ctype_") {
                        return true
                }
+       case *ast.ParenExpr:
+               return p.isType(t.X)
        case *ast.StarExpr:
                return p.isType(t.X)
        case *ast.ArrayType, *ast.StructType, *ast.FuncType, *ast.InterfaceType,