Skip to content

Embedding Julia in C and using macro produces segmentation fault #43855

@AnHeuermann

Description

@AnHeuermann

Short description

I have Julia code that gets called from C. One of my Julia functions is using a macro to load a variable from a .bson file.
With that macro my executable produces a segmentation fault. Replacing the macro seems to solve my issue, so I suspect that there is either a problem in the Julia macro itself or that embedded Julia has some issue with macros in general.
But of course it could be that I have some bug in my C code as I'm fairly new to calling Julia from C.

I asked a question about this on discourse: https://discourse.julialang.org/t/embedded-julia-segmentation-fault-when-loading-bson-file/74795

How to reproduce

C sources

mwe.c

#include <stdio.h>
#include <stdlib.h>
#include <julia.h>

JULIA_DEFINE_FAST_TLS // only define this once, in an executable (not in a shared library) if you want fast code.

int main(int argc, char *argv[]){
  /* required: setup the Julia context */
  jl_init();

  jl_eval_string("Base.include(Main, \"mwe.jl\")");
  jl_eval_string("using Main.MWE");
  jl_module_t* MWE = (jl_module_t *)jl_eval_string("Main.MWE");

  /* Get loadNN and evalNN function */
  jl_function_t *loadVar = jl_get_function(MWE, "loadVar");
  jl_function_t *evalFunc = jl_get_function(MWE, "evalFunc");

  /* Create thin wrapper around arrays */
  jl_value_t* array_type = jl_apply_array_type((jl_value_t*)jl_float64_type, 1);

  size_t length_inputs = 2;
  double *inputs = (double*)calloc(length_inputs, sizeof(double));
  jl_array_t *jl_inputs = jl_ptr_to_array_1d(array_type, inputs, length_inputs, 0);

  size_t length_outputs = 2;
  double *outputs = (double*)calloc(length_outputs, sizeof(double));
  jl_array_t *jl_outputs = jl_ptr_to_array_1d(array_type, outputs, length_outputs, 0);

  /* Load data from BSON */
  const char filename[]= "savedVar.bson";
  jl_value_t *jl_filename = jl_cstr_to_string(filename);
  jl_call1(loadVar, (jl_value_t*)jl_filename);

  /* Evaluate NN */
  inputs[0] = 1.0;
  inputs[1] = 2.0;
  jl_call2(evalFunc, (jl_value_t*)jl_inputs, (jl_value_t*)jl_outputs);

  printf("Return value: [");
  for(int i=0; i<length_outputs-1; i++) {
    printf("%.1f, ", outputs[i]);
  }
  printf("%f]\n", outputs[length_outputs-1]);

  /* Notify Julia that programm is going to end */
  jl_atexit_hook(0);
  return 0;
}

Julia sources

mwe.jl

module MWE
  using BSON: @load, @save

  export loadVar
  export saveVar
  export evalFunc

  function saveVar(modelFile::String)
    someVar = [1.0, 2.0]
    @save abspath(modelFile) someVar
  end

  function loadVar(modelFile::String)
    @info "Loading var from \"$(modelFile)\""
    @load abspath(modelFile) someVar # Using the next two lines insted of the macro seems to work.
    #dict = BSON.load(modelFile)
    #someVar = dict[:someVar]
    println(someVar)
  end

  function evalFunc!(inputs::Array{Float64}, outputs::Array{Float64})
    @info "Inputs $(inputs)"
    @info "Outputs $(outputs)"
  end
end

Compile & Run

Create .bson file from Julia:

julia> include("mwe.jl")
julia> MWE.saveVar("savedVar.bson")

Compile sources and run:

$ export JULIA_PATH=/opt/julia/julia-1.7.1
$ clang -o mwe -fPIC -g -O0 -I$JULIA_PATH/include/julia -L$JULIA_PATH/lib -Wl,-rpath,$JULIA_PATH/lib mwe.c -ljulia

Try program mew:

$ ./mwe 
[ Info: Loading var from "savedVar.bson"
[1.0, 2.0]

signal (11): Segmentation fault
in expression starting at none:0
jl_object_id__cold at /buildworker/worker/package_linux64/build/src/builtins.c:400
type_hash at /buildworker/worker/package_linux64/build/src/jltypes.c:1125
typekey_hash at /buildworker/worker/package_linux64/build/src/jltypes.c:1137 [inlined]
jl_precompute_memoized_dt at /buildworker/worker/package_linux64/build/src/jltypes.c:1197
inst_datatype_inner at /buildworker/worker/package_linux64/build/src/jltypes.c:1510
jl_inst_arg_tuple_type at /buildworker/worker/package_linux64/build/src/jltypes.c:1606
arg_type_tuple at /buildworker/worker/package_linux64/build/src/gf.c:1845 [inlined]
jl_lookup_generic_ at /buildworker/worker/package_linux64/build/src/gf.c:2373 [inlined]
jl_apply_generic at /buildworker/worker/package_linux64/build/src/gf.c:2425
jl_apply at /buildworker/worker/package_linux64/build/src/julia.h:1788 [inlined]
jl_call2 at /buildworker/worker/package_linux64/build/src/jlapi.c:256
main at /home/andreas/publications/openmodelica-workshop-2022/example/callJuliaFromC/mwe.c:38
__libc_start_main at /lib/x86_64-linux-gnu/libc.so.6 (unknown line)
_start at ./mwe (unknown line)
Allocations: 1561933 (Pool: 1561377; Big: 556); GC: 2
Segmentation fault

GDB output:

(gdb) r
Starting program: /home/andreas/publications/openmodelica-workshop-2022/example/callJuliaFromC/mwe 
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
[New Thread 0x7ffff1f06700 (LWP 28205)]
[New Thread 0x7fffdf645700 (LWP 28206)]
[New Thread 0x7fffd6e44700 (LWP 28207)]
[New Thread 0x7fffce643700 (LWP 28208)]
[New Thread 0x7fffcde42700 (LWP 28209)]
[New Thread 0x7fffbd641700 (LWP 28210)]
[New Thread 0x7fffb4e40700 (LWP 28211)]
[New Thread 0x7fffac63f700 (LWP 28212)]
[ Info: Loading var from "savedVar.bson"
[1.0, 2.0]

Thread 1 "mwe" received signal SIGSEGV, Segmentation fault.
jl_object_id__cold (dt=0x0, v=0x7fffee2e4ae0) at /buildworker/worker/package_linux64/build/src/builtins.c:400
400     /buildworker/worker/package_linux64/build/src/builtins.c: No such file or directory.
(gdb) bt
#0  jl_object_id__cold (dt=0x0, v=0x7fffee2e4ae0) at /buildworker/worker/package_linux64/build/src/builtins.c:400
#1  0x00007ffff71bba60 in type_hash (kj=<optimized out>, failed=failed@entry=0x7fffffffd3bc) at /buildworker/worker/package_linux64/build/src/jltypes.c:1125
#2  0x00007ffff71bec6e in typekey_hash (nofail=<optimized out>, n=<optimized out>, key=<optimized out>, tn=<optimized out>) at /buildworker/worker/package_linux64/build/src/jltypes.c:1137
#3  jl_precompute_memoized_dt (dt=0x7fffedd25ff0, cacheable=<optimized out>, cacheable@entry=0) at /buildworker/worker/package_linux64/build/src/jltypes.c:1197
#4  0x00007ffff71c05e3 in inst_datatype_inner (dt=<optimized out>, p=<optimized out>, iparams=<optimized out>, ntp=ntp@entry=3, stack=0x7fffffffd470, stack@entry=0x0, env=env@entry=0x0)
    at /buildworker/worker/package_linux64/build/src/jltypes.c:1510
#5  0x00007ffff71c276f in jl_inst_arg_tuple_type (arg1=arg1@entry=0x7ffff15dc7c8, args=args@entry=0x7fffffffd658, nargs=nargs@entry=3, leaf=leaf@entry=1) at /buildworker/worker/package_linux64/build/src/jltypes.c:1606
#6  0x00007ffff71ce4ca in arg_type_tuple (nargs=3, args=0x7fffffffd658, arg1=0x7ffff15dc7c8) at /buildworker/worker/package_linux64/build/src/gf.c:1845
#7  jl_lookup_generic_ (world=31325, callsite=<optimized out>, nargs=3, args=0x7fffffffd658, F=0x7ffff15dc7c8) at /buildworker/worker/package_linux64/build/src/gf.c:2373
#8  jl_apply_generic (F=0x7ffff15dc7c8, args=0x7fffffffd658, nargs=2) at /buildworker/worker/package_linux64/build/src/gf.c:2425
#9  0x00007ffff7231065 in jl_apply (nargs=3, args=0x7fffffffd650) at /buildworker/worker/package_linux64/build/src/julia.h:1788
#10 jl_call2 (f=0x7ffff15dc7c8, a=0x7fffee2e4ac0, b=0x7fffee2e4af0) at /buildworker/worker/package_linux64/build/src/jlapi.c:256
#11 0x0000000000401394 in main (argc=1, argv=0x7fffffffd988) at mwe.c:38

Version 'n stuff

julia> versioninfo()
Julia Version 1.7.1
Commit ac5cc99908 (2021-12-22 19:35 UTC)
Platform Info:
  OS: Linux (x86_64-pc-linux-gnu)
  CPU: Intel(R) Core(TM) i7-10700KF CPU @ 3.80GHz
  WORD_SIZE: 64
  LIBM: libopenlibm
  LLVM: libLLVM-12.0.1 (ORCJIT, skylake)
(@v1.7) pkg> status BSON
      Status `~/.julia/environments/v1.7/Project.toml`
  [fbb218c0] BSON v0.3.4

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions