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

cgo: unexpected panic when passing a pointer to slice contents to cgo function #15318

Closed
valyala opened this issue Apr 15, 2016 · 4 comments
Closed

Comments

@valyala
Copy link
Contributor

valyala commented Apr 15, 2016

Please answer these questions before submitting your issue. Thanks!

1. What version of Go are you using (go version)?

go version devel +89a1f02 Fri Apr 15 10:17:17 2016 +0000 linux/amd64

2. What operating system and processor architecture are you using (go env)?

GOARCH="amd64"
GOBIN=""
GOEXE=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOOS="linux"
GORACE=""
CC="gcc"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build118843672=/tmp/go-build -gno-record-gcc-switches"
CXX="g++"
CGO_ENABLED="1"

3. What did you do?

Run the following code:

package main

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

import (
        "encoding/json"
        "unsafe"
)

func main() {
        b, err := json.Marshal(123)
        if err != nil {
                panic(err)
        }
        // panic disappears if the following line is uncommented:
        // b = []byte("foobar")
        p := unsafe.Pointer(&b[0])
        C.foo(p)
}

4. What did you expect to see?

The program must complete without panics.

5. What did you see instead?

The following panic:

panic: runtime error: cgo argument has Go pointer to Go pointer

goroutine 1 [running]:
panic(0x4a0360, 0xc82000c3b0)
    /home/aliaksandr/work/go1.5/src/runtime/panic.go:500 +0x18a
main._cgoCheckPointer0(0x497be0, 0xc820084024, 0x0, 0x0, 0x0, 0x0)
    command-line-arguments/_obj/_cgo_gotypes.go:38 +0x49
main.main()
    /home/aliaksandr/work/ybc/1.go:17 +0xa9

This panic is reproducible on go 1.6 too - see valyala/ybc#14 for details.

@ianlancetaylor
Copy link
Member

This is a known deficiency in the current cgo pointer checker. To avoid it, write C.foo(unsafe.Pointer(&b[0])).

Closing as dup of #14210 .

@valyala
Copy link
Contributor Author

valyala commented Apr 15, 2016

@ianlancetaylor , are there workarounds for the following case?

package main


// struct bar { void *p; };
// static void foo(struct bar b) {}
import "C"

import (
        "encoding/json"
        "unsafe"
)

func main() {
        b, err := json.Marshal(123)
        if err != nil {
                panic(err)
        }
        var bar C.struct_bar
        // panic disappears if the following line is uncommented:
        // b = []byte("foobar")
        bar.p = unsafe.Pointer(&b[0])
        C.foo(bar)
}

@ianlancetaylor
Copy link
Member

What is messing up is that encoding/json uses a 64 byte buffer in a larger struct, and if the encoding requires 64 bytes or fewer than the resulting pointer is into that struct. So one workaround is

if len(b) <= 64 {
    b = append([]byte(nil), b...)
}
bar.p = unsafe.Pointer(&b[0])
C.foo(bar)

@valyala
Copy link
Contributor Author

valyala commented Apr 16, 2016

Thanks!

@golang golang locked and limited conversation to collaborators Apr 16, 2017
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

3 participants