-
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: panic while checking **unsafe.Pointer in cgo call #13830
Comments
Surprisingly enough, I'm getting a compilation error instead with Go 1.5.2:
The wrapper has been generated as:
|
The workaround is to pass it as |
cgo treats this as a type error because a pointer to void is handled as unsafe.Pointer. Since you have The fix for Go 1.6 is to report an error at compile time rather than at run time, as Go 1.5 does. |
Turns out to be hard to check at compile time, for exactly the reason that helper cgoCheckPointer functions were introduced, so postponing to 1.7. |
@ianlancetaylor, should this be postponed to Go 1.8? |
Dropping to unplanned. I would like to have better compile time checking but I'm not sure how to do it. |
This doesn't appear to even require a double-pointer. A plain old For example, this program panics: package main
/*
#include <stdlib.h>
*/
import "C"
import "unsafe"
func main() {
var dt *C.div_t
dt = (*C.div_t)(C.malloc(C.size_t(unsafe.Sizeof(*dt))))
defer C.free(dt)
} whereas this one does not: package main
/*
#include <stdlib.h>
*/
import "C"
import "unsafe"
func main() {
var dt *C.div_t
dt = (*C.div_t)(C.malloc(C.size_t(unsafe.Sizeof(*dt))))
defer C.free(unsafe.Pointer(dt))
} |
Yes. The first program is invalid, the second is not. The way to fix this bug is to catch the invalid case at compile time rather than execution time. In Go 1.5 and earlier we caught the invalid case at compile time, but unfortunately the cgo checks broke that. And, even more unfortunately, it's hard to fix. At least, I don't see how to fix it. |
I'm sure I'm missing something, but why do the _cgoCheckPointer calls need to be inline in the function parameters at all? For the example above, cgo generates this code: func _cgoCheckPointer0(p interface{}, args ...interface{}) unsafe.Pointer {
return _cgoCheckPointer(p, args...).(unsafe.Pointer)
}
func _Cfunc_free(p0 unsafe.Pointer) (r1 _Ctype_void) {
_cgo_runtime_cgocall(_cgo_188eb01e039f_Cfunc_free, uintptr(unsafe.Pointer(&p0)))
[...]
}
[...]
func main() {
var dt *_Ctype_struct___0
dt = (*_Ctype_struct___0)(_Cfunc__CMalloc(_Ctype_size_t(unsafe.Sizeof(*dt))))
defer _Cfunc_free(_cgoCheckPointer0(unsafe.Pointer(dt)))
} Why does the func _Cfunc_free(p0 unsafe.Pointer) (r1 _Ctype_void) {
_cgoCheckPointer0(p0)
_cgo_runtime_cgocall(_cgo_188eb01e039f_Cfunc_free, uintptr(unsafe.Pointer(&p0)))
[...]
}
[...]
func main() {
var dt *_Ctype_struct___0
dt = (*_Ctype_struct___0)(_Cfunc__CMalloc(_Ctype_size_t(unsafe.Sizeof(*dt))))
defer _Cfunc_free(dt)
} Is the problem that the generated function generally accept C types but we need/want to elide the pointer checks based on the corresponding Go types? If that's the case, perhaps we could move the checks to the |
The problem with your suggestion is that given a pointer to an element in a slice, we only want to check that slice. Given a pointer to a field, we only want to check that field. We only know the extent of the area of memory to check at the call site, not in the wrapper. This extent is expressed as additional arguments to cgoCheckPointer. See #14210 for relevant examples. |
Ok. So it's not just type information, but also information about the origins of the values: a And presumably we need call sites to remain expressions (not statements), because the result of a C function call could itself be a function parameter. So we can't pull the ...and we can't use func literals because we can't necessarily name the return-type in the current file (if the type happens to include unsafe.Pointer). So now I understand where the So what about the definition of In fmt.Fprintf(fgo2, "\nfunc %s(p interface{}, args ...interface{}) %s {\n", n, t) to fmt.Fprintf(fgo2, "\nfunc %s(p %s, args ...interface{}) %s {\n", n, t, t) ? |
Yes, I think we could change the Ah, I see what you mean; that fixes this issue. Thanks! I'll try that--maybe I've forgotten some reason it won't work. |
CL https://golang.org/cl/23675 mentions this issue. |
What version of Go are you using (go version)?
What operating system and processor architecture are you using?
What did you do?
I'm trying to pass a pointer into a cgo call. The program below is a full demo.
What did you expect to see?
The pointer successfully passed or a failure because of Go 1.6 restrictions against passing a pointer to Go allocated memory that has pointers to Go allocated memory.
What did you see instead?
The helper has been generated as:
The text was updated successfully, but these errors were encountered: