bind: accept null objects as nil pointers
Currently the generated bindings assume that any object
passed to Go as a method argument is actually a valid one
originating from Go. The `null` object is however a corner
case to this assumption, which should be accepted for Go
pointer types, since they can cleanly convert into `nil`.
This CL modifies the generated wrapper code so any `nil`
reference is permitted for Go pointer types, which until
now produced a nil pointer dereference error.
Fixes golang/go#20330
Change-Id: If1ab9cf9df7ac3808486d23ccf2db8d32fb89426
Reviewed-on: https://go-review.googlesource.com/43253
Reviewed-by: Elias Naur <elias.naur@gmail.com>
diff --git a/bind/gengo.go b/bind/gengo.go
index c56d3e3..1d0ff9f 100644
--- a/bind/gengo.go
+++ b/bind/gengo.go
@@ -413,8 +413,10 @@
return
}
g.Printf("// Must be a Go object\n")
- g.Printf("%s_ref := _seq.FromRefNum(int32(%s))\n", toVar, fromVar)
- g.Printf("%s := %s_ref.Get().(*%s%s)\n", toVar, toVar, g.pkgName(oPkg), o.Name())
+ g.Printf("var %s *%s%s\n", toVar, g.pkgName(oPkg), o.Name())
+ g.Printf("if %s_ref := _seq.FromRefNum(int32(%s)); %s_ref != nil {\n", toVar, fromVar, toVar)
+ g.Printf(" %s = %s_ref.Get().(*%s%s)\n", toVar, toVar, g.pkgName(oPkg), o.Name())
+ g.Printf("}\n")
default:
g.errorf("unsupported pointer type %s", t)
}
diff --git a/bind/java/SeqTest.java b/bind/java/SeqTest.java
index 2439c51..36f3169 100644
--- a/bind/java/SeqTest.java
+++ b/bind/java/SeqTest.java
@@ -448,8 +448,11 @@
return null;
}
}));
- assertEquals("Go nil interface is null", null, Testpkg.newNullInterface());
- assertEquals("Go nil struct pointer is null", null, Testpkg.newNullStruct());
+ assertEquals("Go nil interface is null", null, Testpkg.newNullInterface());
+ assertEquals("Go nil struct pointer is null", null, Testpkg.newNullStruct());
+
+ Issue20330 nullArger = new Issue20330();
+ assertTrue(nullArger.callWithNull(null));
}
public void testPassByteArray() {
diff --git a/bind/objc/SeqTest.m b/bind/objc/SeqTest.m
index e6d0fe7..139a9f9 100644
--- a/bind/objc/SeqTest.m
+++ b/bind/objc/SeqTest.m
@@ -395,6 +395,8 @@
XCTAssertNil(i, @"NewNullInterface() returned %p; expected nil", i);
TestpkgS *s = TestpkgNewNullStruct();
XCTAssertNil(s, @"NewNullStruct() returned %p; expected nil", s);
+ TestpkgIssue20330 *nullArger = TestpkgNewIssue20330();
+ XCTAssertTrue([nullArger callWithNull:nil], @"Issue20330.CallWithNull failed");
}
- (void)testReturnsError {
diff --git a/bind/testdata/issue10788.go.golden b/bind/testdata/issue10788.go.golden
index a6ef182..f8d1145 100644
--- a/bind/testdata/issue10788.go.golden
+++ b/bind/testdata/issue10788.go.golden
@@ -46,8 +46,10 @@
ref := _seq.FromRefNum(int32(refnum))
v := ref.Get().(issue10788.TestInterface)
// Must be a Go object
- _param_s_ref := _seq.FromRefNum(int32(param_s))
- _param_s := _param_s_ref.Get().(*issue10788.TestStruct)
+ var _param_s *issue10788.TestStruct
+ if _param_s_ref := _seq.FromRefNum(int32(param_s)); _param_s_ref != nil {
+ _param_s = _param_s_ref.Get().(*issue10788.TestStruct)
+ }
v.DoSomeWork(_param_s)
}
diff --git a/bind/testdata/structs.go.golden b/bind/testdata/structs.go.golden
index f989e4e..49e366f 100644
--- a/bind/testdata/structs.go.golden
+++ b/bind/testdata/structs.go.golden
@@ -120,8 +120,10 @@
//export proxystructs__Identity
func proxystructs__Identity(param_s C.int32_t) C.int32_t {
// Must be a Go object
- _param_s_ref := _seq.FromRefNum(int32(param_s))
- _param_s := _param_s_ref.Get().(*structs.S)
+ var _param_s *structs.S
+ if _param_s_ref := _seq.FromRefNum(int32(param_s)); _param_s_ref != nil {
+ _param_s = _param_s_ref.Get().(*structs.S)
+ }
res_0 := structs.Identity(_param_s)
var _res_0 C.int32_t = _seq.NullRefNum
if res_0 != nil {
@@ -133,8 +135,10 @@
//export proxystructs__IdentityWithError
func proxystructs__IdentityWithError(param_s C.int32_t) (C.int32_t, C.int32_t) {
// Must be a Go object
- _param_s_ref := _seq.FromRefNum(int32(param_s))
- _param_s := _param_s_ref.Get().(*structs.S)
+ var _param_s *structs.S
+ if _param_s_ref := _seq.FromRefNum(int32(param_s)); _param_s_ref != nil {
+ _param_s = _param_s_ref.Get().(*structs.S)
+ }
res_0, res_1 := structs.IdentityWithError(_param_s)
var _res_0 C.int32_t = _seq.NullRefNum
if res_0 != nil {
diff --git a/bind/testdata/vars.go.golden b/bind/testdata/vars.go.golden
index f3a1132..6158e20 100644
--- a/bind/testdata/vars.go.golden
+++ b/bind/testdata/vars.go.golden
@@ -101,8 +101,10 @@
//export var_setvars_AStructPtr
func var_setvars_AStructPtr(v C.int32_t) {
// Must be a Go object
- _v_ref := _seq.FromRefNum(int32(v))
- _v := _v_ref.Get().(*vars.S)
+ var _v *vars.S
+ if _v_ref := _seq.FromRefNum(int32(v)); _v_ref != nil {
+ _v = _v_ref.Get().(*vars.S)
+ }
vars.AStructPtr = _v
}
diff --git a/bind/testpkg/testpkg.go b/bind/testpkg/testpkg.go
index 2e825c7..f0cda07 100644
--- a/bind/testpkg/testpkg.go
+++ b/bind/testpkg/testpkg.go
@@ -266,6 +266,16 @@
return _null == nil && nuller.Null() == nil
}
+type Issue20330 struct{}
+
+func NewIssue20330() *Issue20330 {
+ return new(Issue20330)
+}
+
+func (i *Issue20330) CallWithNull(_null *Issue20330) bool {
+ return _null == nil
+}
+
type Issue14168 interface {
F(seq int32)
}