How do you correctly align array memory when using unsafe_store! to write a struct array to a c or fortran program?

I have a julia program, which opens a fortran shared object library, writes to a global type(struct) array and then calls a function, which accesses this variable.
The problem is that the values entered in the julia struct do not correspond to the values extracted in the fortran code:

test.jl:

using Base.Libc.Libdl
using Base.Libc

mutable struct jul_param
    f1::Float64
    f2::Float64
    testbool::Bool
    teststring::String
end

try
    # create jul_param struct array of size 2 and store pointer in ptr_jul_struct_array
    testparam = jul_param(1.0, 2.0, true, "output1")
    ptr_jul_struct_array = convert(Ptr{jul_param}, calloc(2, sizeof(jul_param)))
    unsafe_store!(ptr_jul_struct_array,testparam,1)
    unsafe_store!(ptr_jul_struct_array,testparam,2)

    # fetch the memory address of global allocatable test_param type array in fortran 
    testmodule_bin = Libdl.dlopen("testmodule.so")
    test_param_sym = Libdl.dlsym(testmodule_bin, Symbol("__testmodule_MOD_test_param"))
    ptr_fortran_type_array = convert(Ptr{Ptr{jul_param}}, test_param_sym)
    unsafe_store!(ptr_fortran_type_array, ptr_jul_struct_array)

    # call test_func in fortran program
    function_sym = Libdl.dlsym(testmodule_bin, Symbol("__testmodule_MOD_test_func"))
    ccall(function_sym,Cvoid,())
catch e
    println("Error: ", e)
    rethrow(e)
end

testmodule.f90:

module testmodule

  type :: JulParam
    real :: &
      f1, &
      f2
    logical :: &
      testbool
    character(len=256), allocatable, dimension(:) :: &
      teststring
  end type JulParam

  type(JulParam),     allocatable, dimension(:) :: test_param

  contains

  module subroutine test_func()
    print *, "test size", size(test_param) !returns 1 instead of 2
    print *, "test val1", test_param(1)%f1 !returns random floats that change on every call instead of 1.0
    print *, "test val2", test_param(1)%teststring !generates segmentation fault
  end subroutine test_func

end module testmodule

I am using this command to run this program:

gfortran -fpic -c testmodule.f90 && gfortran -shared -o testmodule.so testmodule.o && julia test.jl

Is there a way to convert the memory layout of the julia struct so it can be read properly from within the fortran program?

Related posts:

I don’t know what the layout of the Fortran type would be, so that’s hard to answer. If you can explain what the Fortran type’s layout would be, then it becomes possible to help.

I suspect the len parameter in fortran causes the string to be allocated inline - this is not the case of the general String type in julia, which is internally stored as a pointer due to the dynamic length of a string. Depending on what exactly that character(256) is, you’re probably looking for something like NTuple{256, UInt8} (or another element type).

1 Like

I think there he has an allocatable vector of strings of length 256 (each character in Fortran is effectively 8 bits).

Maybe what is needed in the Fortran side is

character(len=1), allocatable::string(:)

which is a allocatable vector of characters.

Still one would need to guarantee that only 8 bit characters are used in the Julia string.