golang / go

The Go programming language
https://go.dev
BSD 3-Clause "New" or "Revised" License
123.72k stars 17.63k forks source link

github.com/snej/zdelta-go: runtime error: cgo argument has Go pointer to Go pointer #28527

Closed nguoinaodo closed 5 years ago

nguoinaodo commented 5 years ago

Please answer these questions before submitting your issue. Thanks!

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

go version go1.8 linux/amd64

Does this issue reproduce with the latest release?

Yes

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

GOARCH="amd64" GOBIN="" GOEXE="" GOHOSTARCH="amd64" GOHOSTOS="linux" GOOS="linux" GOPATH="/home/ubuntu/dev/go" GORACE="" GOROOT="/usr/local/go" GOTOOLDIR="/usr/local/go/pkg/tool/linux_amd64" GCCGO="gccgo" CC="gcc" GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build585877189=/tmp/go-build -gno-record-gcc-switches" CXX="g++" CGO_ENABLED="1" PKG_CONFIG="pkg-config" CGO_CFLAGS="-g -O2" CGO_CPPFLAGS="" CGO_CXXFLAGS="-g -O2" CGO_FFLAGS="-g -O2" CGO_LDFLAGS="-g -O2"

What did you do?

package main

import (
    "github.com/snej/zdelta-go"
)

func main() {
    vers1 := []byte("Test delta compression vOne")
    vers2 := []byte("Test delta compression vTwo")
    delta, err := zdelta.CreateDelta(vers1, vers2)
    if err != nil {
        panic(err)
    }
    print(len(delta))
}

What did you expect to see?

Program to run normally and show length of delta.

What did you see instead?

Error output:

runtime error: cgo argument has Go pointer to Go pointer
...
panic(0x6ef4c0, 0xc4201ec040)
    /usr/local/go/src/runtime/panic.go:489 +0x2cf
github.com/snej/zdelta-go.zd_deflateInit.func1(0xc420240000, 0xffffffff, 0x7f1f100008c0, 0x90, 0x7f1f176f4e10)
    /home/ubuntu/dev/go/src/github.com/snej/zdelta-go/zdelta_utils.go:27 +0x52
github.com/snej/zdelta-go.zd_deflateInit(0xc420240000, 0xc4ffffffff, 0x411638)
    /home/ubuntu/dev/go/src/github.com/snej/zdelta-go/zdelta_utils.go:30 +0x63
github.com/snej/zdelta-go.(*Compressor).WriteDelta(0xc420240000, 0xc42021a000, 0x2315f, 0x24000, 0xc4201a0000, 0x2315f, 0x3fe00, 0xaca340, 0xc420246000, 0x0, ...)
    /home/ubuntu/dev/go/src/github.com/snej/zdelta-go/zdelta.go:127 +0xf0
github.com/snej/zdelta-go.(*Compressor).CreateDelta(0xc420240000, 0xc42021a000, 0x2315f, 0x24000, 0xc4201a0000, 0x2315f, 0x3fe00, 0x24000, 0xc42021a000, 0xc42004d9e8, ...)
    /home/ubuntu/dev/go/src/github.com/snej/zdelta-go/zdelta.go:156 +0xa5
github.com/snej/zdelta-go.CreateDelta(0xc42021a000, 0x2315f, 0x24000, 0xc4201a0000, 0x2315f, 0x3fe00, 0x1c, 0xc4201ee000, 0x28, 0xc4201ee030, ...)
    /home/ubuntu/dev/go/src/github.com/snej/zdelta-go/zdelta.go:222 +0xb8

This is the code block that cause the error:

func zd_deflateInit(strm C.zd_streamp, level C.int) C.int {
    vers := C.CString(C.ZDLIB_VERSION)
    rval := C.zd_deflateInit_(strm, level, vers, C.int(unsafe.Sizeof(*strm))) --> ERROR
    C.free(unsafe.Pointer(vers))
    return rval
}

This is the C.zd_streamp declaration I think it may help:

typedef struct zd_stream_s {
  Bytef    *next_in;  /* next input byte */
  uInt     avail_in;  /* number of bytes available at next_in */
  uLong    total_in;  /* total nb of input bytes read so far */

  Bytef    *next_out; /* next output byte should be put there */
  uInt     avail_out; /* remaining free space at next_out */
  uLong    total_out; /* total nb of bytes output so far */

  Bytef    *base[REFNUM];      /* pointer to the base window    */
  uLong    base_out[REFNUM];   /* total read bytes from the base window */
  uLong    base_avail[REFNUM];
  int      refnum;

  char     *msg;      /* last error message, NULL if no error */
  struct zd_internal_state FAR *state; /* not visible by applications */

  alloc_func zalloc;  /* used to allocate the internal state */
  free_func  zfree;   /* used to free the internal state */
  voidpf     opaque;  /* private data object passed to zalloc and zfree */

  int     data_type;  /* best guess about the data type: ascii or binary */
  uLong   adler;      /* adler32 value of the uncompressed data */
  uLong   reserved;   /* reserved for future use */

} zd_stream;

typedef zd_stream FAR *zd_streamp;
mattn commented 5 years ago

Go pointer can not be passed to C function as C pointer. Please look at setupStrm in zdeltago. This is changed in go1.6 specification. Note that it's not possible to pass Go pointer into C world even if it is defined as void* in C function.

For workaround, this possibly help you. https://github.com/mattn/go-pointer

ianlancetaylor commented 5 years ago

As far as I can tell, this is working as documented and intended. See https://golang.org/cmd/cgo/#hdr-Passing_pointers . Please comment if you disagree.