I have stripped back a problem I have come across whilst wrapping some C code to work with golang using swig but the problem doesn't rest with swig.
I can pass in a basic string slice but as soon as I construct the slice with anything other than basic strings, I get a panic: runtime error: cgo argument has Go pointer to Go pointer.
go version go1.8.5 linux/amd64
This is the sample code and its output
package main
import (
"fmt"
"reflect"
"unsafe"
)
/*
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct { char *p; int n; } _gostring_;
typedef struct { void* array; int len; int cap; } _goslice_;
void prtText(char * const *txt, int len)
{
int i = 0;
for ( i=0; i<len; i++ ) {
printf("Text %d is: %s
", i, txt[i]);
}
}
void _wrap_printText(_goslice_ _swig_go_0) {
_gostring_ *p;
char **arg1 = (char **)calloc(_swig_go_0.len, sizeof(char*));
if (arg1) {
for (int i=0; i<_swig_go_0.len; i++) {
p = &(((_gostring_*)_swig_go_0.array)[i]);
arg1[i] = calloc(1,(p->n)+1);
strncpy(arg1[i], p->p, p->n);
}
}
int arg2 = _swig_go_0.len;
prtText((char *const *)arg1,arg2);
}
*/
import "C"
func PrintText(arg1 []string) {
C._wrap_printText(*(*C._goslice_)(unsafe.Pointer(&arg1)))
}
func main() {
s := []string{}
s = append(s, "blah")
s = append(s, "hello")
s = append(s, "again")
ns := []string{}
ns = append(ns, "ns: "+s[0])
ns = append(ns, "ns: "+s[1])
ns = append(ns, "ns: "+s[2])
fmt.Println("type s:", reflect.TypeOf(s))
fmt.Println("type ns:", reflect.TypeOf(ns))
fmt.Println("s:", s)
fmt.Println("ns:", ns)
PrintText(s)
PrintText(ns)
}
go build -i -x -gcflags '-N -l' main.go
./main
type s: []string
type ns: []string
s: [blah hello again]
ns: [ns: blah ns: hello ns: again]
Text 0 is: blah
Text 1 is: hello
Text 2 is: again
panic: runtime error: cgo argument has Go pointer to Go pointer
As you can see, the first string slice works fine but as soon as I do anything other than basic strings, it fails. I've tried making new strings first before appending them to the slice but the problem remains.
What am I doing wrong?