Zig compile error (no details) when mixed with C code

I have case when I have to create wrapper for C library. For purpose of this post I extracted bare minimum to show that compilation fail but without any specyfic detail:

C .h file

struct lfs_config {
    void *context;
    int block_cycles;
    
    int (*read)(const struct lfs_config *c, int block,
            int off, void *buffer, int size);
};

main.zig:

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

pub const lfs_config = struct {
    const Self = @This();

    read: fn (block: u32, off: u32, buffer: []u8) i32,

    pub fn to_lfs_config(self: *const Self) c.lfs_config {
        return c.lfs_config {
            .context = @ptrCast(@constCast(self)),
            .read = lfs_read,
        };
    }
};

fn lfs_read(config: [*c]const c.lfs_config, block: u32, off: u32, buffer: ?*anyopaque, size: u32) callconv(.C) c_int {
    return @as(*lfs_config, @ptrCast(config.*.context)).read(block, off, @as([*]u8, @ptrCast(buffer))[0..size]);
}

pub fn main() !void {
    const test_cfg = lfs_config{
        .read = zig_test_read,
    };
    _ = test_cfg.to_lfs_config();
}

fn zig_test_read(block: u32, off: u32, buffer: []u8) i32 {
    std.log.info("read: block: {} off: {} size: {}", .{block, off, buffer.len});
    return 0;
}

and build.zig:

const std = @import("std");

pub fn build(b: *std.Build) void {
    const target = b.standardTargetOptions(.{});
    const optimize = b.standardOptimizeOption(.{});
    const exe = b.addExecutable(.{
        .name = "zig-bug",
        .root_source_file = b.path("src/main.zig"),
        .target = target,
        .optimize = optimize,
    });
    exe.addIncludePath(b.path("src"));
    b.installArtifact(exe);
}

And compilation error:

PS D:\zig-bug> zig build -Doptimize=Debug
install
└─ install zig-bug
   └─ zig build-exe zig-bug Debug native failure
error: the following command exited with error code 5:
C:\Users\arek\AppData\Local\Microsoft\WinGet\Packages\zig.zig_Microsoft.Winget.Source_8wekyb3d8bbwe\zig-windows-x86_64-0.13.0\zig.exe build-exe -ODebug -I D:\zig-bug\src -Mroot=D:\zig-bug\src\main.zig --cache-dir D:\zig-bug\.zig-cache --global-cache-dir C:\Users\arek\AppData\Local\zig --name zig-bug --listen=-
Build Summary: 0/3 steps succeeded; 1 failed (disable with --summary none)
install transitive failure
└─ install zig-bug transitive failure
   └─ zig build-exe zig-bug Debug native failure
error: the following build command failed with exit code 1:
D:\zig-bug\.zig-cache\o\6364e598a586d17a6cee190a6f37085e\build.exe C:\Users\arek\AppData\Local\Microsoft\WinGet\Packages\zig.zig_Microsoft.Winget.Source_8wekyb3d8bbwe\zig-windows-x86_64-0.13.0\zig.exe D:\zig-bug D:\zig-bug\.zig-cache C:\Users\arek\AppData\Local\zig --seed 0x8f55c59d -Z121fe3821b95bb50 -Doptimize=Debug

From my initial investigation I am sure that this bug is caused by line:

return @as(*lfs_config, @ptrCast(config.*.context)).read(block, off, @as([*]u8, @ptrCast(buffer))[0..size]);

Any ideas what is wrong here and why zig don’t show any meaningful errors?

-Doptimize=Debug hides the error.

When executing zig build I am getting a signed/unsigned integer error:

install
└─ install zig-bug
   └─ zig build-exe zig-bug Debug native 1 errors
src/main.zig:14:14: error: expected type '*const fn ([*c]const cimport.struct_lfs_config, c_int, c_int, ?*anyopaque, c_int) callconv(.C) c_int', found '*const fn ([*c]const cimport.struct_lfs_config, u32, u32, ?*anyopaque, u32) callconv(.C) c_int'
            .read = lfs_read,
            ~^~~~~~~~~~~~~~~
src/main.zig:14:14: note: pointer type child 'fn ([*c]const cimport.struct_lfs_config, u32, u32, ?*anyopaque, u32) callconv(.C) c_int' cannot cast into pointer type child 'fn ([*c]const cimport.struct_lfs_config, c_int, c_int, ?*anyopaque, c_int) callconv(.C) c_int'
src/main.zig:14:14: note: parameter 1 'u32' cannot cast into 'c_int'
src/main.zig:14:14: note: unsigned 32-bit int cannot represent all possible signed 32-bit values

and then the transitive error.

1 Like

@dimdin are you using linux machine? On Windows I have very same error when compiling using just zig build like I get for zig build -Doptimize=Debug

Edit:
I have same issue on linux machine

Edit2:
I was able to get compilation errors on zig 0.14-dev

I tried zig build on macos.

You are right:

  • It works on macos 0.13.0
  • It does not work on linux 0.13.0
  • It works on linux 0.14.0-dev
1 Like

These don’t match. It should be:

fn lfs_read(config: [*c]const c.lfs_config, block: c_int, off: c_int, buffer: ?*anyopaque, size: c_int) callconv(.C) c_int
1 Like

Welcome to the forum! To add on to the other replies, I’d like to share a tip that may be helpful in debugging this if it happens again: in the output of zig build, if you take the first command printed (after error: the following command exited with error code 5:), remove --listen=- from the end, and run it, you may get additional useful output in your terminal.

For example, I’m on Linux, but I expect that the behavior should be similar on Windows:

β¬’ [ian@toolbox tmp]$ ~/opt/zig-0.13.0/zig build -Doptimize=Debug
install
└─ install zig-bug
   └─ zig build-exe zig-bug Debug native failure
error: the following command terminated unexpectedly:
/var/home/ian/opt/zig-0.13.0/zig build-exe -ODebug -I /var/home/ian/tmp/src -Mroot=/var/home/ian/tmp/src/main.zig --cache-dir /var/home/ian/tmp/.zig-cache --global-cache-dir /var/home/ian/.cache/zig --name zig-bug --listen=- 
Build Summary: 0/3 steps succeeded; 1 failed (disable with --summary none)
install transitive failure
└─ install zig-bug transitive failure
   └─ zig build-exe zig-bug Debug native failure
error: the following build command failed with exit code 1:
/var/home/ian/tmp/.zig-cache/o/c56d87fe25e31b812873e1ce0f73841e/build /var/home/ian/opt/zig-0.13.0/zig /var/home/ian/tmp /var/home/ian/tmp/.zig-cache /var/home/ian/.cache/zig --seed 0x640bee01 -Z2df74e4cfc94daaa -Doptimize=Debug
β¬’ [ian@toolbox tmp]$ /var/home/ian/opt/zig-0.13.0/zig build-exe -ODebug -I /var/home/ian/tmp/src -Mroot=/var/home/ian/tmp/src/main.zig --cache-dir /var/home/ian/tmp/.zig-cache --global-cache-dir /var/home/ian/.cache/zig --name zig-bug
Segmentation fault (core dumped)

Since the compiler is segfaulting in the zig build-exe command, as confirmed by running it directly, this confirms that it’s a compiler bug in Zig 0.13.0 (which has evidently been fixed since then).

1 Like