Strange error when calling a c function using ccall

I need to use code in c++, for which I made a c-style function and use ccall. I also have tried CxxWrap. In both cases, I sometimes got the following lengthy message when calling the c function.

free(): invalid pointer

signal (6): Aborted
in expression starting at none:0
unknown function (ip: 0x7fc4346ed64c)
gsignal at /usr/bin/../lib/libc.so.6 (unknown line)
abort at /usr/bin/../lib/libc.so.6 (unknown line)
unknown function (ip: 0x7fc4346e17ed)
unknown function (ip: 0x7fc4346f73db)
unknown function (ip: 0x7fc4346f922b)
__libc_free at /usr/bin/../lib/libc.so.6 (unknown line)
_ZN4llvm9AAResultsD2Ev at /usr/bin/../lib/julia/libLLVM-12jl.so (unknown line)
_ZN4llvm20AAResultsWrapperPass13runOnFunctionERNS_8FunctionE at /usr/bin/../lib/julia/libLLVM-12jl.so (unknown line)
_ZN4llvm13FPPassManager13runOnFunctionERNS_8FunctionE at /usr/bin/../lib/julia/libLLVM-12jl.so (unknown line)
_ZN4llvm13FPPassManager11runOnModuleERNS_6ModuleE at /usr/bin/../lib/julia/libLLVM-12jl.so (unknown line)
_ZN4llvm6legacy15PassManagerImpl3runERNS_6ModuleE at /usr/bin/../lib/julia/libLLVM-12jl.so (unknown line)
operator() at /buildworker/worker/package_linux64/build/src/jitlayers.cpp:612
_ZN4llvm3orc14IRCompileLayer4emitESt10unique_ptrINS0_29MaterializationResponsibilityESt14default_deleteIS3_EENS0_16ThreadSafeModuleE at /usr/bin/../lib/julia/libLLVM-12jl.so (unknown line)
_ZN4llvm3orc31BasicIRLayerMaterializationUnit11materializeESt10unique_ptrINS0_29MaterializationResponsibilityESt14default_deleteIS3_EE at /usr/bin/../lib/julia/libLLVM-12jl.so (unknown line)
_ZN4llvm3orc16ExecutionSession26materializeOnCurrentThreadESt10unique_ptrINS0_19MaterializationUnitESt14default_deleteIS3_EES2_INS0_29MaterializationResponsibilityES4_IS7_EE at /usr/bin/../lib/julia/libLLVM-12jl.so (unknown line)
_ZNSt17_Function_handlerIFvSt10unique_ptrIN4llvm3orc19MaterializationUnitESt14default_deleteIS3_EES0_INS2_29MaterializationResponsibilityES4_IS7_EEEPSA_E9_M_invokeERKSt9_Any_dataOS6_OS9_ at /usr/bin/../lib/julia/libLLVM-12jl.so (unknown line)
_ZN4llvm3orc16ExecutionSession22dispatchOutstandingMUsEv at /usr/bin/../lib/julia/libLLVM-12jl.so (unknown line)
_ZN4llvm3orc16ExecutionSession17OL_completeLookupESt10unique_ptrINS0_21InProgressLookupStateESt14default_deleteIS3_EESt10shared_ptrINS0_23AsynchronousSymbolQueryEESt8functionIFvRKNS_8DenseMapIPNS0_8JITDylibENS_8DenseSetINS0_15SymbolStringPtrENS_12DenseMapInfoISF_EEEENSG_ISD_EENS_6detail12DenseMapPairISD_SI_EEEEEE at /usr/bin/../lib/julia/libLLVM-12jl.so (unknown line)
_ZN4llvm3orc25InProgressFullLookupState8completeESt10unique_ptrINS0_21InProgressLookupStateESt14default_deleteIS3_EE at /usr/bin/../lib/julia/libLLVM-12jl.so (unknown line)
_ZN4llvm3orc16ExecutionSession19OL_applyQueryPhase1ESt10unique_ptrINS0_21InProgressLookupStateESt14default_deleteIS3_EENS_5ErrorE at /usr/bin/../lib/julia/libLLVM-12jl.so (unknown line)
_ZN4llvm3orc16ExecutionSession6lookupENS0_10LookupKindERKSt6vectorISt4pairIPNS0_8JITDylibENS0_19JITDylibLookupFlagsEESaIS8_EENS0_15SymbolLookupSetENS0_11SymbolStateENS_15unique_functionIFvNS_8ExpectedINS_8DenseMapINS0_15SymbolStringPtrENS_18JITEvaluatedSymbolENS_12DenseMapInfoISI_EENS_6detail12DenseMapPairISI_SJ_EEEEEEEEESt8functionIFvRKNSH_IS6_NS_8DenseSetISI_SL_EENSK_IS6_EENSN_IS6_SV_EEEEEE at /usr/bin/../lib/julia/libLLVM-12jl.so (unknown line)
_ZN4llvm3orc16ExecutionSession6lookupERKSt6vectorISt4pairIPNS0_8JITDylibENS0_19JITDylibLookupFlagsEESaIS7_EERKNS0_15SymbolLookupSetENS0_10LookupKindENS0_11SymbolStateESt8functionIFvRKNS_8DenseMapIS5_NS_8DenseSetINS0_15SymbolStringPtrENS_12DenseMapInfoISK_EEEENSL_IS5_EENS_6detail12DenseMapPairIS5_SN_EEEEEE at /usr/bin/../lib/julia/libLLVM-12jl.so (unknown line)
_ZN4llvm3orc16ExecutionSession6lookupERKSt6vectorISt4pairIPNS0_8JITDylibENS0_19JITDylibLookupFlagsEESaIS7_EENS0_15SymbolStringPtrENS0_11SymbolStateE at /usr/bin/../lib/julia/libLLVM-12jl.so (unknown line)
_ZN4llvm3orc16ExecutionSession6lookupENS_8ArrayRefIPNS0_8JITDylibEEENS0_15SymbolStringPtrENS0_11SymbolStateE at /usr/bin/../lib/julia/libLLVM-12jl.so (unknown line)
_ZN4llvm3orc16ExecutionSession6lookupENS_8ArrayRefIPNS0_8JITDylibEEENS_9StringRefENS0_11SymbolStateE at /usr/bin/../lib/julia/libLLVM-12jl.so (unknown line)
addModule at /buildworker/worker/package_linux64/build/src/jitlayers.cpp:779
jl_add_to_ee at /buildworker/worker/package_linux64/build/src/jitlayers.cpp:1059
jl_add_to_ee at /buildworker/worker/package_linux64/build/src/jitlayers.cpp:1103
jl_add_to_ee at /buildworker/worker/package_linux64/build/src/jitlayers.cpp:1125 [inlined]
_jl_compile_codeinst at /buildworker/worker/package_linux64/build/src/jitlayers.cpp:154
jl_generate_fptr at /buildworker/worker/package_linux64/build/src/jitlayers.cpp:350
jl_compile_method_internal at /buildworker/worker/package_linux64/build/src/gf.c:1980
jl_compile_method_internal at /buildworker/worker/package_linux64/build/src/gf.c:2246 [inlined]
_jl_invoke at /buildworker/worker/package_linux64/build/src/gf.c:2239 [inlined]
jl_apply_generic at /buildworker/worker/package_linux64/build/src/gf.c:2429
#43 at /buildworker/worker/package_linux64/build/usr/share/julia/stdlib/v1.7/REPL/src/REPL.jl:266
jfptr_YY.43_49069.clone_1 at /usr/lib/julia/sys.so (unknown line)
_jl_invoke at /buildworker/worker/package_linux64/build/src/gf.c:2247 [inlined]
jl_apply_generic at /buildworker/worker/package_linux64/build/src/gf.c:2429
with_repl_linfo at /buildworker/worker/package_linux64/build/usr/share/julia/stdlib/v1.7/REPL/src/REPL.jl:510
_jl_invoke at /buildworker/worker/package_linux64/build/src/gf.c:2247 [inlined]
jl_apply_generic at /buildworker/worker/package_linux64/build/src/gf.c:2429
display at /buildworker/worker/package_linux64/build/usr/share/julia/stdlib/v1.7/REPL/src/REPL.jl:259
display at /buildworker/worker/package_linux64/build/usr/share/julia/stdlib/v1.7/REPL/src/REPL.jl:271
_jl_invoke at /buildworker/worker/package_linux64/build/src/gf.c:2247 [inlined]
jl_apply_generic at /buildworker/worker/package_linux64/build/src/gf.c:2429
display at ./multimedia.jl:328
_jl_invoke at /buildworker/worker/package_linux64/build/src/gf.c:2247 [inlined]
jl_apply_generic at /buildworker/worker/package_linux64/build/src/gf.c:2429
jl_apply at /buildworker/worker/package_linux64/build/src/julia.h:1788 [inlined]
jl_f__call_latest at /buildworker/worker/package_linux64/build/src/builtins.c:757
#invokelatest#2 at ./essentials.jl:716 [inlined]
invokelatest at ./essentials.jl:714 [inlined]
print_response at /buildworker/worker/package_linux64/build/usr/share/julia/stdlib/v1.7/REPL/src/REPL.jl:293
#45 at /buildworker/worker/package_linux64/build/usr/share/julia/stdlib/v1.7/REPL/src/REPL.jl:277
jfptr_YY.45_47416.clone_1 at /usr/lib/julia/sys.so (unknown line)
_jl_invoke at /buildworker/worker/package_linux64/build/src/gf.c:2247 [inlined]
jl_apply_generic at /buildworker/worker/package_linux64/build/src/gf.c:2429
with_repl_linfo at /buildworker/worker/package_linux64/build/usr/share/julia/stdlib/v1.7/REPL/src/REPL.jl:510
_jl_invoke at /buildworker/worker/package_linux64/build/src/gf.c:2247 [inlined]
jl_apply_generic at /buildworker/worker/package_linux64/build/src/gf.c:2429
print_response at /buildworker/worker/package_linux64/build/usr/share/julia/stdlib/v1.7/REPL/src/REPL.jl:275
do_respond at /buildworker/worker/package_linux64/build/usr/share/julia/stdlib/v1.7/REPL/src/REPL.jl:846
jfptr_do_respond_47228.clone_1 at /usr/lib/julia/sys.so (unknown line)
_jl_invoke at /buildworker/worker/package_linux64/build/src/gf.c:2247 [inlined]
jl_apply_generic at /buildworker/worker/package_linux64/build/src/gf.c:2429
jl_apply at /buildworker/worker/package_linux64/build/src/julia.h:1788 [inlined]
jl_f__call_latest at /buildworker/worker/package_linux64/build/src/builtins.c:757
#invokelatest#2 at ./essentials.jl:716 [inlined]
invokelatest at ./essentials.jl:714 [inlined]
run_interface at /buildworker/worker/package_linux64/build/usr/share/julia/stdlib/v1.7/REPL/src/LineEdit.jl:2493
jfptr_run_interface_47761.clone_1 at /usr/lib/julia/sys.so (unknown line)
_jl_invoke at /buildworker/worker/package_linux64/build/src/gf.c:2247 [inlined]
jl_apply_generic at /buildworker/worker/package_linux64/build/src/gf.c:2429
run_frontend at /buildworker/worker/package_linux64/build/usr/share/julia/stdlib/v1.7/REPL/src/REPL.jl:1232
#49 at ./task.jl:429
jfptr_YY.49_47185.clone_1 at /usr/lib/julia/sys.so (unknown line)
_jl_invoke at /buildworker/worker/package_linux64/build/src/gf.c:2247 [inlined]
jl_apply_generic at /buildworker/worker/package_linux64/build/src/gf.c:2429
jl_apply at /buildworker/worker/package_linux64/build/src/julia.h:1788 [inlined]
start_task at /buildworker/worker/package_linux64/build/src/task.c:877
Allocations: 2465718 (Pool: 2464978; Big: 740); GC: 2
Aborted (core dumped)

and it crashes the julia session.

This error seems to happen randomly, but I notice that if it appears and crashes julia, then it is more likely that it appears again immediately after I restart julia and call the same function.

I think it is related to the library I call, but the library has been tested quite long and we do not have this issue when they are used in c++. Maybe related to the way I compiled it? Anyone has ideas about this issue? Thanks.

I think this is an memory-related issue. What I need is passing a julia vector to the C function. Currently, I pass Ptr{myVec} to the C function, which has double * as the corresponding type. I guess this causes some problems at the end. What is the recommended way to pass an data array to a C function?

Do you mind sharing a minimal example? The error log is not informative.

Currently, I pass Ptr{myVec} to the C function, which has double * as the corresponding type.

This clearly won’t do, as pointer to a Julia object is not a pointer to its data. Maybe Calling C and Fortran Code · The Julia Language will help.

Yes, the julia code is the following

const PATH_TO_LIB = ".../path_to_mylib"
function f_GF(xs::Vector{Float64})
    ccall((:GF, PATH_TO_LIB), Cdouble, (Ptr{Cdouble}, Csize_t), xs, length(xs))
end

The c++ code has the following structure:

myClass globalObj(....); 

extern "C" {

double GF(double *array_in, size_t numElm) {
  std::vector<double> xs(numElm);
  for(int i=0; i<numElm; i++) {
    xs[i]=array_in[i];
  }
  std::complex<double> res = globlaObj.someFunc(...);
  return res;
}

By the way, the manual uses Ptr{} and I just follows. Obviously I didn’t really understand its meaning and how to correctly pass an array to the c/c++ library. What should I do? Thank you.

The ccall is fine. I would worry more about possible library clashes. What libraries are your C++ code linked with?

The “library” is actually a single-file cpp, which uses boost and a library we developed before. That library is well-tested and used for a while without problems. It uses Eigen.

I tried a stupid solution:

 ccall((:GF8, PATH_TO_LIB), Cdouble, (Cdouble, Cdouble, Cdouble, Cdouble, Cdouble, Cdouble, Cdouble, Cdouble, Cdouble),
          xs[1],xs[2],xs[3],xs[4],xs[5],xs[6],xs[7],xs[8],xs[9]
          )

Instead of a function taking an array, I pass values directly. With this most time I can run the program in REPL, but after that exit() causes

signal (11): Segmentation fault
in expression starting at REPL[2]:1

However, if I run the ccall before I really run the program (which calls the library many times) this issue seems to disappear, and the julia session ends normally. Very strange behavior.

You can try to explicitly open your library with Libdl.dlopen and see if any RTLD_* flag makes a difference. Cf. loading pytorch causes invalid pointer crash on free() · Issue #973 · JuliaPy/PyCall.jl · GitHub, which has a vaguely similar failure mode.

Changed to 1.8.5, and I got this on exit() when passing Ref{}

corrupted size vs. prev_size

signal (6): Aborted
in expression starting at REPL[3]:1

Is there any reference for those RTLD_*?

Those are described in manual pages for dlopen, e.g. dlopen(3) - Linux manual page.

1 Like

Thank you. Without those RTLD_* parameters, I have

const lib = Libdl.dlopen(PATH_TO_LIB)
const sym = Libdl.dlsym(lib, :GF)  
function f_GF(xs::Vector{Float64})
    ccall(sym, Cdouble, (Ref{Cdouble}, Csize_t), xs, length(xs))
end

This code seems to work quite well. Sometimes I still got segmentation faults when exit(), but overall it seems usable. I tested it on julia 1.6.7 and 1.8.5. Both gave similar behaviors.

Any explanation for the difference, although I think loading a library explicitly seems more reasonable by itself?

The problem is probably within your c++ code, here is an example that won’t error:

// lib.cpp
#include <iostream>
extern "C" {
double GF(double *array, size_t num) {
    for (size_t i = 0; i < num; i++) {
        std::cout << array[i];
    }
    return 1.234;
}
}
# CMakeLists.txt
cmake_minimum_required(VERSION 3.12)
project(ccall-playground)
add_library(lib SHARED lib.cpp)
set_target_properties(lib PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON)
const lib = "build/Debug/lib.dll"
function GF(array)
    @ccall lib.GF(array::Ptr{Cdouble}, length(array)::Csize_t)::Cdouble
end
GF(Float64[1,2,3])

Also note that writing the wrapper is tedious, so you can use Clang.jl or CBinding.jl.

Yeah, I really have no idea what’s wrong. Thanks for providing the code including the cmake setup.