Search code examples
raku

Raku NativeCall to SOD Segmentation fault


I am trying to use sod in Raku using NativeCall but I keep getting a segmentation fault error.

#!/usr/bin/env raku
use v6.d;
use NativeCall;

class Image is repr('CStruct') {
    has int32 $.h;
    has int32 $.w;
    has int32 $.c;
    has Pointer[num32] $.data;
}

sub sod_make_random_image(
    int32 $h,
    int32 $w,
    int32 $c,
) returns Image is native("$*CWD/sod") { * }


sub sod_img_save_as_png(
    Image $img,
    Str $filename,
    --> uint8 ) is native("$*CWD/sod") { * }


my $img = sod_make_random_image(100, 100, 3);
say sod_img_save_as_png($img, "test.png");

I compiled the lib running gcc -shared -Wall -fPIC -o libsod.so sod.c -std=c99. rakudo-gdb-m then bt full output:

0x00007fffef6939e3 in sod_make_random_image () from /media/khalid/Data/CommaProjects/SOD/libsodreader.so
(gdb) bt full
#0  0x00007fffef6939e3 in sod_make_random_image () from /media/khalid/Data/CommaProjects/SOD/libsodreader.so
No symbol table info available.

#1  0x00007ffff79c25b2 in dcCall_x64_sysv () from //home/khalid/.rakubrew/versions/moar-2023.05/install/lib/libmoar.so
No symbol table info available.

#2  0x0000000000000016 in ?? ()
No symbol table info available.

#3  0x00007fffffffd2b0 in ?? ()
No symbol table info available.

#4  0x00007ffff79c23fa in dc_callvm_call_x64 () from //home/khalid/.rakubrew/versions/moar-2023.05/install/lib/libmoar.so
No symbol table info available.

Backtrace stopped: previous frame inner to this frame (corrupt stack?)

Any idea why I am getting a segmentation fault error? Also sod_img_load_from_file always returns an empty image with zero width and height.


Solution

  • The actual problem is the interface of the library. The sod_make_random_image() returns the sod_img by value rather than a pointer, whereas raku expects the Image to be a pointer, this messes up the call stack and hence the segfault.

    To test I altered the sod_make_random_image to return a pointer instead:

    sod_img *sod_make_random_image(int w, int h, int c)
    {
        printf("w: %i  h: %i  c: %i\n", w, h, c);
        sod_img out = sod_make_empty_image(w, h, c);
        out.data = calloc(h*w*c, sizeof(float));
        if (out.data) {
            int i;
            for (i = 0; i < w*h*c; ++i) {
                out.data[i] = (rand_normal() * .25) + .5;
            }
        }
        return &out;
    }
    

    and adjusted the sod.h accordingly, and it worked. Except of course the problem moved on to the sod_img_save_as_png() which is now getting a pointer rather than the value it expects, but that could be fixed too.

    You have two options as I see it: either make a fork of the library such that the sod_img (and other structs ) are being returned and passed as pointers to the structs, or make your own wrapper for the functions you want to use that dereferences the pointer arguments to pass to the actual functions and takes the pointer of the struct return values.