Golang
import "C"
//export MyFunction
func MyFunction(str *C.char) *C.char {
goStr := C.GoString(str)
msg := goStr + " world"
return C.CString(msg)
}
func main() {}
Java
public interface MyLib extends Library {
MyLib INSTANCE = Native.load("mylib.so", MyLib.class);
String MyFunction(String str);
}
public class CGoExample {
public static void main(String[] args) {
String str = "Hello";
String msg = MyLib.INSTANCE.MyFunction(str);
System.out.println(msg);
}
}
This code works, the Java String is passed to Go, and Go returns a new String. The issue I'm having is that the CString returned by Go will not be deallocated by either the Java or Go garbage collector. The CGO documentation states "it is the caller's responsibility to arrange for it to be freed, such as by calling C.free", of course in my case calling C.free will not work as I'm returning the CString and if I free the CString before returning it I don't get a proper response from the Go function. I also tried calling defer C.free(unsafe.Pointer(msg))
but as I found out the hard way defer statements will be called before the return statement.
As I need to return the CString I'm assuming its memory needs to be deallocated from java, how would I go about doing this?
Edit:
Based on DanielWiddis' comment I have tried the following but the java process exists with code -1073741819.
// #include <stdlib.h>
import "C"
import "unsafe"
//export MyFunction
func MyFunction(str *C.char) *C.char {
goStr := C.GoString(str)
msg := goStr + " world"
return C.CString(msg)
}
//export Free
func Free(str *C.char){
C.free(unsafe.Pointer(str))
}
func main() {}
public interface MyLib extends Library {
MyLib INSTANCE = Native.load("mylib.so", MyLib.class);
String MyFunction(String str);
void Free(String str);
}
public class CGoExample {
public static void main(String[] args) {
String str = "Hello";
String msg = MyLib.INSTANCE.MyFunction(str);
System.out.println(msg);
MyLib.INSTANCE.Free(msg);
}
}
Based on DanielWiddis' comments I came up with the following solution which successfully deallocates memory for all involved objects.
package main
// #include <stdlib.h>
import "C"
import (
"unsafe"
)
//export MyFunction
func MyFunction(cStr *C.char) *C.char {
str := C.GoString(cStr)
msg := str + " world"
return C.CString(msg)
}
//export Free
func Free(str *C.char){
C.free(unsafe.Pointer(str))
}
func main() {}
public interface MyLib extends Library {
MyLib INSTANCE = Native.load("mylib.so", MyLib.class);
Pointer MyFunction(Pointer ptr);
void Free(Pointer ptr);
}
public class CGoExample {
public static void main(String[] args) {
// Create pointer with a String value
String str = "Hello";
Pointer ptr = new Memory(str.length() + 1);
ptr.clear();
ptr.setString(0, str);
//Pass the pointer to Go function which returns the pointer of the message
Pointer resultPtr = MyLib.INSTANCE.MyFunction(ptr);
//Get the message String from the pointer
String msg = resultPtr.getString(0);
//Deallocate the memory for the message
MyLib.INSTANCE.Free(resultPtr);
System.out.println(msg);
}
}