Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cmd/cgo: false cgo "Go pointer to Go pointer" #18184

Closed
Cubixmeister opened this issue Dec 3, 2016 · 1 comment

Comments

@Cubixmeister
Copy link

commented Dec 3, 2016

Cgo panics if C function is called with pointer to []byte assigned to interface{} variable.
I've tested it with simple function returning []byte in same package, but error does not occur.

package main

/*
static void _test_ptr(void *p) {}
*/
import "C"

import (
    "encoding/json"
    "fmt"
    "unsafe"
)

func main() {
    var err error
    var val interface{}
    val, err = json.Marshal(struct{ A, B int }{1, 2})
    if err != nil {
        fmt.Println("marshal error:", err)
        return
    }

    // crashes
    var b = val.([]byte)
    var p *byte
    p = &b[0]
    C._test_ptr(unsafe.Pointer(p))

    // works
    var copied = append([]byte(nil), b...)
    p = &copied[0]
    C._test_ptr(unsafe.Pointer(p))
}

run:

$ go run crashtest.go 
panic: runtime error: cgo argument has Go pointer to Go pointer

goroutine 1 [running]:
panic(0x40af460, 0xc4200782c0)
    /usr/local/Cellar/go/1.7.4/libexec/src/runtime/panic.go:500 +0x1a1
main._cgoCheckPointer0(0xc42009e024, 0x0, 0x0, 0x0, 0xc42009c120)
    command-line-arguments/_obj/_cgo_gotypes.go:35 +0x59
main.main()
    /tmp/crashtest.go:28 +0x280
exit status 2

env:

$ go version
go version go1.7.4 darwin/amd64

$ go env
GOARCH="amd64"
GOBIN=""
GOEXE=""
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GOOS="darwin"
GOPATH="/Users/cubix/Developing/godaemon/"
GORACE=""
GOROOT="/usr/local/Cellar/go/1.7.4/libexec"
GOTOOLDIR="/usr/local/Cellar/go/1.7.4/libexec/pkg/tool/darwin_amd64"
CC="clang"
GOGCCFLAGS="-fPIC -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/5w/7t9m60w12390mjlr63qvxg1h0000gn/T/go-build441330328=/tmp/go-build -gno-record-gcc-switches -fno-common"
CXX="clang++"
CGO_ENABLED="1"

@ianlancetaylor ianlancetaylor changed the title cmd/go: false cgo "Go pointer to Go pointer" cmd/cgo: false cgo "Go pointer to Go pointer" Dec 5, 2016

@ianlancetaylor

This comment has been minimized.

Copy link
Contributor

commented Dec 5, 2016

This is essentially a duplicate of #14210. The problem is that json.Marshal returns a slice that points into scratch space stored in a larger struct (json.encodeState). When you set p = &b[0] in a statement separate from the call to the cgo function, the cgo command is not smart enough to see that you are passing the address of a slice element to the C function. Since it doesn't see that, it assumes that the argument points to the entire heap block, and the entire heap block does contain a pointer.

A simple workaround until cgo is fixed is to change

C._test_ptr(unsafe.Pointer(p))

to

C._test_ptr(unsafe.Pointer(&b[0]))

That will let cgo see that you are passing the address of a slice element and that it should only check the slice, not the entire heap block.

Closing as dup of #14210.

@golang golang locked and limited conversation to collaborators Dec 5, 2017

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
3 participants
You can’t perform that action at this time.