-
Notifications
You must be signed in to change notification settings - Fork 17.9k
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: cgo pointer checking panic on address of slice from function call #14210
Comments
That is the way the current implementation works, a consequence of the way that cgo rewrites calls to C functions. We can try to do better for 1.7, but we aren't going to change this for 1.6. To be clear, what is happening is that the expression If the slice didn't point back into buf, then it would work. For example, this variant works.
|
Thanks for the prompt reply. My understanding then is that in the crash case, it's detected that the pointer is to |
I'm not sure I completely understand. I have a very similar looking problem but the solution here is not working for me (linux/amd64). I have a project that crashes during
The problematic call is not even a direct call into C (mdb_store.go:180). It calls a method on *lmdb.Txn that will then call into C using an unsafe pointer from its
Assigning a variable to val.Bytes() beforehand does not help, the panic still occurs
When I copy the bytes into a
|
@bmatsuo The problem in your case is that the key &b[0] operation is hidden from cgo, because it's in a separate function valBytes. One way to write your code would be
The point is that cgo needs to see the address operation in the call. |
Okay. I see now. Thanks. Presumably that will work, given that I am telling C the array has zero length. It definitely feels like a hack though, and will add boilerplate in several places around my LMDB bindings. @ianlancetaylor The way you describe it my problems sound like a separate issue. Is that correct? I'm confused if things are working as intended or if I should file a new issue for this. I will reread the documentation. |
@bmatsuo Yes, yours is a different issue. |
…: cgo argument has Go pointer to Go pointer)
Avoid golang/go#14210 (Go 1.6 panic: runtime error: cgo argument has Go pointer to Go pointer)
@ianlancetaylor, should we bump this to Go 1.8? |
Yeah, I didn't get to this. Sorry. Bumping to 1.8. |
This heuristic can cut the other way, too: when cgo knows we're talking about a slice, it may spuriously ignore the rest of the object: package main
/*
#include <stdint.h>
struct leak {
char pad[4];
int* oops;
};
void sneak(void *l, uintptr_t *u) {
*u = (uintptr_t)((struct leak*)(l))->oops;
}
*/
import "C"
import (
"fmt"
"unsafe"
)
func main() {
var (
l C.struct_leak
escapee C.int
)
l.oops = &escapee
var u C.uintptr_t
C.sneak(unsafe.Pointer(&l.pad[0]), &u)
fmt.Println(u)
} |
I don't think we should warn about that example. The C code here is not following the rules, but there is nothing we can do to prevent that. The rules are clear: when passing the address of an element in an element in an array, the Go memory being passed is the array (the entire array, and nothing but the array). If the C code chooses to go beyond those bounds, it is broken, though the breakage is undetectable. |
There's a lot here. The short version for future readers is this. We know and accept as OK that the cgo checks look into unsafe pointer expressions at the call site, so that
is rejected, because cgo cannot tell what p is meant to point to, so it assumes the whole allocation, and there are pointers reachable in the whole allocation (the bytes.Buffer struct). It's also true that:
does work, because the call makes it clear that we're just passing the address of the first slice element, so the check for pointers is limited to the slice backing store, which of course contains no pointers (it's a []byte). But this variant of the last example does not work:
For one reason or another the variable x is required, and that's not expected and probably worth fixing. |
I have similar problem, but workaround is very strange:
this fails with
difference is in |
Change https://golang.org/cl/120615 mentions this issue: |
Change https://golang.org/cl/142884 mentions this issue: |
Testing our code on go 1.6rc1 I ran into an unexpected cgo pointer check panic calling a write-like C function.
The case is reproducible using the following code:
My expectation was that they would run the same. But the crash function panics while the ok function does not. The different between them is that in ok I first assign the buf.Bytes() return value to a temporary variable, instead of calling the C function with the return value directly.
Go version:
go1.6rc1 linux/amd64
binary download from golang.orgSteps to reproduce:
go run code.go crash
Expected result:
Hello, cgo!
written on stdoutActual result:
panic: runtime error: cgo argument has Go pointer to Go pointer
The text was updated successfully, but these errors were encountered: