I'm trying to make an FFI call but I get a segmentation fault inside the function called by ffi_call (gtk_init
in this case). I'm not sure where I screwed up.
/*
* gtk_init.cc
*/
#include <ffi.h>
#include <gtk/gtk.h>
void test();
int main(int argc, char *argv[]) {
test();
return 0;
}
void test() {
ffi_cif cif;
ffi_type *arg_types[2];
void *arg_values[2];
ffi_status status;
ffi_arg result;
arg_types[0] = &ffi_type_uint;
arg_types[1] = &ffi_type_pointer;
status = ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 2, &ffi_type_void, arg_types);
if (status != FFI_OK) {
printf("Failed to prep_ffi\n");
return;
}
int argc = 4;
char **argv = (char**)malloc(sizeof(char*) * argc);
argv[0] = strcpy((char*)malloc(sizeof(char) * 6), "test");
argv[1] = strcpy((char*)malloc(sizeof(char) * 13), "--gtk-debug");
argv[2] = strcpy((char*)malloc(sizeof(char) * 6), "misc");
argv[3] = strcpy((char*)malloc(sizeof(char) * 6), "last");
arg_values[0] = &argc;
arg_values[1] = &argv;
ffi_call(&cif, FFI_FN(gtk_init), &result, arg_values);
// gtk_init(&argc, &argv);
for (int i = 0; i < argc; i++) {
printf("%s\n", argv[i]);
free(argv[i]);
}
free(argv);
}
The complete gist can be found here.
The problem is that ffi_call()
take the address of the argument as gtk_init()
take int *
and char ***
you need to take the address of these so that give int **
and char ****
, fun ?
As said in comment gtk_init()
also expect argv
to be NULL
terminated.
And the final problem is that ffi_type_uint
is the wrong type you must use ffi_type_pointer
in this case (and by the way int
need ffi_type_sint
).
So the final fixed code is:
#include <ffi.h>
#include <gtk/gtk.h>
void test(void);
int main(void) { test(); }
void test(void) {
ffi_type *arg_types[] = {&ffi_type_pointer, &ffi_type_pointer};
ffi_cif cif;
ffi_status status =
ffi_prep_cif(&cif, FFI_DEFAULT_ABI, sizeof arg_types / sizeof *arg_types,
&ffi_type_void, arg_types);
if (status != FFI_OK) {
printf("Failed to prep_ffi\n");
return;
}
// bad we don't check malloc() !!! ;)
int argc = 4;
char **argv = malloc(sizeof *argv * (argc + 1));
#define X(x) strcpy(malloc(sizeof x), x);
argv[0] = X("test");
argv[1] = X("--gtk-debug");
argv[2] = X("misc");
argv[3] = X("last");
argv[4] = NULL;
#undef X
int *p_argc = &argc; // This is what expect gtk_init
char ***p_argv = &argv;
void *arg_values[] = {&p_argc, &p_argv}; // so ffi need their address
ffi_arg result;
ffi_call(&cif, FFI_FN(>k_init), &result, arg_values);
for (int i = 0; i < argc; i++) {
printf("%s\n", argv[i]);
free(argv[i]);
}
free(argv);
}
Disclaimer: Not tested.