I’ve been consistently running into an assert in the standard library. I’ve been trying to figure out what is causing it, and I have been unable to reduce it to a small reproduction so I can write up a bug report on the Ziglang repository.
Stack trace:
thread 588214 panic: reached unreachable code
/home/southporter/.local/share/mise/installs/zig/0.16.0/lib/std/debug.zig
:420:14: 0x1399fe9 in assert (std.zig)
if (!ok) unreachable; // assertion failure
^
/home/southporter/.local/share/mise/installs/zig/0.16.0/lib/std/Io/Threaded.zig:560:19: 0x150d23c in start (std.zig)
assert(old_status.num_running > 0);
^
/home/southporter/.local/share/mise/installs/zig/0.16.0/lib/std/Io/Threaded.zig:1797:29: 0x150b663 in worker (std.zig)
runnable.startFn(runnable, &thread, t);
^
/home/southporter/.local/share/mise/installs/zig/0.16.0/lib/std/Thread.zig:422:13: 0x150b215 in callFn__anon_27338 (std.zig)
@call(.auto, f, args);
^
/home/southporter/.local/share/mise/installs/zig/0.16.0/lib/std/Thread.zig:752:30: 0x150b009 in entryFn (std.zig)
return callFn(f, args_ptr.*);
^
???:?:?: 0x7f455d46bc18 in start_thread (/lib64/libc.so.6)
???:?:?: 0x7f455d4ef5cb in __clone3 (/lib64/libc.so.6)
It happens fairly consistently in the following code:
pub fn load(image: *Image, group: *std.Io.Group, client: *std.http.Client) void {
switch (image.state) {
.unloaded => |kind| {
if (kind != .init) return;
image.state.unloaded = .in_flight;
// This line _seems_ to be the culprit
group.concurrent(client.io, fetch, .{ image, client }) catch |err| {
log.warn("Image loading failed: {t}", .{err});
image.state.unloaded = .err;
};
},
.downloaded => {},
}
}
Full codebase file: https://codeberg.org/Southporter/hush/src/commit/931dba033b5285f2fb4421dfc9cbe5a1f2585bb1/src/Image.zig#L93
I looked into the std.Io.Task code for the start, and it seems like this is comming back with a old_status.num_running == 0:
const old_status = group.status().fetchSub(.{
.num_running = 1,
.have_awaiter = false,
.canceled = false,
}, .acq_rel); // acquire `group.awaiter()`, release task results
assert(old_status.num_running > 0);
It seems like I am somehow getting into a state where there are 0 tasks running and this is somehow unexpected.
It’s also possible I’m using it wrong.
Any insights into how to reduce to a small reproduction this would be helpful.