renderErrorMessage: integer overflow during @cImport

Hey all,

I am trying to use termbox2 in zig by updating these wrapper bindings here: https://sr.ht/\~kolunmi/termbox2-zig/ . Ideally I would like to use zig 0.16. My current build.zig looks like:

const std = @import("std");

pub fn build(b: *std.Build) void {
    const target = b.standardTargetOptions(.{});
    const optimize = b.standardOptimizeOption(.{});

    // Build termbox-zig
    //  - taken and updated from https://git.sr.ht/~kolunmi/termbox2-zig
    const ztb_opts = b.addOptions();
    ztb_opts.addOption(i32, "attr_w", b.option(i32, "attr_w", "integer width of fg and bg attributes (16, 32, 64)") orelse 64);
    ztb_opts.addOption(bool, "egc", b.option(bool, "egc", "enable extended grapheme cluster support") orelse false);
    ztb_opts.addOption(usize, "printf_buf", b.option(usize, "printf_buf", "buffer size for printf operations") orelse 0);
    ztb_opts.addOption(usize, "read_buf", b.option(usize, "read_buf", "buffer size for tty reads") orelse 0);

    const ztb_opts_mod = ztb_opts.createModule();

    const ztb_mod = b.addModule("ztb", .{
        .target = target,
        .optimize = optimize,
        .root_source_file = b.path("src/ztb.zig"),
        .link_libc = true,
    });
    ztb_mod.addImport("ztb_opts", ztb_opts_mod);
    ztb_mod.addIncludePath(b.path("include"));

    const lib = b.addLibrary(.{
        .name = "ztb",
        .linkage = .static,
        .root_module = ztb_mod,
    });

    b.installArtifact(lib);

    // small demo
    //  - taken and adapted from https://github.com/karintomania/zig-termbox2-wrapper
    const demo_run_step = b.step("demo", "Run src/demo.zig");
    const demo = b.addExecutable(.{
        .name = "demo",
        .root_module = b.addModule("demo-example", .{
            .root_source_file = b.path("src/demo.zig"),
            .target = target,
            .optimize = optimize,
        }),
    });
    demo.root_module.addImport("ztb", ztb_mod);
    b.installArtifact(demo);
    const demo_run = b.addRunArtifact(demo);
    demo_run_step.dependOn(&demo_run.step);
}

When I try to build with zig version: 0.16.0-dev.3133+5ec8e45f3, I encounter the following error:

install
└─ install demo
   └─ compile exe demo Debug native 4 errors
src/ztb.zig:5:11: error: C import failed
const c = @cImport({
          ^~~~~~~~
referenced by:
    init: src/ztb.zig:340:16
thread 57358 panic: integer overflow
/nix/store/lv1fqkbld8qqrc81ghbl42z7xmh6m2a4-zig-0.16.0-dev.3133+5ec8e45f3/lib/std/zig/ErrorBundle.zig:218:27: 0x130470e in renderErrorMessage (std.zig)
            src.data.line + 1,
                          ^
/nix/store/lv1fqkbld8qqrc81ghbl42z7xmh6m2a4-zig-0.16.0-dev.3133+5ec8e45f3/lib/std/zig/ErrorBundle.zig:187:31: 0x1303851 in renderToTerminal (std.zig)
        try renderErrorMessage(eb, options, err_msg, t, "error", .red, 0);
                              ^
/nix/store/lv1fqkbld8qqrc81ghbl42z7xmh6m2a4-zig-0.16.0-dev.3133+5ec8e45f3/lib/compiler/build_runner.zig:1494:58: 0x12ffafe in printErrorMessages (build_runner.zig)
    try failing_step.result_error_bundle.renderToTerminal(options, stderr);
                                                         ^
/nix/store/lv1fqkbld8qqrc81ghbl42z7xmh6m2a4-zig-0.16.0-dev.3133+5ec8e45f3/lib/compiler/build_runner.zig:1388:27: 0x1472f13 in makeStep (build_runner.zig)
        printErrorMessages(gpa, s, .{}, stderr.terminal(), run.error_style, run.multiline_errors) catch {};
                          ^
/nix/store/lv1fqkbld8qqrc81ghbl42z7xmh6m2a4-zig-0.16.0-dev.3133+5ec8e45f3/lib/std/Io.zig:1238:17: 0x14727a5 in start (std.zig)
                _ = @as(Cancelable!void, @call(.auto, function, args_casted.*)) catch {};
                ^
/nix/store/lv1fqkbld8qqrc81ghbl42z7xmh6m2a4-zig-0.16.0-dev.3133+5ec8e45f3/lib/std/Io/Threaded.zig:552:22: 0x122c3a5 in start (std.zig)
            task.func(task.contextPointer());
                     ^
/nix/store/lv1fqkbld8qqrc81ghbl42z7xmh6m2a4-zig-0.16.0-dev.3133+5ec8e45f3/lib/std/Io/Threaded.zig:1794:29: 0x122a584 in worker (std.zig)
            runnable.startFn(runnable, &thread, t);
                            ^
/nix/store/lv1fqkbld8qqrc81ghbl42z7xmh6m2a4-zig-0.16.0-dev.3133+5ec8e45f3/lib/std/Thread.zig:422:13: 0x122a265 in callFn__anon_27500 (std.zig)
            @call(.auto, f, args);
            ^
/nix/store/lv1fqkbld8qqrc81ghbl42z7xmh6m2a4-zig-0.16.0-dev.3133+5ec8e45f3/lib/std/Thread.zig:1431:30: 0x122a020 in entryFn (std.zig)
                return callFn(f, self.fn_args);
                             ^
/nix/store/lv1fqkbld8qqrc81ghbl42z7xmh6m2a4-zig-0.16.0-dev.3133+5ec8e45f3/lib/std/os/linux/x86_64.zig:105:5: 0x122a185 in clone (std.zig)
    asm volatile (
    ^
error: the following build command terminated with signal ABRT:
.zig-cache/o/d05174c32b08d5612517aba18dcb9d6c/build /nix/store/lv1fqkbld8qqrc81ghbl42z7xmh6m2a4-zig-0.16.0-dev.3133+5ec8e45f3/bin/zig /nix/store/lv1fqkbld8qqrc81ghbl42z7xmh6m2a4-zig-0.16.0-dev.3133+5ec8e45f3/lib /home/inbelic/ztb .zig-cache /home/inbelic/.cache/zig --seed 0x111388f3 -Z4307e7f26bd20456

which means I can’t see the actual diagnostic error to try and resolve it.

Building with 0.15.1 builds fine and the demo.zig runs as expected. Full source is viewable here: ssh inbelic.dev -p 23231 under the ztb repo.

I don’t currently build the compiler from source to just hackily prevent the overflow, hoping for some leads before going down that route.

Thanks!

It looks like this error consists of two layers. The error renderer of cImport received an abnormal line number, causing an integer overflow when the line number was incremented, and we didn’t receive the underlying error message. So first, let’s use zig translate-c to see what the native error looks like.

npc1054657282@localhost:~/projects/ztb$ zig translate-c include/termbox2.h -lc -DTB_IMPL -DTB_OPT_ATTR_W=64 > output.zig
error: translation failure
<scratch space>:0:1: error: expected expression

^
<scratch space>:0:1: error: expected expression

^

It seems that the error occurs during macro expansion. Because errors at this stage do not have a valid line number, I guess that internally the line number might be recorded as an invalid value, that is 0xFFFFFFFF, causing integer overflow when the error renderer processes it. I think this issue is worth reporting to Zig.

Edit: I once used an incorrect analysis method, performing macro expansion with zig cc, and then analyzing the macro expansion output with zig translate-c. I am sorry, it’s not the problem! If the environment of zig cc is different from zig translate-c, then applying the macro expansion of zig cc to zig translate-c is fundamentally wrong!

Upon inspection, this kind of header file is sufficient to cause problems:

// minimal.h
#ifndef _XOPEN_SOURCE
#define _XOPEN_SOURCE
#endif
#include <stdio.h>

Found the --verbose-cimport parameter, hoping it can bring some help:

npc1054657282@localhost:~/projects/ztb$ zig translate-c minimal.h -lc --verbose-cimport > trace.zig
--zig-integration -x c -isystem /home/npc1054657282/.vscode-server/data/User/globalStorage/ziglang.vscode-zig/zig/x86_64-linux-0.16.0-dev.2905+5d71e3051/lib/compiler/aro/include -fno-PIE -fPIC -gdwarf-4 -gdwarf32 -fno-lto -MD -MV -MF .zig-cache/tmp/25fd8f9ade7e0aab/minimal.h.d -fhosted -nostdinc -D__GLIBC_MINOR__=41 -isystem /home/npc1054657282/.vscode-server/data/User/globalStorage/ziglang.vscode-zig/zig/x86_64-linux-0.16.0-dev.2905+5d71e3051/lib/include -isystem /usr/include -isystem /usr/include/x86_64-linux-gnu -O0 -target x86_64-linux.6.12.48...6.12.48-gnu.2.41 -mcpu=cascadelake-16bit_mode-32bit_mode-3dnow-3dnowa+64bit+adx+aes+allow_light_256_bit-amx_avx512-amx_bf16-amx_complex-amx_fp16-amx_fp8-amx_int8-amx_movrs-amx_tf32-amx_tile-amx_transpose+avx-avx10_1-avx10_2+avx2-avx512bf16-avx512bitalg+avx512bw+avx512cd+avx512dq-avx512er+avx512f-avx512fp16-avx512ifma-avx512pf-avx512vbmi-avx512vbmi2+avx512vl+avx512vnni-avx512vp2intersect-avx512vpopcntdq-avxifma-avxneconvert-avxvnni-avxvnniint16-avxvnniint8+bmi+bmi2-branch_hint-branchfusion-bsf_bsr_0_clobbers_result-ccmp-cf-cldemote+clflushopt+clwb-clzero+cmov-cmpccxadd+crc32+cx16+cx8-egpr-enqcmd+ermsb+evex512+f16c-false_deps_getmant-false_deps_lzcnt_tzcnt-false_deps_mulc-false_deps_mullq-false_deps_perm+false_deps_popcnt-false_deps_range-fast_11bytenop+fast_15bytenop-fast_7bytenop-fast_bextr-fast_dpwssd+fast_gather-fast_hops-fast_imm16-fast_lzcnt-fast_movbe+fast_scalar_fsqrt-fast_scalar_shift_masks+fast_shld_rotate+fast_variable_crosslane_shuffle+fast_variable_perlane_shuffle+fast_vector_fsqrt-fast_vector_shift_masks+faster_shift_than_shuffle+fma-fma4+fsgsbase-fsrm+fxsr-gfni-harden_sls_ijmp-harden_sls_ret-hreset-idivl_to_divb+idivq_to_divl-inline_asm_use_gpr32+invpcid-kl-lea_sp-lea_uses_ag-lvi_cfi-lvi_load_hardening-lwp+lzcnt+macrofusion+mmx+movbe-movdir64b-movdiri-movrs-mwaitx-ndd-nf-no_bypass_delay+no_bypass_delay_blend+no_bypass_delay_mov+no_bypass_delay_shuffle+nopl-pad_short_functions+pclmul-pconfig+pku+popcnt-ppx-prefer_128_bit+prefer_256_bit-prefer_mask_registers-prefer_movmsk_over_vtest-prefer_no_gather-prefer_no_scatter-prefetchi-prefetchwt1+prfchw-ptwrite-push2pop2-raoint-rdpid-rdpru+rdrnd+rdseed-retpoline-retpoline_external_thunk-retpoline_indirect_branches-retpoline_indirect_calls-rtm+sahf-sbb_dep_breaking-serialize-seses-sgx-sha-sha512-shstk+slow_3ops_lea-slow_incdec-slow_lea-slow_pmaddwd-slow_pmulld-slow_shld-slow_two_mem_ops-slow_unaligned_mem_16-slow_unaligned_mem_32-sm3-sm4+smap+smep-soft_float+sse+sse2+sse3+sse4_1+sse4_2-sse4a-sse_unaligned_mem+ssse3-tagged_globals-tbm-tsxldtrk+tuning_fast_imm_vector_shift-uintr-use_glm_div_sqrt_costs-use_slm_arith_costs-usermsr-vaes-vpclmulqdq+vzeroupper-waitpkg-wbnoinvd-widekl+x87-xop+xsave+xsavec+xsaveopt+xsaves-zu minimal.h -o .zig-cache/tmp/25fd8f9ade7e0aab/minimal.zig
info(compilation): processing dep file at .zig-cache/tmp/25fd8f9ade7e0aab/minimal.h.d
error: translation failure
<scratch space>:0:1: error: expected expression

^
<scratch space>:0:1: error: expected expression

^

Very good, we have more detailed information. But version 0.15.2 cannot obtain the same amount of information.

I once considered using zig cc to output again, but found that the result was still different from translate-c. Later, I found that it was because zig cc uses Clang while translate-c uses Aro as the frontend, which is fundamentally different. Unfortunately, this is all the information I could obtain.

Cheers. Thanks for pointing that out!

From this, I thought I could get away with making a dummy c source file and compiling that with zig cc (which works), but it looks like even without TB_IMPL defined we crash when importing the headers, which is nicely illustrated in your second comment.

I am happy to go ahead and file a bug with your minimal repro and link back here. But lmk if you’d like to file the report.

Thanks

Thank you, I think it is most appropriate for you to submit the issue.