What is the error of illegal instruction at address 0xba8658?

I recently tried to learn how to use zig to interact with c(I have no experience with c), and used the miniaudio library as a demo.
And i encountered some errors, but I don’t know if it was caused by incorrect usage of zig build. I hope someone with experience can guide me. Thank you very much.

src dir structure

src
├── c
│  ├── miniaudio.c
│  └── miniaudio.h
└── main.zig

main.zig

const std = @import("std");
const builtin = @import("builtin");
const log = std.log;

const ma = @cImport({
    @cInclude("miniaudio.h");
});

pub const std_options = .{
    .log_level = switch (builtin.mode) {
        .Debug => .debug,
        else => .info,
    },
};

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    const allocator = gpa.allocator();

    // read file path from commandline args
    //
    var args = try std.process.argsWithAllocator(allocator);
    defer args.deinit();
    _ = args.next();
    const sound_file_path = args.next() orelse return error.ArgsNotFound;
    log.info("song file path: {s}", .{sound_file_path});

    // engine init
    //
    const engine = try allocator.create(ma.ma_engine);
    defer allocator.destroy(engine);
    if (ma.ma_engine_init(null, engine) != ma.MA_SUCCESS) {
        return error.MAEngineInit;
    }
    defer ma.ma_engine_uninit(engine);

    // sound init
    //
    const sound = try allocator.create(ma.ma_sound);
    defer allocator.destroy(sound);
    const flags = ma.MA_SOUND_FLAG_DECODE;
    if (ma.ma_sound_init_from_file(engine, sound_file_path, flags, null, null, sound) != ma.MA_SUCCESS) {
        return error.MASoundInitFile;
    }

    // sound start
    //
    if (ma.ma_sound_start(sound) != ma.MA_SUCCESS) {
        return error.MASoundStart;
    }
}

build.zig

const std = @import("std");
const miniaudio_header_dir = "src/c";
const miniaudio_src_file = "src/c/miniaudio.c";
const main_file = "src/main.zig";
const test_file = "src/main.zig";

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

    // configure and install exe
    //
    const exe = b.addExecutable(.{
        .name = "miniaudio.zig",
        .root_source_file = b.path(main_file),
        .target = target,
        .optimize = optimize,
    });
    exe.addCSourceFile(.{ .file = .{
        .path = miniaudio_src_file,
    }, .flags = &.{} });
    exe.addIncludePath(.{ .path = miniaudio_header_dir });
    exe.linkLibC();
    if (target.result.os.tag == .linux) {
        exe.linkSystemLibrary("pthread");
        exe.linkSystemLibrary("m");
        exe.linkSystemLibrary("dl");
    }
    b.installArtifact(exe);

    // run
    //
    const run_cmd = b.addRunArtifact(exe);
    run_cmd.step.dependOn(b.getInstallStep());
    if (b.args) |args| {
        run_cmd.addArgs(args);
    }
    const run_step = b.step("run", "Run the app");
    run_step.dependOn(&run_cmd.step);

    // tests
    //
    const unit_tests = b.addTest(.{
        .root_source_file = .{ .path = test_file },
        .target = target,
        .optimize = optimize,
    });
    const run_unit_tests = b.addRunArtifact(unit_tests);
    const test_step = b.step("test", "Run unit tests");
    test_step.dependOn(&run_unit_tests.step);
}

run app

╰─❯ zig build run -- test.mp3
info: song file path: test.mp3
Illegal instruction at address 0xba8658
E:\code\me\test-zig\miniaudio.zig\src\c\miniaudio.h:67134:0: 0xba6fef in ma_hash_string_32 (miniaudio.obj)
    return ma_hash_32(str, (int)strlen(str), MA_DEFAULT_HASH_SEED);

E:\code\me\test-zig\miniaudio.zig\src\c\miniaudio.h:68484:0: 0xab31a4 in ma_resource_manager_data_buffer_node_acquire (miniaudio.obj)
            hashedName32 = ma_hash_string_32(pFilePath);

E:\code\me\test-zig\miniaudio.zig\src\c\miniaudio.h:68818:0: 0xaae6b7 in ma_resource_manager_data_buffer_init_ex_internal (miniaudio.obj)
        result = ma_resource_manager_data_buffer_node_acquire(pResourceManager, pConfig->pFilePath, pConfig->pFilePathW, hashedName32, flags, NULL, notifications.init.pFence, notifications.done.pFence, &pDataBufferNode);

E:\code\me\test-zig\miniaudio.zig\src\c\miniaudio.h:68935:0: 0xaae069 in ma_resource_manager_data_buffer_init_ex (miniaudio.obj)
    return ma_resource_manager_data_buffer_init_ex_internal(pResourceManager, pConfig, 0, pDataBuffer);

E:\code\me\test-zig\miniaudio.zig\src\c\miniaudio.h:70188:0: 0xab8d32 in ma_resource_manager_data_source_init_ex (miniaudio.obj)
        return ma_resource_manager_data_buffer_init_ex(pResourceManager, pConfig, &pDataSource->backend.buffer);

E:\code\me\test-zig\miniaudio.zig\src\c\miniaudio.h:75920:0: 0xad2ea9 in ma_sound_init_from_file_internal (miniaudio.obj)
        result = ma_resource_manager_data_source_init_ex(pEngine->pResourceManager, &resourceManagerDataSourceConfig, pSound->pResourceManagerDataSource);

E:\code\me\test-zig\miniaudio.zig\src\c\miniaudio.h:76064:0: 0xad45b2 in ma_sound_init_ex (miniaudio.obj)
        return ma_sound_init_from_file_internal(pEngine, pConfig, pSound);

E:\code\me\test-zig\miniaudio.zig\src\c\miniaudio.h:75960:0: 0xad21ad in ma_sound_init_from_file (miniaudio.obj)
    return ma_sound_init_ex(pEngine, &config, pSound);

E:\code\me\test-zig\miniaudio.zig\src\main.zig:42:35: 0xc7fef5 in main (miniaudio.zig.exe.obj)
    if (ma.ma_sound_init_from_file(engine, sound_file_path, flags, null, null, sound) != ma.MA_SUCCESS) {
                                  ^
E:\scoop\global\apps\zig-dev\0.13.0-dev.30\lib\std\start.zig:484:5: 0xc808fa in main (miniaudio.zig.exe.obj)
    return callMainWithArgs(@as(usize, @intCast(c_argc)), @as([*][*:0]u8, @ptrCast(c_argv)), envp);
    ^
E:\scoop\global\apps\zig-dev\0.13.0-dev.30\lib\libc\mingw\crt\crtexe.c:267:0: 0xd082e4 in __tmainCRTStartup (crt2.obj)
    mainret = _tmain (argc, argv, envp);

E:\scoop\global\apps\zig-dev\0.13.0-dev.30\lib\libc\mingw\crt\crtexe.c:188:0: 0xd0833b in mainCRTStartup (crt2.obj)
  ret = __tmainCRTStartup ();

???:?:?: 0x7ffe9047257c in ??? (KERNEL32.DLL)
???:?:?: 0x7ffe918aaa47 in ??? (ntdll.dll)

Running this in GDB I see the trap occuring at line 67063.

 67058  static MA_INLINE ma_uint32 ma_hash_getblock(const ma_uint32* blocks, int i)
 67059  {
 67060      ma_uint32 block;
 67061  
 67062      /* Try silencing a sanitization warning about unaligned access by doing a memcpy() instead of assignment. */
 67063      MA_COPY_MEMORY(&block, ma_offset_ptr(blocks, i * sizeof(block)), sizeof(block));

In debug mode Zig compiles C files with sanitizers enabled and a sanitizer is inserting an illegal instruction here. By the comment it looks like the author realizes that sanitizers don’t like the unaligned memory access here.

2 Likes

As mentioned by @permutationlock, Zig turns on undefined behavior sanitization by default, and this is undefined behavior being caught. If you need to disable the sanitizer, you can do:

    exe.addCSourceFile(.{ .file = .{
        .path = miniaudio_src_file,
    }, .flags = &.{
        "-fno-sanitize=undefined",
    } });
2 Likes

A new error has appeared. Is it a problem with miniaudio?

╰─❯ zig build run -- test2.mp3
info: song file path: test2.mp3
Segmentation fault at address 0x266c0d300e8
E:\code\me\test-zig\miniaudio.zig\src\c\miniaudio.h:72176:0: 0xa9b1c2 in ma_node_uninit (miniaudio.obj)
    ma_node_detach_full(pNode);

E:\code\me\test-zig\miniaudio.zig\src\c\miniaudio.h:71248:0: 0xa9b225 in ma_node_graph_uninit (miniaudio.obj)
    ma_node_uninit(&pNodeGraph->endpoint, pAllocationCallbacks);

E:\code\me\test-zig\miniaudio.zig\src\c\miniaudio.h:75244:0: 0xaa2d8d in ma_engine_uninit (miniaudio.obj)
    ma_node_graph_uninit(&pEngine->nodeGraph, &pEngine->allocationCallbacks);

E:\code\me\test-zig\miniaudio.zig\src\main.zig:35:30: 0xb19fb6 in main (miniaudio.zig.exe.obj)
    defer ma.ma_engine_uninit(engine);
                             ^
E:\scoop\global\apps\zig-dev\0.13.0-dev.30\lib\std\start.zig:484:5: 0xb1a90a in main (miniaudio.zig.exe.obj)
    return callMainWithArgs(@as(usize, @intCast(c_argc)), @as([*][*:0]u8, @ptrCast(c_argv)), envp);
    ^
E:\scoop\global\apps\zig-dev\0.13.0-dev.30\lib\libc\mingw\crt\crtexe.c:267:0: 0xba22f4 in __tmainCRTStartup (crt2.obj)
    mainret = _tmain (argc, argv, envp);

E:\scoop\global\apps\zig-dev\0.13.0-dev.30\lib\libc\mingw\crt\crtexe.c:188:0: 0xba234b in mainCRTStartup (crt2.obj)
  ret = __tmainCRTStartup ();

???:?:?: 0x7ffe9047257c in ??? (KERNEL32.DLL)
???:?:?: 0x7ffe918aaa47 in ??? (ntdll.dll)
run
└─ run miniaudio.zig failure
error: the following command exited with error code 3:

It seems that the engine stores a reference to the sound, so calling destroy(soud) before ma_engine_uninit(engine) is where the segfault is coming from. If you move the sound initialization above the engine initialization (and thus make the defer for destroying the sound occur after the engine uninit) then everything works fine.

Debuggers are pretty useful for stuff like this, I saw this by stepping through and seeing the a segfault happen on defer ma.ma_engine_uninit.

Thank you for your help. I have no knowledge of gdb. I will definitely learn it when I have time.

I found i can unint_sound to avoid the segmentfault error

    // engine init
    //
    const engine = try allocator.create(ma.ma_engine);
    defer allocator.destroy(engine);
    if (ma.ma_engine_init(null, engine) != ma.MA_SUCCESS) {
        return error.MAEngineInit;
    }
    defer ma.ma_engine_uninit(engine);

    // sound init
    //
    const sound = try allocator.create(ma.ma_sound);
    defer allocator.destroy(sound);
    const flags = ma.MA_SOUND_FLAG_DECODE;
    if (ma.ma_sound_init_from_file(engine, sound_file_path, flags, null, null, sound) != ma.MA_SUCCESS) {
        return error.MASoundInitFile;
    }
    defer ma.ma_sound_uninit(sound);

Are you also running this code? I found that it seemed that the sound could not be played and quit immediately.

╰─❯ zig build run  -- test2.mp3
info: song file path: test2.mp3
╭╴🪟 $psh me\test-zig\miniaudio.zig via ↯ v0.13.0-dev.30+6fd09f8d2 took 2s
╰─❯

I was running the code, but I was working on a Linux VM that I haven’t really configured sound for. I figured it was my fault the mp3 wasn’t playing, but maybe something else is still wrong.

1 Like

Honestly, I haven’t successfully done anything with sound on Linux in a long time and it was immensely satisfying to hear this mp3 finally play. I now know a bit about how miniaudio works!

const std = @import("std");
const builtin = @import("builtin");
const log = std.log;

const ma = @cImport({
    @cInclude("miniaudio.h");
});

pub const std_options = .{
    .log_level = switch (builtin.mode) {
        .Debug => .debug,
        else => .info,
    },
};

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    const allocator = gpa.allocator();

    // read file path from commandline args
    //
    var args = try std.process.argsWithAllocator(allocator);
    defer args.deinit();
    _ = args.next();
    const sound_file_path = args.next() orelse return error.ArgsNotFound;
    log.info("song file path: {s}", .{sound_file_path});

    // sound init
    //
    const sound = try allocator.create(ma.ma_sound);
    defer allocator.destroy(sound);

    // engine init
    //
    const engine = try allocator.create(ma.ma_engine);
    defer allocator.destroy(engine);
    if (ma.ma_engine_init(null, engine) != ma.MA_SUCCESS) {
        return error.MAEngineInit;
    }
    defer ma.ma_engine_uninit(engine);

    const flags = ma.MA_SOUND_FLAG_DECODE;
    if (ma.ma_sound_init_from_file(engine, sound_file_path, flags, null, null, sound) != ma.MA_SUCCESS) {
        return error.MASoundInitFile;
    }

    // sound start
    //
    if (ma.ma_sound_start(sound) != ma.MA_SUCCESS) {
        return error.MASoundStart;
    }

    try std.io.getStdOut().writer().print("Press ENTER to exit!\n", .{});
    var buffer: [1]u8 = undefined;
    _ = try std.io.getStdIn().reader().read(&buffer);
}

It seems that the sound is playing in a thread so we need to loop or sleep or wait for the user to hit a key so that the sound has time to play.

2 Likes

You are right, how did you find out, it seems that the documentation does not mention this, maybe I missed something,anyway thanks, hope the music brings you a good mood ;-)

2 Likes

I looked at the engine_hello_world example in the miniaudio repo and saw that they waited for a key press :slight_smile:

:rofl: :rofl: :rofl: :sweat_smile: :sweat_smile: :sweat_smile: