Search code examples
javagojnacgo

Return String[] from Go using cgo


I have to call a Go function from Java. I am using cgo and JNA for doing this.

The only thing that the Go routine does is allocating memory and return a char**. From Java side, I am receiving the char** using String[] as is mentioned in the documentation.

Below are the details of the C helper and Go functions:

static char** cmalloc(int size) {
    return (char**) malloc(size * sizeof(char*));
}

static void setElement(char **a, char *s, int index) {
    a[index] = s;
}

//export getSearchKeysA
func getSearchKeysA() **C.char {
    set_char := C.cmalloc(1)
    defer C.free(unsafe.Pointer(set_char))
    C.setElement(set_char, C.CString("hello world"), C.int(0))
    return set_char
}

The Java side:

String[] getSearchKeysA();

The error I am getting is:

#
# A fatal error has been detected by the Java Runtime Environment:
#
#  SIGSEGV (0xb) at pc=0x00007fff6b15323e, pid=92979, tid=0x0000000000000c07
#
# JRE version: Java(TM) SE Runtime Environment (8.0_192-b12) (build 1.8.0_192-b12)
# Java VM: Java HotSpot(TM) 64-Bit Server VM (25.192-b12 mixed mode bsd-amd64 compressed oops)
# Problematic frame:
# C  [libsystem_kernel.dylib+0x723e]  __pthread_kill+0xa
#
# Failed to write core dump. Core dumps have been disabled. To enable core dumping, try "ulimit -c unlimited" before starting Java again
#
# An error report file with more information is saved as:
# /Users/dfb3/datafabric/pocs/go-java-connector/hs_err_pid92979.log
#
# If you would like to submit a bug report, please visit:
#   http://bugreport.java.com/bugreport/crash.jsp
# The crash happened outside the Java Virtual Machine in native code.
# See problematic frame for where to report the bug.
#

What I have noticed is that the issue appears when malloc is allocating memory.

I already tried doing ulimit -c unlimited and removing the defer C.free(unsafe.Pointer(set_char)) from the method.

What can be the cause of the error and how can I solve it? Is there any other way of returning a []string from Go using JNA?

Update because of typo and base on @PeterSO answer :

  1. I wrote initially malloc(0) but it should be malloc(1)
  2. func C.CString(string) *C.char, it should allocate the memory for me, is not?

Solution

  • I could finally return a String[] from GO using cgo.

    I will leave the functions signatures:

    //export getSearchKeys
    func getSearchKeys(numKeysByReference *C.int) **C.char {
      *numKeysByReference = // ... some value
      // Using the C helper defined above
      set_char := C.cmalloc(*numKeysByReference)
      // Logic allocating and populating C.char[i .. *numKeysByReference]
      // ...
      return set_char
    }
    

    After creating the **C.char structure using cgo, on Java side, I am receiving the data as follow:

    IntByReference intByReference = new IntByReference();
    PointerByReference array = lib.getSearchKeys(intByReference);
    String[] results = array.getPointer().getStringArray(0, intByReference.getValue());
    

    As @PeterSO mentioned, we have call defer C.free() after using it. Otherwise, it will be deallocated after returning.