cfortran

Segmentation fault when calling Fortran function with bind(C) from C (single-precision dual number struct)


I'm trying to call a Fortran function from C using bind(C) with a simple dual type that holds a value and its derivative (for forward-mode automatic differentiation).

I'm using single precision (float in C, real(c_float) in Fortran), and I made sure to match the struct layout.

However, when I run the program, I get a segmentation fault at runtime, even though everything compiles fine.

//main.c

#include <stdio.h>

typedef struct {
    float real;
    float diff;
} dual;

extern dual dual_pow_real(dual a, float b);

int main() {
 
    dual a;
    a.real = 2.0f;
    a.diff = 1.0f;
    
    
    dual result = dual_pow_real(a, (float) 3.00f);

    //printf("result = (%f, %f)\n", result.real, result.diff);
    return 0;
}
module dual_module

  use iso_c_binding 

  implicit none

  type, bind(c) :: dual
    real(c_float) :: real
    real(c_float) :: diff
  end type dual
    
  interface operator(**)
      module procedure pow_dual_real
  end interface operator(**)
    
contains

    function pow_dual_real(a, b) result(c) bind(C, name="dual_pow_real")
        
        type(dual), intent(in) :: a
        real(c_float), intent(in) :: b
        type(dual) :: c
        c%real = a%real ** b
        c%diff = b * (a%real ** (b - 1.0)) * a%diff
    end function pow_dual_real
                    
end module dual_module

I'm compiling with gfortran -c -fPIC, creating a shared library, and linking with gcc -o main main.c -L. -ldual -lgfortran.

I’ve set LD_LIBRARY_PATH=. before running.

Both dual structs match exactly (float/real(c_float)).

I tried to use double precision but got the same result.

I also tried calling the function without assigning the result, like this:
(void) dual_pow_real(a, 3.0f);
— but the segmentation fault still occurs, so the crash happens during the call itself, not when accessing the result.

I’ve tried printing debug statements — the main function runs up to the dual_pow_real call, then segfaults.

I tested this on both macOS with an Apple M2 (ARM64) and Ubuntu on an Intel i7 8th Gen (x86_64) — the segmentation fault occurs on both platforms, so the issue doesn't appear to be architecture-specific.

Any help will be highly appreciated.

Thank you


Solution

  • The function

    function pow_dual_real(a, b) result(c) bind(C, name="dual_pow_real")
            
            type(dual), intent(in) :: a
            real(c_float), intent(in) :: b
    

    expects two pointers (variables passed by reference). You are passing two scalars by value. Pass their addresses or add the value atribute on the Fortran side to the arguments.

    Either

        dual_pow_real(&a, &three);
    

    or

        type(dual), value :: a
        real(c_float), value :: b