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: pointer checking fails on pointer to pointers (representing slice of slices) #42844

Closed
elichai opened this issue Nov 26, 2020 · 7 comments

Comments

@elichai
Copy link

elichai commented Nov 26, 2020

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

$ go version
go version go1.15.5 linux/amd64

Does this issue reproduce with the latest release?

Yes

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

go env Output
$ go env
GO111MODULE=""
GOARCH="amd64"
GOBIN=""
GOCACHE="/home/elichai2/.cache/go-build"
GOENV="/home/elichai2/.config/go/env"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOINSECURE=""
GOMODCACHE="/home/elichai2/go/pkg/mod"
GONOPROXY=""
GONOSUMDB=""
GOOS="linux"
GOPATH="/home/elichai2/go"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/usr/lib/go"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/usr/lib/go/pkg/tool/linux_amd64"
GCCGO="gccgo"
AR="ar"
CC="clang"
CXX="clang++"
CGO_ENABLED="1"
GOMOD="/home/elichai2/gits/go-test/go.mod"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build414451051=/tmp/go-build -gno-record-gcc-switches"

What did you do?

package main

// size_t test_slices(const unsigned char **inputs, const size_t *sizes, size_t amount) {
//   size_t sum = 0, i,j;
//   for(i = 0; i < amount; i++) {
//     for (j = 0; j < sizes[i]; j++) {
//       sum += inputs[i][j];
//     }
//   }
//  return sum;
//}
import "C"
import "fmt"

func test_slices(slices ...[]byte) int {
	lens := make([]C.size_t, len(slices))
	ptrs := make([]*C.uchar, len(slices))
	for i, _ := range slices {
		lens[i] = (C.size_t)(len(slices[i]))
		ptrs[i] = (*C.uchar)(&slices[i][0])
	}
	cPtrInputs := (**C.uchar)(&ptrs[0])
	cSizesPtr := (*C.size_t)(&lens[0])
	cAmounts := (C.size_t)(len(slices))
	res := C.test_slices(cPtrInputs, cSizesPtr, cAmounts)
	return int(res)

}

func main() {
	a := [][]byte{{1, 2, 3}, {4, 5, 6}, {1, 2, 3}}
	res := test_slices(a...)

	var sum int
	for _, outer := range a {
		for _, inner := range outer {
			sum += int(inner)
		}
	}
	if sum != res {
		panic(fmt.Sprintf("Expected %d, found: %d", sum, res))
	}
}

What did you expect to see?

I expected the code to work, and it does work correctly without cgo checks GODEBUG=cgocheck=0 go run .

What did you see instead?

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

goroutine 1 [running]:
main.test_slices.func1(0xc00012c020, 0xc00013a000, 0x3, 0xc00012c020)
        /home/elichai2/gits/go-test/main.go:25 +0x3f
main.test_slices(0xc000064f30, 0x3, 0x3, 0xc000064f18)
        /home/elichai2/gits/go-test/main.go:25 +0xdf
main.main()
        /home/elichai2/gits/go-test/main.go:32 +0x125
exit status 2
@elichai elichai changed the title cmd/cgo: pointer checking fails on pointer of pointers (representing slice of slices) cmd/cgo: pointer checking fails on pointer to pointers (representing slice of slices) Nov 26, 2020
@ALTree
Copy link
Member

ALTree commented Nov 26, 2020

I expected the code to work

Why? The code violates cgo rules, the checker warning seems correct to me.

cgo Rules § Passing Pointers:

Go code may pass a Go pointer to C provided the Go memory to which it points does not contain any Go pointers.

@elichai
Copy link
Author

elichai commented Nov 26, 2020

Go code may pass a Go pointer to C provided the Go memory to which it points does not contain any Go pointers.

This line does seem to forbid what I'm trying to do
But is this restriction necessary? If I'm allowed to pass a Go pointer to C, why am I not allowed to pass an array of Go pointers to C?

and if so, is the only way to do this is manually allocate C memory(C.malloc) and copy all the data into C arrays? and then pass a C/Go pointer to an array of C pointers?

@ALTree
Copy link
Member

ALTree commented Nov 26, 2020

We don't really use the bug tracker for general discussion or asking questions about the language. The Github bug tracker is only used for tracking confirmed bugs in Go and proposals going through the Proposal Process.

Please see the Questions wiki page; it has a list of good places for asking questions.

Closing here, since this is not a bug.

@ALTree ALTree closed this as completed Nov 26, 2020
@elichai
Copy link
Author

elichai commented Nov 26, 2020

We don't really use the bug tracker for general discussion or asking questions about the language. The Github bug tracker is only used for tracking confirmed bugs in Go and proposals going through the Proposal Process.

Please see the Questions wiki page; it has a list of good places for asking questions.

Closing here, since this is not a bug.

Can I reopen this as a feature request?

@ALTree
Copy link
Member

ALTree commented Nov 26, 2020

You could... but it's not wise to ask for a restriction you don't understand to be lifted. Understanding needs to come first. Those rules were not chosen at random. The page I linked above gives an hint

Go is a garbage collected language, and the garbage collector needs to know the location of every pointer to Go memory. Because of this, there are restrictions on passing pointers between Go and C.

But as I said the issue tracker is not the right place to pursue the aforementioned understanding.

@ianlancetaylor
Copy link
Contributor

For more background see https://go.googlesource.com/proposal/+/refs/heads/master/design/12416-cgo-pointers.md .

@elichai
Copy link
Author

elichai commented Nov 26, 2020

Thanks :)

@golang golang locked and limited conversation to collaborators Nov 26, 2021
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

4 participants