csegmentation-faultffilibffi

libffi segmentation fault with void function


I can't determine the cause of crash of this code:

#define MACOSX
#include <assert.h>
#include <stdint.h>
#include <stdio.h>
#include <ffi/ffi.h>

void sum(int64_t *a, int64_t *b, int64_t *c) {
      *c = *a + *b;
}

int main() {
      int64_t ai = 1, bi = 2, ci;

      ffi_cif cif;
      ffi_status status;
      ffi_type *arg_types[] = {
            &ffi_type_pointer,
            &ffi_type_pointer,
            &ffi_type_pointer,
      };
      void *args[] = {&ai, &bi, &ci};

      status = ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 3, &ffi_type_void, arg_types);
      assert(status == FFI_OK);

      ffi_call(&cif, FFI_FN(sum), NULL, args);

      printf("%lld\n", ci);

      return 0;
}

It fails with segmentation fault error. As I know ffi_call must ignore return value pointer if ffi_prep_cif is called with ffi_type_void.

UPDATE

lldb output:

* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x1)
    frame #0: 0x0000000100000dd4 a.out`sum(a=0x0000000000000001, b=0x0000000000000002, c=0x00007fff5fbffac0) at main2.c:8
   5    #include <ffi/ffi.h>
   6    
   7    void sum(int64_t *a, int64_t *b, int64_t *c) {
-> 8          *c = *a + *b;
   9    }
   10   
   11   int main() {

So, it crashes inside the void function (attempting to dereference a?, * before a was underlined).


Solution

  • You have a problem with level of indirection. Your CIF is correct for the function presented, but the actual arguments you send to it (the elements of array args) are not.

    The elements of the argument array should be pointers to the argument values. When the function parameters are of pointer type, that means you must pass pointers to appropriate pointer values. Instead, you attempt to pass the actual values directly. As a result, the function implementation attempts to dereference the integer value of a (1) as if it were a pointer value.

    For a function with the signature and CIF you present, an FFI call to it might look like this:

      int64_t ai = 1, bi = 2, ci;
      int64_t *ap = &ai, *bp = &bi, *cp = &ci;
      void *args[] = {&ap, &bp, &cp};  // <-- pointers to the (pointer) arguments
    
      // ...
    
      ffi_call(&cif, FFI_FN(sum), NULL, args);