authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2025-09-08 14:31:45+01:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2025-09-30 13:44:51+01:00
log3a561da38d42ba331eb67bdb7d86d4a3e9b74533
treec24294aa672db7df3257b702a7ead5d3c06d07f3
parent0c7b2a7bd5433b7e7bcde3bb49d48226dc2adef9
signaturelock-open Commit is signed but in an unrecognized format.

std: doc comments and tweaks


2 files changed, 51 insertions(+), 28 deletions(-)

lib/std/debug.zig+50-28
......@@ -216,8 +216,12 @@ pub fn unlockStdErr() void {
216216///
217217/// During the lock, any `std.Progress` information is cleared from the terminal.
218218///
219/// Returns a `Writer` with empty buffer, meaning that it is
220/// in fact unbuffered and does not need to be flushed.
219/// The lock is recursive, so it is valid for the same thread to call `lockStderrWriter` multiple
220/// times. The primary motivation is that this allows the panic handler to safely dump the stack
221/// trace and panic message even if the mutex was held at the panic site.
222///
223/// The returned `Writer` does not need to be manually flushed: flushing is performed automatically
224/// when the matching `unlockStderrWriter` call occurs.
221225pub fn lockStderrWriter(buffer: []u8) *Writer {
222226 return std.Progress.lockStderrWriter(buffer);
223227}
......@@ -348,13 +352,12 @@ pub fn relocateContext(dest: *ThreadContext) void {
348352 }
349353}
350354
351pub const have_getcontext = @TypeOf(posix.system.getcontext) != void;
352
353355/// Capture the current context. The register values in the context will reflect the
354356/// state after the platform `getcontext` function returns.
355357///
356358/// It is valid to call this if the platform doesn't have context capturing support,
357/// in that case false will be returned.
359/// in that case `false` will be returned. This function is `inline` so that the `false`
360/// is comptime-known at the call site in that case.
358361pub inline fn getContext(context: *ThreadContext) bool {
359362 if (native_os == .windows) {
360363 context.* = std.mem.zeroes(windows.CONTEXT);
......@@ -362,18 +365,19 @@ pub inline fn getContext(context: *ThreadContext) bool {
362365 return true;
363366 }
364367
365 const result = have_getcontext and posix.system.getcontext(context) == 0;
366 if (native_os == .macos) {
367 assert(context.mcsize == @sizeOf(std.c.mcontext_t));
368 if (@TypeOf(posix.system.getcontext) != void) {
369 if (posix.system.getcontext(context) != 0) return false;
370 if (native_os == .macos) {
371 assert(context.mcsize == @sizeOf(std.c.mcontext_t));
368372
369 // On aarch64-macos, the system getcontext doesn't write anything into the pc
370 // register slot, it only writes lr. This makes the context consistent with
371 // other aarch64 getcontext implementations which write the current lr
372 // (where getcontext will return to) into both the lr and pc slot of the context.
373 if (native_arch == .aarch64) context.mcontext.ss.pc = context.mcontext.ss.lr;
373 // On aarch64-macos, the system getcontext doesn't write anything into the pc
374 // register slot, it only writes lr. This makes the context consistent with
375 // other aarch64 getcontext implementations which write the current lr
376 // (where getcontext will return to) into both the lr and pc slot of the context.
377 if (native_arch == .aarch64) context.mcontext.ss.pc = context.mcontext.ss.lr;
378 }
379 return true;
374380 }
375
376 return result;
377381}
378382
379383/// Invokes detectable illegal behavior when `ok` is `false`.
......@@ -413,8 +417,8 @@ pub fn panic(comptime format: []const u8, args: anytype) noreturn {
413417 panicExtra(@returnAddress(), format, args);
414418}
415419
416/// Equivalent to `@panic` but with a formatted message, and with an explicitly
417/// provided return address.
420/// Equivalent to `@panic` but with a formatted message and an explicitly provided return address
421/// which will be the first address in the stack trace.
418422pub fn panicExtra(
419423 ret_addr: ?usize,
420424 comptime format: []const u8,
......@@ -952,6 +956,7 @@ fn printLineInfo(
952956 }
953957}
954958fn printLineFromFile(writer: *Writer, source_location: SourceLocation) !void {
959 // Allow overriding the target-agnostic source line printing logic by exposing `root.debug.printLineFromFile`.
955960 if (@hasDecl(root, "debug") and @hasDecl(root.debug, "printLineFromFile")) {
956961 return root.debug.printLineFromFile(writer, source_location);
957962 }
......@@ -1139,17 +1144,17 @@ test printLineFromFile {
11391144}
11401145
11411146/// TODO multithreaded awareness
1142var debug_info_arena: ?std.heap.ArenaAllocator = null;
1143var debug_info_fba: std.heap.FixedBufferAllocator = .init(&debug_info_fba_buf);
1144var debug_info_fba_buf: [1024 * 1024 * 4]u8 = undefined;
1145fn getDebugInfoAllocator() mem.Allocator {
1146 if (false) {
1147 if (debug_info_arena == null) {
1148 debug_info_arena = .init(std.heap.page_allocator);
1149 }
1150 return debug_info_arena.?.allocator();
1147fn getDebugInfoAllocator() Allocator {
1148 // Allow overriding the debug info allocator by exposing `root.debug.getDebugInfoAllocator`.
1149 if (@hasDecl(root, "debug") and @hasDecl(root.debug, "getDebugInfoAllocator")) {
1150 return root.debug.getDebugInfoAllocator();
11511151 }
1152 return debug_info_fba.allocator();
1152 // Otherwise, use a global arena backed by the page allocator
1153 const S = struct {
1154 var arena: ?std.heap.ArenaAllocator = null;
1155 };
1156 if (S.arena == null) S.arena = .init(std.heap.page_allocator);
1157 return S.arena.?.allocator();
11531158}
11541159
11551160/// Whether or not the current target can print useful debug information when a segfault occurs.
......@@ -1184,7 +1189,16 @@ pub fn updateSegfaultHandler(act: ?*const posix.Sigaction) void {
11841189 posix.sigaction(posix.SIG.FPE, act, null);
11851190}
11861191
1187/// Attaches a global SIGSEGV handler which calls `@panic("segmentation fault");`
1192/// Attaches a global handler for several signals which, when triggered, prints output to stderr
1193/// similar to the default panic handler, with a message containing the type of signal and a stack
1194/// trace if possible. This implementation does not just call the panic handler, because unwinding
1195/// the stack (for a stack trace) when a signal is received requires special target-specific logic.
1196///
1197/// The signals for which a handler is installed are:
1198/// * SIGSEGV (segmentation fault)
1199/// * SIGILL (illegal instruction)
1200/// * SIGBUS (bus error)
1201/// * SIGFPE (arithmetic exception)
11881202pub fn attachSegfaultHandler() void {
11891203 if (!have_segfault_handling_support) {
11901204 @compileError("segfault handler not supported for this target");
......@@ -1305,6 +1319,14 @@ fn handleSegfaultWindows(info: *windows.EXCEPTION_POINTERS) callconv(.winapi) c_
13051319}
13061320
13071321fn handleSegfault(addr: ?usize, name: []const u8, opt_ctx: ?*ThreadContext) noreturn {
1322 // Allow overriding the target-agnostic segfault handler by exposing `root.debug.handleSegfault`.
1323 if (@hasDecl(root, "debug") and @hasDecl(root.debug, "handleSegfault")) {
1324 return root.debug.handleSegfault(addr, name, opt_ctx);
1325 }
1326 return defaultHandleSegfault(addr, name, opt_ctx);
1327}
1328
1329pub fn defaultHandleSegfault(addr: ?usize, name: []const u8, opt_ctx: ?*ThreadContext) noreturn {
13081330 // There is very similar logic to the following in `defaultPanic`.
13091331 switch (panic_stage) {
13101332 0 => {
lib/std/debug/SelfInfo.zig+1
......@@ -124,6 +124,7 @@ pub fn getModuleNameForAddress(self: *SelfInfo, gpa: Allocator, address: usize)
124124/// ) SelfInfo.Error!usize;
125125/// ```
126126const Module: type = Module: {
127 // Allow overriding the target-specific `SelfInfo` implementation by exposing `root.debug.Module`.
127128 if (@hasDecl(root, "debug") and @hasDecl(root.debug, "Module")) {
128129 break :Module root.debug.Module;
129130 }