atproto relay in zig zlay.waow.tech
relay zig atproto
Something went wrong. Try again.
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495///! Minimal reproduction: Io.Evented GPFs under ReleaseSafe on x86_64-linux.///! No external dependencies — pure zig stdlib.///!///! zig version: 0.16.0-dev.3059+42e33db9d (and unchanged through dev.3091)///! platform: x86_64-linux (io_uring required — Evented not available on macOS/darwin)///!///! Results:///! Debug — PASS///! ReleaseFast — PASS///! ReleaseSmall — PASS///! ReleaseSafe — GPF at fiber.zig:30 contextSwitch → Uring.zig:1142 mainIdle///!///! Root cause: LLVM register allocator bug. The inline asm in fiber.zig///! contextSwitch uses an explicit register constraint: "{rsi}" (s). Under///! ReleaseSafe, the stack probe (__zig_probe_stack) and canary (fs:0x28)///! instrumentation changes the code layout in Uring.idle such that LLVM///! fails to emit the `lea` that materializes the SwitchMessage address///! into %rsi before the inline asm block. %rsi is left holding a stale///! value from a prior function call (Thread.current), causing the context///! switch to write to a garbage address.///!///! Comparison of Uring.idle disassembly at the context switch:///!///! ReleaseFast: ReleaseSafe:///! lea -0x80(%rbp),%rsi ← CORRECT (missing — no lea before asm)///! ... call Thread.current ← clobbers rsi///! mov (%rsi),%rax ← valid ptr mov (%rsi),%rax ← stale value → GPF///!///! Build & run:///! zig build-exe -OReleaseSafe fiber_gpf_repro.zig -lc && ./fiber_gpf_reproconst std = @import("std");const Io = std.Io;
var evented: Io.Evented = undefined;
var debug_threaded_io: Io.Threaded = undefined;pub const std_options_debug_threaded_io: ?*Io.Threaded = &debug_threaded_io;
fn fiberReturn(_: Io) void { std.debug.print(" fiber: entered and returning\n", .{});}
fn fiberYield(io: Io) void { std.debug.print(" fiber: yielding\n", .{}); io.sleep(Io.Duration.fromMilliseconds(0), .awake) catch return; std.debug.print(" fiber: resumed\n", .{});}
fn fiberSleep(io: Io) void { std.debug.print(" fiber: sleeping 50ms\n", .{}); io.sleep(Io.Duration.fromMilliseconds(50), .awake) catch return; std.debug.print(" fiber: woke up\n", .{});}
pub fn main() !void { const allocator = std.heap.c_allocator;
debug_threaded_io = Io.Threaded.init(allocator, .{}); try Io.Evented.init(&evented, allocator, .{}); const io = evented.io();
std.debug.print("zig version: {s}\n", .{@import("builtin").zig_version_string}); std.debug.print("optimize: {s}\n", .{@tagName(@import("builtin").mode)}); std.debug.print("Io backend: Evented\n\n", .{});
// test 1: immediate return — GPFs here under ReleaseSafe std.debug.print("test 1: fiber returns immediately\n", .{}); { var f = try io.concurrent(fiberReturn, .{io}); io.sleep(Io.Duration.fromMilliseconds(10), .awake) catch {}; f.cancel(io); } std.debug.print("test 1: PASSED\n\n", .{});
// test 2: yield once std.debug.print("test 2: fiber yields once\n", .{}); { var f = try io.concurrent(fiberYield, .{io}); io.sleep(Io.Duration.fromMilliseconds(50), .awake) catch {}; f.cancel(io); } std.debug.print("test 2: PASSED\n\n", .{});
// test 3: sleep std.debug.print("test 3: fiber sleeps 50ms\n", .{}); { var f = try io.concurrent(fiberSleep, .{io}); io.sleep(Io.Duration.fromMilliseconds(200), .awake) catch {}; f.cancel(io); } std.debug.print("test 3: PASSED\n\n", .{});
std.debug.print("all tests passed\n", .{});}