Attempting calling a function from a header file, but ending with Segmentation fault

After messing around webassembly and raylib, I am now trying to figure out how to link some non-zig libraries. So far, I have successfully loaded a dynamic library (.dll/.so), but I have gotten some issues on calling the functions.

The library I was trying to use is called the SunVox Library which is used for controlling a backend of SunVox which is a music tracker.

Initially, I need to call an init function “sv_init” to initialize the library which the function pointer as shown:

// This is generated from cimport.zig after compilation
pub extern var sv_init: ?*const fn ([*c]const u8, c_int, c_int, u32) callconv(.C) c_int;

Based on the required arguments, I have created a wrapper function:

fn sv_init(config: [*c]const u8, sample_rate: i32, channels: i32, flags: u32) !i32 {
    const status = sunvox.sv_init.?(config, @as(c_int, sample_rate), @as(c_int, channels), flags);
    if (status < 0) {
        return SUNVOX_ERR.initialization_failed;
    } else {
        return @as(i32, status);
    }
}

With the function, I wrote the following codes in my main function:

const std = @import("std");
const sunvox = @cImport({
    @cInclude("sunvox.h");
});

const SUNVOX_ERR = error{
    initialization_failed,
    open_slot_failed,
    maximum_slot_exceeded,
    project_load_failed,
    playback_failed,
};

pub fn main() !void {
    _ = try sv_init("", 44100, 2, 0);
}

When I build the project, the compiler didn’t throw any error; however, when I run the program, it throws me an Segmentation fault as shown:

Segmentation fault at address 0xffffffffffffffff
...\dynamic_libraries_test\src\main.zig:21:20: 0x913b6 in main (dynamic_libraries_test.exe.obj)
    _ = try sv_init(0, 44100, 2, 0);
                   ^
C:\ProgramData\chocolatey\lib\zig\tools\zig-windows-x86_64-0.13.0\lib\std\start.zig:497:75: 0x9190b in main (dynamic_libraries_test.exe.obj)
    return callMainWithArgs(@as(usize, @intCast(c_argc)), @as([*][*:0]u8, @ptrCast(c_argv)), envp);
                                                                          ^
C:\ProgramData\chocolatey\lib\zig\tools\zig-windows-x86_64-0.13.0\lib\libc\mingw\crt\crtexe.c:267:0: 0x105c11 in __tmainCRTStartup (crt2.obj)
    mainret = _tmain (argc, argv, envp);

C:\ProgramData\chocolatey\lib\zig\tools\zig-windows-x86_64-0.13.0\lib\libc\mingw\crt\crtexe.c:188:0: 0x105c6b in mainCRTStartup (crt2.obj)
  ret = __tmainCRTStartup ();

???:?:?: 0x7ffe4d56259c in ??? (KERNEL32.DLL)
???:?:?: 0x7ffe4e22af37 in ??? (ntdll.dll)

Based on the address, I thought it was something done with null reference, so I decided to wrap an optional check as shown:

    if (sunvox.sv_init) |func| {
        const status = func(config, @as(c_int, sample_rate), @as(c_int, channels), flags);

        if (status < 0) {
            return SUNVOX_ERR.initialization_failed;
        } else {
            return @as(i32, status);
        }
    } else {
        return SUNVOX_ERR.initialization_failed;
    }

Nevertheless, the optional wasn’t appeared as null, and the same error persists, so I guess it could be the arguments of the function call, but not sure how it exactly happens. Thus, I wanna know what are the possible causes for the Segmentation fault in this case.

I know this question might be too vague, so let me know if anyone want more details about this problem.

When I look at the SunVox Library link it looks to me as if you should call sv_load_dll() when you dynamically load it, before doing anything else.

C + dynamic lib (Windows, Linux, macOS):

#define SUNVOX_MAIN /* We are using a dynamic lib. SUNVOX_MAIN adds implementation of sv_load_dll()/sv_unload_dll() */
#include "sunvox.h"
int main()
{
   if( sv_load_dll() ) return 1;

You probably also want to add the define to your cImport:

const sunvox = @cImport({
    @cDefine("SUNVOX_MAIN", {});
    @cInclude("sunvox.h");
});
3 Likes

Thank you! And a respect to look into the library!

After added the @cDefine() to the main file, I can observed the error message has changed:

...\dynamic_libraries_test\c-src/sunvox.h:695:5: error: unknown type name 'HMODULE'
    HMODULE g_sv_dll = NULL;

Based on the finding from this stackoverflow post, I have included windows.h in the header to get around the compile error, and now I have faced another error messages related to pointers as the following.

...\dynamic_libraries_test\c-src/sunvox.h:797:17: error: incompatible pointer to integer conversion passing 'char[27]' to parameter of type 'size_t' (aka 'unsigned long long')
 sprintf_s( ts, "sunvox lib: %s() not found", fn_not_found );
                ^

Since that is just a sprintf() function, seemingly used for logging an error when the library is not found, so I just temporary commented that function, but I have encountered:

...\dynamic_libraries_test\.zig-cache\o\690aa991d5b2f42b009dade9f0ae5f50\cimport.zig:66770:5: error: unreachable code
    return -@as(c_int, 1111);
    ^~~~~~~~~~~~~~~~~~~~~~~~

...\dynamic_libraries_test\.zig-cache\o\690aa991d5b2f42b009dade9f0ae5f50\cimport.zig:66769:5: note: control flow is diverted here
    return sv_load_dll2(@as(LIBNAME_STR_TYPE, @ptrCast(@alignCast("sunvox.dll"))));

Seems this is now back to zig, but the problem is located in cimport.zig from a zig cache because, the sv_load_dll is defined as:

pub export fn sv_load_dll() c_int {
    return sv_load_dll2(@as(LIBNAME_STR_TYPE, @ptrCast(@alignCast("sunvox.dll"))));
    return -@as(c_int, 1111);
}

Which should be corresponding to this part of the header:

int sv_load_dll( void )
{
#ifdef OS_WIN
    return sv_load_dll2( TEXT(LIBNAME) );
#else
    return sv_load_dll2( LIBNAME );
#endif
    return -1111;
}

Hmmm… I guess I need to contact the developer of the library to understand what is the meaning for returning -1111 and all the aforementioned issues because the problems seem like they are from the header than zig itself; however, after I have commented the code, I have gotten something more familiar which are my error enums:

...\dynamic_libraries_test\src\main.zig:54:9: 0xff108c in sv_init (dynamic_libraries_test.exe.obj)
        return SUNVOX_ERR.not_found;
        ^
...\dynamic_libraries_test\src\main.zig:23:9: 0xff12ce in main (dynamic_libraries_test.exe.obj)
    _ = try sv_init(0, 44100, 2, 0);
        ^

I know there will be a long way to go to make this library works for zig, but this is definitely some progress, but for now, I guess I need to learn more about the library and the builtins for importing libraries.

And again, thanks for your help! Now I have learnt more about @cDefine, and I do believe the main question of this post should be addressed.

1 Like

I did it!!! After I have clarified to the dev of the library and focusing on the last problem:

...\dynamic_libraries_test\src\main.zig:54:9: 0xff108c in sv_init (dynamic_libraries_test.exe.obj)
        return SUNVOX_ERR.not_found;
        ^
...\dynamic_libraries_test\src\main.zig:23:9: 0xff12ce in main (dynamic_libraries_test.exe.obj)
    _ = try sv_init(0, 44100, 2, 0);
        ^

It turns out according to the documentation, if I use a dynamic library, I need to manually load the dll from the header file using the function “sv_load_dll()”, so after properly loaded the dll using the function, everything works fine.

The only catch is that the dll file must be manually loaded into the zig-out/bin folder; otherwise, the program throws an error due to not finding the dll file, but this is a minor issue as long as I remember to ship the executable along with the library.

Finally, with raylib and this library, I can rewrite some of my old projects.

1 Like