-
Notifications
You must be signed in to change notification settings - Fork 17.8k
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: jmethodID/jfieldID is not mapped to uintptr if building with the Android NDK #40954
Comments
Change https://golang.org/cl/249744 mentions this issue: |
Nice find. Consider backporting this to the Go 1.15 (and Go 1.14?) given that it's easily reproduced on Android 11, which is due soon.
Perhaps jmethodID/jfieldID values became IDs, not pointers, in Android 11? @ianlancetaylor we keep having to whack these moles, each time leading to an API change. In particular, comparing with nil must change to comparing with 0. I'm sure there are many other C APIs out there that misuse pointers like this. Can we handle them better in Cgo? |
I am indeed in strong favor of a backport in Go 1.15 and Go 1.14 since this is a crasher and Android 11 will be out soon (early Sept if we look at the previous versions) For what it's worth, I just cherry-picked the commit as-is in our Go 1.13 branch. |
CC @randall77 |
In Go it's absolutely essential that we be able to distinguish a pointer and an integer. I don't see a way around that. In cgo we do want C names that are typedefs for pointer types to be usable in Go, and it seems natural to use them as pointers. I don't see a way around that. I don't fully understand the problem but I don't see any available options. Go requires completely strict typing for pointers, and C does not. |
Yes, it looks like we have to add those two types to the list that need to use Does anyone have a pointer to code in Android 11 that makes these pointer-not-pointers? I'm curious what changed and why. Longer term: It would be nice if we could distinguish types that are intended to be opaque from ones that are not. The JNI headers do things like:
If we could detect pointers like this, ones where there's no possible way you could dereference them, or allocate one in Go (what does cgo do with The other option is to make a special cgo type that's known to the compiler. Syntactically it looks like a pointer (initialized with What about |
Change https://golang.org/cl/249917 mentions this issue: |
I filed #40507 a little bit ago to look at incomplete struct/union types. I think |
@randall77 Nice idea, by the way. |
Change https://golang.org/cl/250939 mentions this issue: |
Change https://golang.org/cl/250940 mentions this issue: |
I think my series of CLs solves this issue, and maybe future such issues going forward as well. |
I would advise against waiting for 1.16, as Android 11 is due in a few weeks and existing programs may be crashing (at least ours does). Also, CL 249744 could be easily backported in 1.15 and 1.14 while the |
The problem with CL 249744 is that the initializers of |
We could do both in Go 1.16 (convert jfieldID and jmethodID to uintptr, and your notinheap fix). That's once churn (but still in a point release). However, I'd love for all the special cases (JNI types, CFTypes, EGL* types) to go away now that the longer term fix is in. How about doing CL 249744 for Go 1.15.1 and then remove all special cases at once in Go 1.16? That's more churn, but at least we're getting rid of a Cgo wart. If that's too drastic, only remove the special cases when "go 1.16" or later is in go.mod. Note that code may not need to be rewritten, if you're careful. For example, I'm using |
We could make BTW, what should checkptr semantics be for notinheap types? (Didn't have to worry about this before when it was runtime only.) I think converting |
Converting Going from |
Yeah, though that's a concern for I think if we want to detect pointers becoming heap pointers due to heap growth, it would be more robust to detect that during heap growth itself. E.g., allocate the new heap memory, but flag it as not quite ready yet; trigger a full GC run; and during heap marking, crash if we find any pointers that point into this newly allocated memory. |
Change https://golang.org/cl/251158 mentions this issue: |
Yes, I guess that makes sense. The false negative I was worried about seems very rare. |
Gentle ping. What to do for Go 1.15, and can we get rid of the special cases in Go 1.16 with go:notinheap? |
FWIW, Android 11 is out: https://blog.google/products/android/android-11. |
Gentle ping too. I'm in favour of @eliasnaur's plan: merge this one for 1.15 and After all it's fixing a very real crash, and Android 11 is out now. |
I think the suggested plan is:
Does that sound right to everyone? @randall77 Any objections to this plan? |
I was kind of hoping that we could backport #3 (consisting of CLs 250939, 250940, and maybe 251158). That way no user would have to change their code ( |
…heap or stack Right now we just prevent such types from being on the heap. This CL makes it so they cannot appear on the stack either. The distinction between heap and stack is pretty vague at the language level (e.g. it is affected by -N), and we don't need the flexibility anyway. Once go:notinheap types cannot be in either place, we don't need to consider pointers to such types to be pointers, at least according to the garbage collector and stack copying. (This is the big win of this CL, in my opinion.) The distinction between HasPointers and HasHeapPointer no longer exists. There is only HasPointers. This CL is cleanup before possible use of go:notinheap to fix #40954. Update #13386 Change-Id: Ibd895aadf001c0385078a6d4809c3f374991231a Reviewed-on: https://go-review.googlesource.com/c/go/+/255320 Trust: Keith Randall <khr@golang.org> Reviewed-by: Austin Clements <austin@google.com> Reviewed-by: Matthew Dempsky <mdempsky@google.com>
The alias doesn't need to be marked go:notinheap. It gets its notinheap-ness from the target type. Without this change, the type alias test in the notinheap.go file generates these two errors: notinheap.go:62: misplaced compiler directive notinheap.go:63: type nih must be go:notinheap The first is a result of go:notinheap pragmas not applying to type alias declarations. The second is the result of then trying to match the notinheap-ness of the alias and the target type. Add a few more go:notinheap tests while we are here. Update #40954 Change-Id: I067ec47698df6e9e593e080d67796fd05a1d480f Reviewed-on: https://go-review.googlesource.com/c/go/+/250939 Run-TryBot: Keith Randall <khr@golang.org> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Emmanuel Odeke <emm.odeke@gmail.com> Trust: Keith Randall <khr@golang.org> Reviewed-on: https://go-review.googlesource.com/c/go/+/255337 Trust: Emmanuel Odeke <emm.odeke@gmail.com> Reviewed-by: Austin Clements <austin@google.com>
They can't reasonably be allocated on the heap. Not a huge deal, but it has an interesting and useful side effect. After CL 249917, the compiler and runtime treat pointers to go:notinheap types as uintptrs instead of real pointers (no write barrier, not processed during stack scanning, ...). That feature is exactly what we want for cgo to fix #40954. All the cases we have of pointers declared in C, but which might actually be filled with non-pointer data, are of this form (JNI's jobject heirarch, Darwin's CFType heirarchy, ...). Fixes #40954 Change-Id: I44a3b9bc2513d4287107e39d0cbbd0efd46a3aae Reviewed-on: https://go-review.googlesource.com/c/go/+/250940 Run-TryBot: Emmanuel Odeke <emm.odeke@gmail.com> TryBot-Result: Go Bot <gobot@golang.org> Trust: Keith Randall <khr@golang.org> Reviewed-by: Ian Lance Taylor <iant@golang.org> Reviewed-on: https://go-review.googlesource.com/c/go/+/255321
…friendlier for cgo Update #40954 Change-Id: Ifaab7349631ccb12fc892882bbdf7f0ebf3d845f Reviewed-on: https://go-review.googlesource.com/c/go/+/251158 Run-TryBot: Keith Randall <khr@golang.org> Reviewed-by: Ian Lance Taylor <iant@golang.org> TryBot-Result: Go Bot <gobot@golang.org> Trust: Keith Randall <khr@golang.org> Reviewed-on: https://go-review.googlesource.com/c/go/+/255338 Reviewed-by: Austin Clements <austin@google.com>
I think this change, at least the if dt.Kind == "struct" { ... tt.NotInHeap = true ... } in cgo/gcc.go L2437, part, has an unexpected consequence. It is now in 1.15.3 and is leading to panics in code that uses reflect.DeepEqual on structs that contain pointers created by cgo code. ptrdata is nil and hence the reflect package (value.go:95) will panic when called upon to compare them. From reading this and the code I don't think you were expecting this to cause these panics. I bigger warning in the release notes seems warranted:-) |
@cosnicolaou Yes, it looks like we need to relax the condition in |
This is an example of a program triggering this failure. It panics with However, we should do something for uses of |
Hm, actually just putting a |
Hi Keith,
I can probably pull this out into a standalone example/test if you wish,
but first let me explain in a little more detail. My offending code looks,
approximately, as follows:
type opensslECDSAPublicKey struct {
k *C.EC_KEY
....
}
where k is obtained from openssl as follows:
...
k := C.openssl_d2i_EC_PUBKEY(uchar(der), C.long(len(der)), &errno)
if k == nil {
return nil, opensslMakeError(errno)
}
...
with a finalizer:
runtime.SetFinalizer(ret, func(k *opensslECDSAPublicKey) { k.finalize() })
type opensslECDSASigner struct {
k *C.EC_KEY
}
func (k *opensslECDSASigner) finalize() {
C.EC_KEY_free(k.k)
}
This has worked "fine" since about 2013/2014 with a lot of the application
code, and tests, using DeepEqual (arguably they shouldn't be doing so but
that's a separate issue).
This code is expecting for the returned go struct, that contains the C
struct, to be on the heap. The problem appears to be that cgo can't
determine the size of this struct and
that the new behaviour treats it as if it can't be on the heap, though, I
think, with a finalizer everything works fine.
A separate question is why the size information is not available, and I'd
guess that's because the debug dwarf sections are not in the library, but I
don't know enough about
dwarf to be sure.
Cheers, Cos.
…On Fri, Oct 16, 2020 at 8:16 AM Keith Randall ***@***.***> wrote:
Hm, actually just putting a *T in a reflect.Value is bad, as it is stored
internally as an unsafe.Pointer. We may need to teach reflect to
understand notinheap and store them as uintptrs.
Maybe force *T when T is notinheap to be indirect?
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#40954 (comment)>, or
unsubscribe
<https://github.com/notifications/unsubscribe-auth/ACCMUYDIVJFE2JFLJJUIM2DSLBPWLANCNFSM4QHOBRHA>
.
|
- update go.mod with a specific version for the logger submodule - integration tests with ssl need go 15.1.2, not .3, see golang/go#40954
Your usage of your allocator + finalizer seems fine.
Thanks, but I don't think that will be necessary. I think I understand what is going on. Not sure what the right fix is yet.
I don't think this has anything to do with dwarf. Cgo uses .h files to find declarations of types and examines those declarations to decide whether they should be notinheap. Can you find the declaration of EC_KEY? You might be able to patch that declaration somehow. |
On Fri, Oct 16, 2020 at 10:59 AM Keith Randall ***@***.***> wrote:
Your usage of your allocator + finalizer seems fine.
I can probably pull this out into a standalone example/test if you wish,
Thanks, but I don't think that will be necessary. I think I understand
what is going on. Not sure what the right fix is yet.
A separate question is why the size information is not available, and I'd
guess that's because the debug dwarf sections are not in the library, but I
don't know enough about dwarf to be sure.
I don't think this has anything to do with dwarf. Cgo uses .h files to
find declarations of types and examines those declarations to decide
whether they should be notinheap. Can you find the declaration of EC_KEY?
You might be able to patch that declaration somehow.
A few debug lines in cgo show me that EC_KEY has size -1, but *EC_KEY has
size 8 so cgo is not able to discern the size of the underlying struct from
the gcc/clang debug output that it generates (that's where the dwarf code
comes in). The debug/dwarf package's dwarf reader reports the types as
incomplete, which makes sense, since the openssl code deliberately hides
the actual struct behind its API and only exports a pointer. So, I suspect
any cgo wrappers that embed opaque pointers in go structs are likely to run
into this. Let me see if I can hide the pointers from go and get things to
work again.
Cheers, Cos.
… —
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#40954 (comment)>, or
unsubscribe
<https://github.com/notifications/unsubscribe-auth/ACCMUYCOINTZE6FS4S7XEHTSLCCZFANCNFSM4QHOBRHA>
.
|
Should this bug be reopened (or a separate one created) to track this regression? |
Yes, I'll open a new issue. |
…heap or stack Right now we just prevent such types from being on the heap. This CL makes it so they cannot appear on the stack either. The distinction between heap and stack is pretty vague at the language level (e.g. it is affected by -N), and we don't need the flexibility anyway. Once go:notinheap types cannot be in either place, we don't need to consider pointers to such types to be pointers, at least according to the garbage collector and stack copying. (This is the big win of this CL, in my opinion.) The distinction between HasPointers and HasHeapPointer no longer exists. There is only HasPointers. This CL is cleanup before possible use of go:notinheap to fix golang#40954. Update golang#13386 Change-Id: Ibd895aadf001c0385078a6d4809c3f374991231a Reviewed-on: https://go-review.googlesource.com/c/go/+/255320 Trust: Keith Randall <khr@golang.org> Reviewed-by: Austin Clements <austin@google.com> Reviewed-by: Matthew Dempsky <mdempsky@google.com>
The alias doesn't need to be marked go:notinheap. It gets its notinheap-ness from the target type. Without this change, the type alias test in the notinheap.go file generates these two errors: notinheap.go:62: misplaced compiler directive notinheap.go:63: type nih must be go:notinheap The first is a result of go:notinheap pragmas not applying to type alias declarations. The second is the result of then trying to match the notinheap-ness of the alias and the target type. Add a few more go:notinheap tests while we are here. Update golang#40954 Change-Id: I067ec47698df6e9e593e080d67796fd05a1d480f Reviewed-on: https://go-review.googlesource.com/c/go/+/250939 Run-TryBot: Keith Randall <khr@golang.org> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Emmanuel Odeke <emm.odeke@gmail.com> Trust: Keith Randall <khr@golang.org> Reviewed-on: https://go-review.googlesource.com/c/go/+/255337 Trust: Emmanuel Odeke <emm.odeke@gmail.com> Reviewed-by: Austin Clements <austin@google.com>
They can't reasonably be allocated on the heap. Not a huge deal, but it has an interesting and useful side effect. After CL 249917, the compiler and runtime treat pointers to go:notinheap types as uintptrs instead of real pointers (no write barrier, not processed during stack scanning, ...). That feature is exactly what we want for cgo to fix golang#40954. All the cases we have of pointers declared in C, but which might actually be filled with non-pointer data, are of this form (JNI's jobject heirarch, Darwin's CFType heirarchy, ...). Fixes golang#40954 Change-Id: I44a3b9bc2513d4287107e39d0cbbd0efd46a3aae Reviewed-on: https://go-review.googlesource.com/c/go/+/250940 Run-TryBot: Emmanuel Odeke <emm.odeke@gmail.com> TryBot-Result: Go Bot <gobot@golang.org> Trust: Keith Randall <khr@golang.org> Reviewed-by: Ian Lance Taylor <iant@golang.org> Reviewed-on: https://go-review.googlesource.com/c/go/+/255321
…friendlier for cgo Update golang#40954 Change-Id: Ifaab7349631ccb12fc892882bbdf7f0ebf3d845f Reviewed-on: https://go-review.googlesource.com/c/go/+/251158 Run-TryBot: Keith Randall <khr@golang.org> Reviewed-by: Ian Lance Taylor <iant@golang.org> TryBot-Result: Go Bot <gobot@golang.org> Trust: Keith Randall <khr@golang.org> Reviewed-on: https://go-review.googlesource.com/c/go/+/255338 Reviewed-by: Austin Clements <austin@google.com>
Change https://golang.org/cl/277432 mentions this issue: |
For #40954 Change-Id: I6a30aed31a16e820817f4ca5c7f591222e922946 Reviewed-on: https://go-review.googlesource.com/c/go/+/277432 Trust: Ian Lance Taylor <iant@golang.org> Reviewed-by: Keith Randall <khr@golang.org>
Change https://golang.org/cl/278573 mentions this issue: |
… empty structs For #40954 Change-Id: I6a30aed31a16e820817f4ca5c7f591222e922946 Reviewed-on: https://go-review.googlesource.com/c/go/+/277432 Trust: Ian Lance Taylor <iant@golang.org> Reviewed-by: Keith Randall <khr@golang.org> (cherry picked from commit 129bb19) Reviewed-on: https://go-review.googlesource.com/c/go/+/278573 Run-TryBot: Ian Lance Taylor <iant@golang.org> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org>
This is a variant of #26213
What version of Go are you using (
go version
)?Does this issue reproduce with the latest release?
Yes
What operating system and processor architecture are you using (
go env
)?go env
OutputWhat did you do?
with the Android NDK:
What did you expect to see?
No error.
What did you see instead?
Notes
This issue is the same as #26213, only with
jmethodID
andjfieldID
. It seems the bug was always there, but for some reason it now reliably crashes on Android 11 with the following:We are running a modified 1.13.8 and adding
jmethodID
andjfieldID
to the list of badJNI types fixes the issue.They are defined like so in Android NDK:
I'll open a PR with the patch.
The text was updated successfully, but these errors were encountered: