From 739abda8dec16c9f15ff283354dd43e960c6c2d1 Mon Sep 17 00:00:00 2001 From: Iain Date: Sun, 23 Aug 2026 00:15:08 +0100 Subject: [PATCH 1/2] purego: fix returning a C function pointer as a Go func --- func.go | 3 +-- func_test.go | 10 ++++++++++ testdata/abitest/abi_test.c | 10 ++++++++++ 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/func.go b/func.go index 57afd93e..0da1dbc3 100644 --- a/func.go +++ b/func.go @@ -409,8 +409,7 @@ func RegisterFunc(fptr any, cfn uintptr) { v = reflect.NewAt(outType, unsafe.Pointer(&a1)).Elem() case reflect.Func: // wrap this C function in a nicely typed Go function - v = reflect.New(outType) - RegisterFunc(v.Interface(), syscall.a1) + RegisterFunc(v.Addr().Interface(), syscall.a1) case reflect.String: v.SetString(strings.GoString(syscall.a1)) case reflect.Float32: diff --git a/func_test.go b/func_test.go index f5190714..6f31f04d 100644 --- a/func_test.go +++ b/func_test.go @@ -239,6 +239,16 @@ func TestABI(t *testing.T) { t.Fatalf("%s: got %q, want %q", cName, res, want) } } + { + const cName = "return_func_ptr" + var fn func() func(a, b int32) int32 + purego.RegisterLibFunc(&fn, lib, cName) + add := fn() + const expect = 5 + if res := add(2, 3); res != expect { + t.Fatalf("%s: got %d, want %d", cName, res, expect) + } + } } func TestABI_ArgumentPassing(t *testing.T) { diff --git a/testdata/abitest/abi_test.c b/testdata/abitest/abi_test.c index c129d26d..4f187e25 100644 --- a/testdata/abitest/abi_test.c +++ b/testdata/abitest/abi_test.c @@ -197,3 +197,13 @@ double arm_float64_unaligned_on_stack(uintptr_t a1, uintptr_t a2, uintptr_t a3, return (double)a1 * 1 + (double)a2 * 2 + (double)a3 * 3 + (double)a4 * 4 + (double)a5 * 5 + a6; } + +typedef int32_t (*AddFunc)(int32_t, int32_t); + +int32_t returned_add(int32_t a, int32_t b) { + return a + b; +} + +AddFunc return_func_ptr(void) { + return returned_add; +} From 2ae2a53c9fd6ed67d10e914d96f03d7a314e19f7 Mon Sep 17 00:00:00 2001 From: Iain Date: Sun, 23 Aug 2026 20:44:05 +0100 Subject: [PATCH 2/2] purego: keep a NULL C function pointer as a nil Go func --- func.go | 4 +++- func_test.go | 8 ++++++++ testdata/abitest/abi_test.c | 4 ++++ 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/func.go b/func.go index 0da1dbc3..005813be 100644 --- a/func.go +++ b/func.go @@ -409,7 +409,9 @@ func RegisterFunc(fptr any, cfn uintptr) { v = reflect.NewAt(outType, unsafe.Pointer(&a1)).Elem() case reflect.Func: // wrap this C function in a nicely typed Go function - RegisterFunc(v.Addr().Interface(), syscall.a1) + if syscall.a1 != 0 { + RegisterFunc(v.Addr().Interface(), syscall.a1) + } case reflect.String: v.SetString(strings.GoString(syscall.a1)) case reflect.Float32: diff --git a/func_test.go b/func_test.go index 6f31f04d..fb853276 100644 --- a/func_test.go +++ b/func_test.go @@ -249,6 +249,14 @@ func TestABI(t *testing.T) { t.Fatalf("%s: got %d, want %d", cName, res, expect) } } + { + const cName = "return_null_func_ptr" + var fn func() func(a, b int32) int32 + purego.RegisterLibFunc(&fn, lib, cName) + if fn() != nil { + t.Fatalf("%s: got a non-nil func, want nil", cName) + } + } } func TestABI_ArgumentPassing(t *testing.T) { diff --git a/testdata/abitest/abi_test.c b/testdata/abitest/abi_test.c index 4f187e25..86eeca67 100644 --- a/testdata/abitest/abi_test.c +++ b/testdata/abitest/abi_test.c @@ -207,3 +207,7 @@ int32_t returned_add(int32_t a, int32_t b) { AddFunc return_func_ptr(void) { return returned_add; } + +AddFunc return_null_func_ptr(void) { + return NULL; +}