diff --git a/lib/std/debug.zig b/lib/std/debug.zig index e22f2f7345..b10f98ee7b 100644 --- a/lib/std/debug.zig +++ b/lib/std/debug.zig @@ -567,13 +567,11 @@ pub const StackUnwindOptions = struct { /// /// See `writeCurrentStackTrace` to immediately print the trace instead of capturing it. pub fn captureCurrentStackTrace(options: StackUnwindOptions, addr_buf: []usize) std.builtin.StackTrace { - var it = StackIterator.init(options.context) catch { - return .{ .index = 0, .instruction_addresses = &.{} }; - }; + const empty_trace: std.builtin.StackTrace = .{ .index = 0, .instruction_addresses = &.{} }; + if (!std.options.allow_stack_tracing) return empty_trace; + var it = StackIterator.init(options.context) catch return empty_trace; defer it.deinit(); - if (!it.stratOk(options.allow_unsafe_unwind)) { - return .{ .index = 0, .instruction_addresses = &.{} }; - } + if (!it.stratOk(options.allow_unsafe_unwind)) return empty_trace; var frame_idx: usize = 0; var wait_for = options.first_address; while (true) switch (it.next()) { @@ -599,6 +597,12 @@ pub fn captureCurrentStackTrace(options: StackUnwindOptions, addr_buf: []usize) /// /// See `captureCurrentStackTrace` to capture the trace addresses into a buffer instead of printing. pub fn writeCurrentStackTrace(options: StackUnwindOptions, writer: *Writer, tty_config: tty.Config) Writer.Error!void { + if (!std.options.allow_stack_tracing) { + tty_config.setColor(writer, .dim) catch {}; + try writer.print("Cannot print stack trace: stack tracing is disabled\n", .{}); + tty_config.setColor(writer, .reset) catch {}; + return; + } const di_gpa = getDebugInfoAllocator(); const di = getSelfDebugInfo() catch |err| switch (err) { error.UnsupportedTarget => { @@ -688,6 +692,12 @@ pub fn dumpCurrentStackTrace(options: StackUnwindOptions) void { /// Write a previously captured stack trace to `writer`, annotated with source locations. pub fn writeStackTrace(st: *const std.builtin.StackTrace, writer: *Writer, tty_config: tty.Config) Writer.Error!void { + if (!std.options.allow_stack_tracing) { + tty_config.setColor(writer, .dim) catch {}; + try writer.print("Cannot print stack trace: stack tracing is disabled\n", .{}); + tty_config.setColor(writer, .reset) catch {}; + return; + } // Fetch `st.index` straight away. Aside from avoiding redundant loads, this prevents issues if // `st` is `@errorReturnTrace()` and errors are encountered while writing the stack trace. const n_frames = st.index; diff --git a/lib/std/std.zig b/lib/std/std.zig index 4a7f9bd866..4e68d1d611 100644 --- a/lib/std/std.zig +++ b/lib/std/std.zig @@ -171,6 +171,22 @@ pub const Options = struct { http_enable_ssl_key_log_file: bool = @import("builtin").mode == .Debug, side_channels_mitigations: crypto.SideChannelsMitigations = crypto.default_side_channels_mitigations, + + /// Whether to allow capturing and writing stack traces. This affects the following functions: + /// * `debug.captureCurrentStackTrace` + /// * `debug.writeCurrentStackTrace` + /// * `debug.dumpCurrentStackTrace` + /// * `debug.writeStackTrace` + /// * `debug.dumpStackTrace` + /// + /// Stack traces can generally be collected and printed when debug info is stripped, but are + /// often less useful since they usually cannot be mapped to source locations and/or have bad + /// source locations. The stack tracing logic can also be quite large, which may be undesirable, + /// particularly in ReleaseSmall. + /// + /// If this is `false`, then captured stack traces will always be empty, and attempts to write + /// stack traces will just print an error to the relevant `Io.Writer` and return. + allow_stack_tracing: bool = !@import("builtin").strip_debug_info, }; // This forces the start.zig file to be imported, and the comptime logic inside that diff --git a/test/cases/disable_stack_tracing.zig b/test/cases/disable_stack_tracing.zig new file mode 100644 index 0000000000..044eaf7012 --- /dev/null +++ b/test/cases/disable_stack_tracing.zig @@ -0,0 +1,28 @@ +pub const std_options: std.Options = .{ + .allow_stack_tracing = false, +}; + +pub fn main() !void { + var st_buf: [8]usize = undefined; + var buf: [1024]u8 = undefined; + var stdout = std.fs.File.stdout().writer(&buf); + + const captured_st = try foo(&stdout.interface, &st_buf); + try std.debug.writeStackTrace(&captured_st, &stdout.interface, .no_color); + try stdout.interface.print("stack trace index: {d}\n", .{captured_st.index}); + + try stdout.interface.flush(); +} +fn foo(w: *std.Io.Writer, st_buf: []usize) !std.builtin.StackTrace { + try std.debug.writeCurrentStackTrace(.{}, w, .no_color); + return std.debug.captureCurrentStackTrace(.{}, st_buf); +} + +const std = @import("std"); + +// run +// +// Cannot print stack trace: stack tracing is disabled +// Cannot print stack trace: stack tracing is disabled +// stack trace index: 0 +//