Segmentation fault when embedding Julia and using DifferentialEquations.jl

Hi, I need to embed Julia in a C library that is dynamically loaded and invoked from Python. I can make basic stuff work with the embedded Julia. However, when I try to import DifferentialEquations.jl, I get a segmentation fault with a very confusing traceback.

The minimal (non-) working example is:

import ctypes

call_julia_lib = ctypes.CDLL("./call_julia.so")
call_julia_lib.init_julia()
call_julia_lib.call_julia_good()
call_julia_lib.call_julia_bad()

call_julia.c:

#include <julia.h>

void init_julia(void) {
    jl_init();
}

void call_julia_good(void) {
    jl_eval_string("println(\"[call_julia_good] BEGIN\")");
    jl_eval_string("println(\"2 * 2 = \", 2 * 2))");
    jl_eval_string("println(\"[call_julia_good] END\")");
}

void call_julia_bad(void) {
    jl_eval_string("println(\"[call_julia_bad] BEGIN\")");
    jl_eval_string("using DifferentialEquations");
    if (jl_exception_occurred()) {
        fprintf(stderr, "error\n");
        exit(1);
    }
    jl_eval_string("println(\"[call_julia_bad] END\")");
}

Makefile:

JL_SHARE = $(shell julia -e 'print(joinpath(Sys.BINDIR, Base.DATAROOTDIR, "julia"))')

CFLAGS   += $(shell $(JL_SHARE)/julia-config.jl --cflags) -O0 -g
CXXFLAGS += $(shell $(JL_SHARE)/julia-config.jl --cflags)
LDFLAGS  += $(shell $(JL_SHARE)/julia-config.jl --ldflags)
LDLIBS   += $(shell $(JL_SHARE)/julia-config.jl --ldlibs)

.PHONY : all
all: call_julia.so

call_julia.so : call_julia.o
	$(CC) $(CFLAGS) $(CXXFLAGS) $< -o $@ -shared $(LDFLAGS) $(LDLIBS)

Invokation:

python call_julia.py

Expectation: things work.
Reality: I receive the following segmentation fault:

➜ python call_julia.py
[call_julia_good] BEGIN
2 * 2 = 4
[call_julia_good] END
[call_julia_bad] BEGIN

[333155] signal (11.1): Segmentation fault
in expression starting at none:1
initialize_env at /workspace/srcdir/gcc-13.2.0/libgomp/env.c:2062
unknown function (ip: 0x75342974a47d)
unknown function (ip: 0x75342974a567)
_dl_catch_exception at /lib/x86_64-linux-gnu/libc.so.6 (unknown line)
unknown function (ip: 0x753429751ff5)
_dl_catch_exception at /lib/x86_64-linux-gnu/libc.so.6 (unknown line)
unknown function (ip: 0x75342975234d)
unknown function (ip: 0x75342929063b)
_dl_catch_exception at /lib/x86_64-linux-gnu/libc.so.6 (unknown line)
_dl_catch_error at /lib/x86_64-linux-gnu/libc.so.6 (unknown line)
unknown function (ip: 0x75342929012d)
dlopen at /lib/x86_64-linux-gnu/libc.so.6 (unknown line)
ijl_load_dynamic_library at /cache/build/builder-amdci5-1/julialang/julia-release-1-dot-10/src/dlload.c:365
#dlopen#3 at ./libdl.jl:117
dlopen at ./libdl.jl:116 [inlined]
dlopen at ./libdl.jl:116
jfptr_dlopen_51541.1 at /home/dima/.julia/juliaup/julia-1.10.2+0.x64.linux.gnu/lib/julia/sys.so (unknown line)
_jl_invoke at /cache/build/builder-amdci5-1/julialang/julia-release-1-dot-10/src/gf.c:2894 [inlined]
ijl_apply_generic at /cache/build/builder-amdci5-1/julialang/julia-release-1-dot-10/src/gf.c:3076
__init__ at /home/dima/.julia/juliaup/julia-1.10.2+0.x64.linux.gnu/share/julia/stdlib/v1.10/CompilerSupportLibraries_jll/src/CompilerSupportLibraries_jll.jl:62
_jl_invoke at /cache/build/builder-amdci5-1/julialang/julia-release-1-dot-10/src/gf.c:2894 [inlined]
ijl_apply_generic at /cache/build/builder-amdci5-1/julialang/julia-release-1-dot-10/src/gf.c:3076
jl_apply at /cache/build/builder-amdci5-1/julialang/julia-release-1-dot-10/src/julia.h:1982 [inlined]
jl_module_run_initializer at /cache/build/builder-amdci5-1/julialang/julia-release-1-dot-10/src/toplevel.c:76
run_module_init at ./loading.jl:1134
register_restored_modules at ./loading.jl:1122
_include_from_serialized at ./loading.jl:1067
_tryrequire_from_serialized at ./loading.jl:1481
_require_search_from_serialized at ./loading.jl:1574
_require at ./loading.jl:1938
__require_prelocked at ./loading.jl:1812
jfptr___require_prelocked_80777.1 at /home/dima/.julia/juliaup/julia-1.10.2+0.x64.linux.gnu/lib/julia/sys.so (unknown line)
_jl_invoke at /cache/build/builder-amdci5-1/julialang/julia-release-1-dot-10/src/gf.c:2894 [inlined]
ijl_apply_generic at /cache/build/builder-amdci5-1/julialang/julia-release-1-dot-10/src/gf.c:3076
jl_apply at /cache/build/builder-amdci5-1/julialang/julia-release-1-dot-10/src/julia.h:1982 [inlined]
jl_f__call_in_world at /cache/build/builder-amdci5-1/julialang/julia-release-1-dot-10/src/builtins.c:831
#invoke_in_world#3 at ./essentials.jl:926 [inlined]
invoke_in_world at ./essentials.jl:923 [inlined]
_require_prelocked at ./loading.jl:1803
macro expansion at ./loading.jl:1790 [inlined]
macro expansion at ./lock.jl:267 [inlined]
__require at ./loading.jl:1753
jfptr___require_80742.1 at /home/dima/.julia/juliaup/julia-1.10.2+0.x64.linux.gnu/lib/julia/sys.so (unknown line)
_jl_invoke at /cache/build/builder-amdci5-1/julialang/julia-release-1-dot-10/src/gf.c:2894 [inlined]
ijl_apply_generic at /cache/build/builder-amdci5-1/julialang/julia-release-1-dot-10/src/gf.c:3076
jl_apply at /cache/build/builder-amdci5-1/julialang/julia-release-1-dot-10/src/julia.h:1982 [inlined]
jl_f__call_in_world at /cache/build/builder-amdci5-1/julialang/julia-release-1-dot-10/src/builtins.c:831
#invoke_in_world#3 at ./essentials.jl:926 [inlined]
invoke_in_world at ./essentials.jl:923 [inlined]
require at ./loading.jl:1746
jfptr_require_80739.1 at /home/dima/.julia/juliaup/julia-1.10.2+0.x64.linux.gnu/lib/julia/sys.so (unknown line)
_jl_invoke at /cache/build/builder-amdci5-1/julialang/julia-release-1-dot-10/src/gf.c:2894 [inlined]
ijl_apply_generic at /cache/build/builder-amdci5-1/julialang/julia-release-1-dot-10/src/gf.c:3076
jl_apply at /cache/build/builder-amdci5-1/julialang/julia-release-1-dot-10/src/julia.h:1982 [inlined]
call_require at /cache/build/builder-amdci5-1/julialang/julia-release-1-dot-10/src/toplevel.c:481 [inlined]
eval_import_path at /cache/build/builder-amdci5-1/julialang/julia-release-1-dot-10/src/toplevel.c:518
jl_toplevel_eval_flex at /cache/build/builder-amdci5-1/julialang/julia-release-1-dot-10/src/toplevel.c:752
jl_toplevel_eval_flex at /cache/build/builder-amdci5-1/julialang/julia-release-1-dot-10/src/toplevel.c:877
ijl_toplevel_eval_in at /cache/build/builder-amdci5-1/julialang/julia-release-1-dot-10/src/toplevel.c:985
ijl_eval_string at /cache/build/builder-amdci5-1/julialang/julia-release-1-dot-10/src/jlapi.c:117
call_julia_bad at /home/dima/dev/learn/2024-04-19-julia-package-problems/call_julia.c:17
ffi_call_unix64 at /home/dima/.conda/envs/um02-open-interfaces/lib/python3.11/lib-dynload/../../libffi.so.8 (unknown line)
ffi_call_int at /home/dima/.conda/envs/um02-open-interfaces/lib/python3.11/lib-dynload/../../libffi.so.8 (unknown line)
_call_function_pointer at /usr/local/src/conda/python-3.11.6/Modules/_ctypes/callproc.c:923 [inlined]
_ctypes_callproc at /usr/local/src/conda/python-3.11.6/Modules/_ctypes/callproc.c:1262
PyCFuncPtr_call at /usr/local/src/conda/python-3.11.6/Modules/_ctypes/_ctypes.c:4201
_PyObject_MakeTpCall at python (unknown line)
_PyEval_EvalFrameDefault at python (unknown line)
unknown function (ip: 0x59348889acbc)
PyEval_EvalCode at python (unknown line)
unknown function (ip: 0x5934888b9129)
unknown function (ip: 0x5934888b5432)
unknown function (ip: 0x5934888ca06f)
_PyRun_SimpleFileObject at python (unknown line)
_PyRun_AnyFileObject at python (unknown line)
Py_RunMain at python (unknown line)
Py_BytesMain at python (unknown line)
unknown function (ip: 0x753429229d8f)
__libc_start_main at /lib/x86_64-linux-gnu/libc.so.6 (unknown line)
unknown function (ip: 0x593488888eac)
Allocations: 542750 (Pool: 542140; Big: 610); GC: 1

Could someone please explain me what could be wrong with my approach?
Thank you!

The problem is with libgomp.so version gcc-13.2. It uses global variable environ (which it did not do before) and there is a mismatch between how libc and Python set this variable.

The fix is to replace libgomp.so with older version (for example, from Conda-packaged Python) or upgrade to Julia 1.10.3+.

Read for details here: Julia 1.10.2 crashes when embedded from Python due to `libgomp.so` compiled with GCC 13.2

1 Like