Skip to content

Commit 36aa2b0

Browse files
committed
cmd/cgo: make JNI's jobject type map to uintptr in Go
The jobject type is declared as a pointer, but some JVMs (Dalvik, ART) store non-pointer values in them. In Go, we must use uintptr instead of a real pointer for these types. This is similar to the CoreFoundation types on Darwin which were "fixed" in CL 66332. Update #22906 Update #21897 RELNOTE=yes Change-Id: I0d4c664501d89a696c2fb037c995503caabf8911 Reviewed-on: https://go-review.googlesource.com/81876 Run-TryBot: Keith Randall <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Ian Lance Taylor <[email protected]>
1 parent d1fa587 commit 36aa2b0

File tree

6 files changed

+406
-10
lines changed

6 files changed

+406
-10
lines changed

misc/cgo/test/cgo_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,5 +86,6 @@ func Test21809(t *testing.T) { test21809(t) }
8686
func Test6907(t *testing.T) { test6907(t) }
8787
func Test6907Go(t *testing.T) { test6907Go(t) }
8888
func Test21897(t *testing.T) { test21897(t) }
89+
func Test22906(t *testing.T) { test22906(t) }
8990

9091
func BenchmarkCgoCall(b *testing.B) { benchCgoCall(b) }

misc/cgo/test/test22906.go

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
// Copyright 2017 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
// +build cgo
6+
7+
package cgotest
8+
9+
/*
10+
11+
// It's going to be hard to include a whole real JVM to test this.
12+
// So we'll simulate a really easy JVM using just the parts we need.
13+
14+
// This is the relevant part of jni.h.
15+
16+
struct _jobject;
17+
18+
typedef struct _jobject *jobject;
19+
typedef jobject jclass;
20+
typedef jobject jthrowable;
21+
typedef jobject jstring;
22+
typedef jobject jarray;
23+
typedef jarray jbooleanArray;
24+
typedef jarray jbyteArray;
25+
typedef jarray jcharArray;
26+
typedef jarray jshortArray;
27+
typedef jarray jintArray;
28+
typedef jarray jlongArray;
29+
typedef jarray jfloatArray;
30+
typedef jarray jdoubleArray;
31+
typedef jarray jobjectArray;
32+
33+
typedef jobject jweak;
34+
35+
// Note: jvalue is already a non-pointer type due to it being a C union.
36+
37+
*/
38+
import "C"
39+
import (
40+
"testing"
41+
)
42+
43+
func test22906(t *testing.T) {
44+
var x1 C.jobject = 0 // Note: 0, not nil. That makes sure we use uintptr for these types.
45+
_ = x1
46+
var x2 C.jclass = 0
47+
_ = x2
48+
var x3 C.jthrowable = 0
49+
_ = x3
50+
var x4 C.jstring = 0
51+
_ = x4
52+
var x5 C.jarray = 0
53+
_ = x5
54+
var x6 C.jbooleanArray = 0
55+
_ = x6
56+
var x7 C.jbyteArray = 0
57+
_ = x7
58+
var x8 C.jcharArray = 0
59+
_ = x8
60+
var x9 C.jshortArray = 0
61+
_ = x9
62+
var x10 C.jintArray = 0
63+
_ = x10
64+
var x11 C.jlongArray = 0
65+
_ = x11
66+
var x12 C.jfloatArray = 0
67+
_ = x12
68+
var x13 C.jdoubleArray = 0
69+
_ = x13
70+
var x14 C.jobjectArray = 0
71+
_ = x14
72+
var x15 C.jweak = 0
73+
_ = x15
74+
}

src/cmd/cgo/gcc.go

Lines changed: 73 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2057,7 +2057,7 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
20572057
name := c.Ident("_Ctype_" + dt.Name)
20582058
goIdent[name.Name] = name
20592059
sub := c.Type(dt.Type, pos)
2060-
if badPointerTypedef(dt.Name) {
2060+
if badPointerTypedef(dt) {
20612061
// Treat this typedef as a uintptr.
20622062
s := *sub
20632063
s.Go = c.uintptr
@@ -2223,7 +2223,7 @@ func (c *typeConv) FuncArg(dtype dwarf.Type, pos token.Pos) *Type {
22232223
}
22242224
// ...or the typedef is one in which we expect bad pointers.
22252225
// It will be a uintptr instead of *X.
2226-
if badPointerTypedef(dt.Name) {
2226+
if badPointerTypedef(dt) {
22272227
break
22282228
}
22292229

@@ -2571,13 +2571,23 @@ func fieldPrefix(fld []*ast.Field) string {
25712571
// A typedef is bad if C code sometimes stores non-pointers in this type.
25722572
// TODO: Currently our best solution is to find these manually and list them as
25732573
// they come up. A better solution is desired.
2574-
func badPointerTypedef(t string) bool {
2575-
// The real bad types are CFNumberRef and CFTypeRef.
2574+
func badPointerTypedef(dt *dwarf.TypedefType) bool {
2575+
if badCFType(dt) {
2576+
return true
2577+
}
2578+
if badJNI(dt) {
2579+
return true
2580+
}
2581+
return false
2582+
}
2583+
2584+
func badCFType(dt *dwarf.TypedefType) bool {
2585+
// The real bad types are CFNumberRef and CFDateRef.
25762586
// Sometimes non-pointers are stored in these types.
25772587
// CFTypeRef is a supertype of those, so it can have bad pointers in it as well.
25782588
// We return true for the other CF*Ref types just so casting between them is easier.
25792589
// See comment below for details about the bad pointers.
2580-
return goos == "darwin" && strings.HasPrefix(t, "CF") && strings.HasSuffix(t, "Ref")
2590+
return goos == "darwin" && strings.HasPrefix(dt.Name, "CF") && strings.HasSuffix(dt.Name, "Ref")
25812591
}
25822592

25832593
// Comment from Darwin's CFInternal.h
@@ -2614,3 +2624,61 @@ enum {
26142624
kCFTaggedObjectID_Undefined7 = (7 << 1) + 1,
26152625
};
26162626
*/
2627+
2628+
func badJNI(dt *dwarf.TypedefType) bool {
2629+
// In Dalvik and ART, the jobject type in the JNI interface of the JVM has the
2630+
// property that it is sometimes (always?) a small integer instead of a real pointer.
2631+
// Note: although only the android JVMs are bad in this respect, we declare the JNI types
2632+
// bad regardless of platform, so the same Go code compiles on both android and non-android.
2633+
if parent, ok := jniTypes[dt.Name]; ok {
2634+
// Try to make sure we're talking about a JNI type, not just some random user's
2635+
// type that happens to use the same name.
2636+
// C doesn't have the notion of a package, so it's hard to be certain.
2637+
2638+
// Walk up to jobject, checking each typedef on the way.
2639+
w := dt
2640+
for parent != "" {
2641+
t, ok := w.Type.(*dwarf.TypedefType)
2642+
if !ok || t.Name != parent {
2643+
return false
2644+
}
2645+
w = t
2646+
parent, ok = jniTypes[w.Name]
2647+
if !ok {
2648+
return false
2649+
}
2650+
}
2651+
2652+
// Check that the typedef is:
2653+
// struct _jobject;
2654+
// typedef struct _jobject *jobject;
2655+
if ptr, ok := w.Type.(*dwarf.PtrType); ok {
2656+
if str, ok := ptr.Type.(*dwarf.StructType); ok {
2657+
if str.StructName == "_jobject" && str.Kind == "struct" && len(str.Field) == 0 && str.Incomplete {
2658+
return true
2659+
}
2660+
}
2661+
}
2662+
}
2663+
return false
2664+
}
2665+
2666+
// jniTypes maps from JNI types that we want to be uintptrs, to the underlying type to which
2667+
// they are mapped. The base "jobject" maps to the empty string.
2668+
var jniTypes = map[string]string{
2669+
"jobject": "",
2670+
"jclass": "jobject",
2671+
"jthrowable": "jobject",
2672+
"jstring": "jobject",
2673+
"jarray": "jobject",
2674+
"jbooleanArray": "jarray",
2675+
"jbyteArray": "jarray",
2676+
"jcharArray": "jarray",
2677+
"jshortArray": "jarray",
2678+
"jintArray": "jarray",
2679+
"jlongArray": "jarray",
2680+
"jfloatArray": "jarray",
2681+
"jdoubleArray": "jarray",
2682+
"jobjectArray": "jarray",
2683+
"jweak": "jobject",
2684+
}

src/cmd/fix/cftype.go

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,13 @@ var cftypeFix = fix{
3030
// and similar for other CF*Ref types.
3131
// This fix finds nils initializing these types and replaces the nils with 0s.
3232
func cftypefix(f *ast.File) bool {
33+
return typefix(f, func(s string) bool {
34+
return strings.HasPrefix(s, "C.CF") && strings.HasSuffix(s, "Ref")
35+
})
36+
}
37+
38+
// typefix replaces nil with 0 for all nils whose type, when passed to badType, returns true.
39+
func typefix(f *ast.File, badType func(string) bool) bool {
3340
if !imports(f, "C") {
3441
return false
3542
}
@@ -39,7 +46,7 @@ func cftypefix(f *ast.File) bool {
3946
// Compute their replacement.
4047
badNils := map[interface{}]ast.Expr{}
4148
walk(f, func(n interface{}) {
42-
if i, ok := n.(*ast.Ident); ok && i.Name == "nil" && badPointerType(typeof[n]) {
49+
if i, ok := n.(*ast.Ident); ok && i.Name == "nil" && badType(typeof[n]) {
4350
badNils[n] = &ast.BasicLit{ValuePos: i.NamePos, Kind: token.INT, Value: "0"}
4451
}
4552
})
@@ -87,7 +94,3 @@ func cftypefix(f *ast.File) bool {
8794

8895
return true
8996
}
90-
91-
func badPointerType(s string) bool {
92-
return strings.HasPrefix(s, "C.CF") && strings.HasSuffix(s, "Ref")
93-
}

src/cmd/fix/jnitype.go

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
// Copyright 2017 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package main
6+
7+
import (
8+
"go/ast"
9+
)
10+
11+
func init() {
12+
register(jniFix)
13+
}
14+
15+
var jniFix = fix{
16+
name: "jni",
17+
date: "2017-12-04",
18+
f: jnifix,
19+
desc: `Fixes initializers of JNI's jobject and subtypes`,
20+
disabled: false,
21+
}
22+
23+
// Old state:
24+
// type jobject *_jobject
25+
// New state:
26+
// type jobject uintptr
27+
// and similar for subtypes of jobject.
28+
// This fix finds nils initializing these types and replaces the nils with 0s.
29+
func jnifix(f *ast.File) bool {
30+
return typefix(f, func(s string) bool {
31+
switch s {
32+
case "C.jobject":
33+
return true
34+
case "C.jclass":
35+
return true
36+
case "C.jthrowable":
37+
return true
38+
case "C.jstring":
39+
return true
40+
case "C.jarray":
41+
return true
42+
case "C.jbooleanArray":
43+
return true
44+
case "C.jbyteArray":
45+
return true
46+
case "C.jcharArray":
47+
return true
48+
case "C.jshortArray":
49+
return true
50+
case "C.jintArray":
51+
return true
52+
case "C.jlongArray":
53+
return true
54+
case "C.jfloatArray":
55+
return true
56+
case "C.jdoubleArray":
57+
return true
58+
case "C.jobjectArray":
59+
return true
60+
case "C.jweak":
61+
return true
62+
}
63+
return false
64+
})
65+
}

0 commit comments

Comments
 (0)