Segmentation fault on ccall

ccall
bug
debug

#1

I have implemented an algorithm for image segmentation, and I am trying to interface the C++ compiled shared library through Julia. The code seems to be working properly on a test.cpp file which uses the same C-API (provided below) and links to the shared object file. However, I get a signal (11): Segmentation fault from Julia. I assume I am messing up with the ccall, since test.cpp works fine.

I would appreciate if you spotted the bug and helped me.

Below is the API header.

#ifndef API_H_
#define API_H_

#include <stdint.h>

#ifdef __cplusplus
extern "C" {
#endif

struct rgb {
  uint8_t comp1, comp2, comp3;
};

struct lab_f {
  float comp1, comp2, comp3;
};

struct lab_d {
  double comp1, comp2, comp3;
};

void palc_rgb_f(const rgb *pixels, int32_t h, int32_t w, int64_t *L,
                const float *E, int64_t k, float s1, float s2, float C);

void palc_rgb_d(const rgb *pixels, int32_t h, int32_t w, int64_t *L,
                const double *E, int64_t k, double s1, double s2, double C);

#ifdef __cplusplus
}
#endif

#endif

with the following API implementation, where superpixel::algorithm::palc is a templated C++ function:

#include "api.h"
#include "algorithm/palc.cpp"

using namespace superpixel;

extern "C" {
void palc_rgb_f(const rgb *pixels, int32_t h, int32_t w, int64_t *L,
                const float *E, int64_t k, float s1, float s2, float C) {
  algorithm::palc(pixels, h, w, L, E, k, s1, s2, C);
}

void palc_rgb_d(const rgb *pixels, int32_t h, int32_t w, int64_t *L,
                const double *E, int64_t k, double s1, double s2, double C) {
  algorithm::palc(pixels, h, w, L, E, k, s1, s2, C);
}

}

Finally, I try to use it in the following test-mwe.jl file:

import Base: convert

immutable MyRGB
  r::UInt8
  g::UInt8
  b::UInt8

  function (::Type{MyRGB})(r::Integer, g::Integer, b::Integer)
    new(r, g, b)
  end

  function (::Type{MyRGB})(px::UInt32)
    new((px >> 16) & 0xff, (px >> 8) & 0xff, px & 0xff)
  end
end

function convert(::Type{UInt32}, m::MyRGB)
  r, g, b = UInt32.((m.r, m.g, m.b))
  return (r << 16) + (g << 8) + b
end

const libhandle   = Libdl.dlopen(joinpath(pwd(), "libpalc"))
const palc_rgb_f  = Libdl.dlsym(libhandle, :palc_rgb_f)
const palc_rgb_d  = Libdl.dlsym(libhandle, :palc_rgb_d)

function palc!(pixels::Matrix{MyRGB}, L::Matrix{Int64}, E::Matrix{Float32},
  k::Int64, s1::Float32, s2::Float32, C::Float32)
  ccall(palc_rgb_f, Void, (Ref{MyRGB}, Cint, Cint, Ref{Clong}, Ref{Cfloat},
    Clong, Cfloat, Cfloat, Cfloat), pixels, size(pixels,1), size(pixels,2),
    L, E, k, s1, s2, C)
  return L
end

function palc!(pixels::Matrix{MyRGB}, L::Matrix{Int64}, E::Matrix{Float64},
  k::Int64, s1::Float64, s2::Float64, C::Float64)
  ccall(palc_rgb_d, Void, (Ref{MyRGB}, Cint, Cint, Ref{Clong}, Ref{Cdouble},
    Clong, Cdouble, Cdouble, Cdouble), pixels, size(pixels,1), size(pixels,2),
    L, E, k, s1, s2, C)
  return L
end

smallimg = fill(MyRGB(1,100,150), 5, 5)
L = Matrix(reshape(1:length(smallimg), size(smallimg)))
E = zeros(size(smallimg))

palc!(smallimg, L, E, 5, 0.2, 40.0, 4.0)

EDIT. The Julia code edited to take into account @yuyichao’s comment on MyRGB type definition.

I receive the following error:

signal (11): Segmentation fault
while loading no file, in expression starting on line 0
palc<rgb, int, double, long int> at /home/aytekin/Documents/My_Gits/Other/va-playground/src/algorithm/palc.cpp:168
palc_rgb_d at /home/aytekin/Documents/My_Gits/Other/va-playground/src/api.cpp:14
palc! at /home/aytekin/Documents/My_Gits/Other/va-playground/test-mwe.jl:36
unknown function (ip: 0x7f15d2f5421c)
jl_call_fptr_internal at /root/Julia/src/julia_internal.h:339 [inlined]
jl_call_method_internal at /root/Julia/src/julia_internal.h:358 [inlined]
jl_apply_generic at /root/Julia/src/gf.c:1926
do_call at /root/Julia/src/interpreter.c:75
eval at /root/Julia/src/interpreter.c:242
jl_interpret_toplevel_expr at /root/Julia/src/interpreter.c:34
jl_toplevel_eval_flex at /root/Julia/src/toplevel.c:577
jl_toplevel_eval_in at /root/Julia/src/builtins.c:496
eval at ./boot.jl:235
unknown function (ip: 0x7f15e2cc35ef)
jl_call_fptr_internal at /root/Julia/src/julia_internal.h:339 [inlined]
jl_call_method_internal at /root/Julia/src/julia_internal.h:358 [inlined]
jl_apply_generic at /root/Julia/src/gf.c:1926
eval_user_input at ./REPL.jl:66
unknown function (ip: 0x7f15e2d4718f)
jl_call_fptr_internal at /root/Julia/src/julia_internal.h:339 [inlined]
jl_call_method_internal at /root/Julia/src/julia_internal.h:358 [inlined]
jl_apply_generic at /root/Julia/src/gf.c:1926
macro expansion at ./REPL.jl:97 [inlined]
#1 at ./event.jl:73
unknown function (ip: 0x7f15d2f3937f)
jl_call_fptr_internal at /root/Julia/src/julia_internal.h:339 [inlined]
jl_call_method_internal at /root/Julia/src/julia_internal.h:358 [inlined]
jl_apply_generic at /root/Julia/src/gf.c:1926
jl_apply at /root/Julia/src/julia.h:1424 [inlined]
start_task at /root/Julia/src/task.c:267
unknown function (ip: 0xffffffffffffffff)
Allocations: 1675501 (Pool: 1674243; Big: 1258); GC: 1
fish: “julia” terminated by signal SIGSEGV (Address boundary error)

Am I doing something wrong during the ccall?

And aside, do I still need to use Cint and Clong even when I am using fixed-size C-types as in the example, or can I simply use UInt8 or UInt64 inside ccall in place of uint8_t and uint64_t, respectively?


#2

The convert is not necessary.

UInt32.((m.r, m.g, m.b)), at least on 0.6.

This will cause the array to have the wrong layout. Use immutable.


#3

Thank you again, for your response, @yuyichao.

I think the above two are not directly related to my problem, but good practices for simpler and more efficient code, right?

Changing the code to have immutable did not solve my problem, either. And, currently, I am not changing anything (as per the C API) inside the library. But what if I wanted to change MyRGB.r field, using the pointer? I cannot define immutable then, can I?

What do you think the problem might be? Is there a way to debug the code in Julia that uses some shared library calls?

And should I still use Cint in Julia for int32_t of C/C++ functions?


#4

Right.

You can. You just need to make sure the pointer points to mutable memory. Arrays holding immutable type is still mutable memory.

gdb…

These two are the same on all platforms we currently support. Using Cint and Int32 for int and int32_t respectively is still recommended just for documentation…


#5

Could you please elaborate on this? Even if MyRGB is immutable, can I still pass pixels::Matrix{MyRGB} to a library function that expects MyRGB* and writes pixels[idx].r = 1, for instance?

Is it simply gdb julia and run from there, or do I need to know something more specific regarding julia?

Basically, it is safe to use the Julia counterparts of the plain-old, fixed-size C/C++ datatypes, then? That’s why I don’t need to care about MyRGB in the example, since the C library expects uint8_t and Julia promises to give the same thing in UInt8?


#6

Yes.

Yes.

Yes.

Yes.


#7

This was the reason. Later on in the C++ code, I had segmentation fault problem. But the main issue from Julia to C++ was immutable addition to the type definition. Fixing the two problems at the same time resulted in a normal behavior in the end.

Thanks!