# Embedded Julia segmentation fault when loading BSON file

**URL:** <https://discourse.julialang.org/t/embedded-julia-segmentation-fault-when-loading-bson-file/74795>\
**Category:** General Usage\
**Tags:** embedding, c\
**Created:** [January 18, 2022, 11:50am UTC](https://discourse.julialang.org/t/embedded-julia-segmentation-fault-when-loading-bson-file/74795 "2022-01-18T11:50:22Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![AnHeuermann](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/anheuermann/32/27059_2.png) [@AnHeuermann](https://discourse.julialang.org/u/AnHeuermann)\
**Post date:** [January 18, 2022, 11:50am UTC](https://discourse.julialang.org/t/embedded-julia-segmentation-fault-when-loading-bson-file/74795/1 "2022-01-18T11:50:22Z")

</div>

# Description

I have some Julia function that I want to call from C. I have saved some Julia variable inside a BSON file that needs to be loaded before that Julia function is called.

Calling Julia from C works and loading the Julia variable from .bson as well. But calling a second function right after fails with a segmentation fault. I’m not sure if this is a bug or I’m missing anything.  
When I remove the `BSON.@load` evaluation from the first function the second function runs fine.

## Minimal Working Example

### C sources

mwe.c

```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();

  /* Load Julia sources */
  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 */
  jl_call2(evalFunc, (jl_value_t*)jl_inputs, (jl_value_t*)jl_outputs);

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

```

### Julia sources

mwe.jl

```julia
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 # Removing this line solves the segmentation fault
    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-repl
julia> include("mwe.jl")
julia> MWE.saveVar("savedVar.bson")

```

Compile sources and run:

```bash
$ 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`:

```bash
$ ./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:36
__libc_start_main at /lib/x86_64-linux-gnu/libc.so.6 (unknown line)
_start at ./mwe (unknown line)
Allocations: 1561945 (Pool: 1561389; Big: 556); GC: 2
Segmentation fault

```

GDB output:

```julia-auto
Thread 1 "mwe" received signal SIGSEGV, Segmentation fault.
jl_object_id__cold (dt=0x0, v=0x7fffee2e4ab0) 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=0x7fffee2e4ab0) at /buildworker/worker/package_linux64/build/src/builtins.c:400
#1 0x00007ffff71bba60 in type_hash (kj=<optimized out>, failed=failed@entry=0x7fffffffd39c) 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=0x7fffffffd450, 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=0x7ffff15dc7f8, args=args@entry=0x7fffffffd638, 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=0x7fffffffd638, arg1=0x7ffff15dc7f8) at /buildworker/worker/package_linux64/build/src/gf.c:1845
#7 jl_lookup_generic_ (world=31325, callsite=<optimized out>, nargs=3, args=0x7fffffffd638, F=0x7ffff15dc7f8) at /buildworker/worker/package_linux64/build/src/gf.c:2373
#8 jl_apply_generic (F=0x7ffff15dc7f8, args=0x7fffffffd638, nargs=2) at /buildworker/worker/package_linux64/build/src/gf.c:2425
#9 0x00007ffff7231065 in jl_apply (nargs=3, args=0x7fffffffd630) at /buildworker/worker/package_linux64/build/src/julia.h:1788
#10 jl_call2 (f=0x7ffff15dc7f8, a=0x7fffee2e4a90, b=0x7fffee2e4ac0) at /buildworker/worker/package_linux64/build/src/jlapi.c:256
#11 0x0000000000401360 in main (argc=1, argv=0x7fffffffd958) at mwe.c:36

```

---

<div class="post-metadata">

**Author:** ![AnHeuermann](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/anheuermann/32/27059_2.png) [@AnHeuermann](https://discourse.julialang.org/u/AnHeuermann)\
**Post date:** [January 18, 2022, 3:00pm UTC](https://discourse.julialang.org/t/embedded-julia-segmentation-fault-when-loading-bson-file/74795/2 "2022-01-18T15:00:00Z")

</div>

Seems I found a bug and the macro did screw up my code. Replacing

```julia
@load abspath(modelFile) someVar

```

with

```julia
dict = BSON.load(modelFile)
someVar = dict[:someVar]

```

seems to solve my issue. I’ve opened a ticket about this: [https://github.com/JuliaLang/julia/issues/43855](https://github.com/JuliaLang/julia/issues/43855)

---

<div class="post-metadata">

**Author:** ![jameson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jameson/32/23_2.png) [@jameson](https://discourse.julialang.org/u/jameson)\
**Post date:** [January 18, 2022, 6:40pm UTC](https://discourse.julialang.org/t/embedded-julia-segmentation-fault-when-loading-bson-file/74795/3 "2022-01-18T18:40:03Z")

</div>

In your code, you need to add GC-roots for every value that you use:

```julia
jl_function_t *loadVar = NULL;
jl_function_t *evalFunc = NULL;
jl_value_t* array_type = NULL;
jl_array_t *jl_inputs = NULL;
jl_array_t *jl_outputs = NULL;
jl_init();
JL_GC_PUSH5(&loadVar, &evalFunc, &array_type, &jl_inputs, &jl_outputs);

....

JL_GC_POP();
return 0;

```

---

<div class="post-metadata">

**Author:** ![AnHeuermann](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/anheuermann/32/27059_2.png) [@AnHeuermann](https://discourse.julialang.org/u/AnHeuermann)\
**Post date:** [January 19, 2022, 10:49am UTC](https://discourse.julialang.org/t/embedded-julia-segmentation-fault-when-loading-bson-file/74795/4 "2022-01-19T10:49:32Z")

</div>

Thanks for the answer! I got it to run as expected.

I think part of my problem is that there seems to be an issue with BSON inside modules as well: [https://github.com/FluxML/Flux.jl/issues/1322](https://github.com/FluxML/Flux.jl/issues/1322)  
So Julia did throw an error which I didn’t caught or checked for in the C code.

Here is now my working code:

C code

```nohighlight
#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[]){
  /* Variables */
  jl_function_t *loadVar = NULL;
  jl_function_t *evalFunc = NULL;
  jl_value_t* array_type = NULL;
  jl_array_t *jl_inputs = NULL;
  jl_array_t *jl_outputs = NULL;
  jl_value_t *jl_filename = NULL;

  /* required: setup the Julia context */
  jl_init();

  /* GC rooting */
  JL_GC_PUSH6(&loadVar, &evalFunc, &array_type, &jl_inputs, &jl_outputs, &jl_filename);

  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 */
  loadVar = jl_get_function(MWE, "loadVar");
  evalFunc = jl_get_function(MWE, "evalFunc");

  /* Create thin wrapper around arrays */
  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_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_outputs = jl_ptr_to_array_1d(array_type, outputs, length_outputs, 0);

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

  /* Evaluate NN */
  jl_call2(evalFunc, (jl_value_t*)jl_inputs, (jl_value_t*)jl_outputs);

  /* Release GC roots */
  JL_GC_POP();

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

```

Julia code

```julia
module MWE
  using BSON
  using BSON: @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)\""
    someVar = "missing"
    try
      someVar = BSON.load(abspath(modelFile), @ __MODULE__ )[:someVar]
    catch err
      println(err)
    end
    println("someVar: ", someVar)
  end

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

```

```bash
$ ./mwe 
[ Info: Loading var from "savedVar.bson"
someVar: [1.0, 2.0]
[Info: Inputs [0.0, 0.0]
[Info: Outputs [0.0, 0.0]

```
