| author | |
| committer | |
| log | 3a9c680ad7b88ed6d9684626be9138ffc44b73b7 |
| tree | d8d9363fc60b59a966c94b8ed69e37edaf8315d9 |
| parent | abb2b1e2daffdadca7edc26634631215df901950 |
| signature |
This option disables both capturing and printing stack traces. The
default is to disable if debug info is stripped.3 files changed, 60 insertions(+), 6 deletions(-)
lib/std/debug.zig+16-6| ... | ... | @@ -567,13 +567,11 @@ pub const StackUnwindOptions = struct { |
| 567 | 567 | /// |
| 568 | 568 | /// See `writeCurrentStackTrace` to immediately print the trace instead of capturing it. |
| 569 | 569 | pub fn captureCurrentStackTrace(options: StackUnwindOptions, addr_buf: []usize) std.builtin.StackTrace { |
| 570 | var it = StackIterator.init(options.context) catch { | |
| 571 | return .{ .index = 0, .instruction_addresses = &.{} }; | |
| 572 | }; | |
| 570 | const empty_trace: std.builtin.StackTrace = .{ .index = 0, .instruction_addresses = &.{} }; | |
| 571 | if (!std.options.allow_stack_tracing) return empty_trace; | |
| 572 | var it = StackIterator.init(options.context) catch return empty_trace; | |
| 573 | 573 | defer it.deinit(); |
| 574 | if (!it.stratOk(options.allow_unsafe_unwind)) { | |
| 575 | return .{ .index = 0, .instruction_addresses = &.{} }; | |
| 576 | } | |
| 574 | if (!it.stratOk(options.allow_unsafe_unwind)) return empty_trace; | |
| 577 | 575 | var frame_idx: usize = 0; |
| 578 | 576 | var wait_for = options.first_address; |
| 579 | 577 | while (true) switch (it.next()) { |
| ... | ... | @@ -599,6 +597,12 @@ pub fn captureCurrentStackTrace(options: StackUnwindOptions, addr_buf: []usize) |
| 599 | 597 | /// |
| 600 | 598 | /// See `captureCurrentStackTrace` to capture the trace addresses into a buffer instead of printing. |
| 601 | 599 | pub fn writeCurrentStackTrace(options: StackUnwindOptions, writer: *Writer, tty_config: tty.Config) Writer.Error!void { |
| 600 | if (!std.options.allow_stack_tracing) { | |
| 601 | tty_config.setColor(writer, .dim) catch {}; | |
| 602 | try writer.print("Cannot print stack trace: stack tracing is disabled\n", .{}); | |
| 603 | tty_config.setColor(writer, .reset) catch {}; | |
| 604 | return; | |
| 605 | } | |
| 602 | 606 | const di_gpa = getDebugInfoAllocator(); |
| 603 | 607 | const di = getSelfDebugInfo() catch |err| switch (err) { |
| 604 | 608 | error.UnsupportedTarget => { |
| ... | ... | @@ -688,6 +692,12 @@ pub fn dumpCurrentStackTrace(options: StackUnwindOptions) void { |
| 688 | 692 | |
| 689 | 693 | /// Write a previously captured stack trace to `writer`, annotated with source locations. |
| 690 | 694 | pub fn writeStackTrace(st: *const std.builtin.StackTrace, writer: *Writer, tty_config: tty.Config) Writer.Error!void { |
| 695 | if (!std.options.allow_stack_tracing) { | |
| 696 | tty_config.setColor(writer, .dim) catch {}; | |
| 697 | try writer.print("Cannot print stack trace: stack tracing is disabled\n", .{}); | |
| 698 | tty_config.setColor(writer, .reset) catch {}; | |
| 699 | return; | |
| 700 | } | |
| 691 | 701 | // Fetch `st.index` straight away. Aside from avoiding redundant loads, this prevents issues if |
| 692 | 702 | // `st` is `@errorReturnTrace()` and errors are encountered while writing the stack trace. |
| 693 | 703 | const n_frames = st.index; |
lib/std/std.zig+16| ... | ... | @@ -171,6 +171,22 @@ pub const Options = struct { |
| 171 | 171 | http_enable_ssl_key_log_file: bool = @import("builtin").mode == .Debug, |
| 172 | 172 | |
| 173 | 173 | side_channels_mitigations: crypto.SideChannelsMitigations = crypto.default_side_channels_mitigations, |
| 174 | ||
| 175 | /// Whether to allow capturing and writing stack traces. This affects the following functions: | |
| 176 | /// * `debug.captureCurrentStackTrace` | |
| 177 | /// * `debug.writeCurrentStackTrace` | |
| 178 | /// * `debug.dumpCurrentStackTrace` | |
| 179 | /// * `debug.writeStackTrace` | |
| 180 | /// * `debug.dumpStackTrace` | |
| 181 | /// | |
| 182 | /// Stack traces can generally be collected and printed when debug info is stripped, but are | |
| 183 | /// often less useful since they usually cannot be mapped to source locations and/or have bad | |
| 184 | /// source locations. The stack tracing logic can also be quite large, which may be undesirable, | |
| 185 | /// particularly in ReleaseSmall. | |
| 186 | /// | |
| 187 | /// If this is `false`, then captured stack traces will always be empty, and attempts to write | |
| 188 | /// stack traces will just print an error to the relevant `Io.Writer` and return. | |
| 189 | allow_stack_tracing: bool = !@import("builtin").strip_debug_info, | |
| 174 | 190 | }; |
| 175 | 191 | |
| 176 | 192 | // This forces the start.zig file to be imported, and the comptime logic inside that |
test/cases/disable_stack_tracing.zig created+28| ... | ... | @@ -0,0 +1,28 @@ |
| 1 | pub const std_options: std.Options = .{ | |
| 2 | .allow_stack_tracing = false, | |
| 3 | }; | |
| 4 | ||
| 5 | pub fn main() !void { | |
| 6 | var st_buf: [8]usize = undefined; | |
| 7 | var buf: [1024]u8 = undefined; | |
| 8 | var stdout = std.fs.File.stdout().writer(&buf); | |
| 9 | ||
| 10 | const captured_st = try foo(&stdout.interface, &st_buf); | |
| 11 | try std.debug.writeStackTrace(&captured_st, &stdout.interface, .no_color); | |
| 12 | try stdout.interface.print("stack trace index: {d}\n", .{captured_st.index}); | |
| 13 | ||
| 14 | try stdout.interface.flush(); | |
| 15 | } | |
| 16 | fn foo(w: *std.Io.Writer, st_buf: []usize) !std.builtin.StackTrace { | |
| 17 | try std.debug.writeCurrentStackTrace(.{}, w, .no_color); | |
| 18 | return std.debug.captureCurrentStackTrace(.{}, st_buf); | |
| 19 | } | |
| 20 | ||
| 21 | const std = @import("std"); | |
| 22 | ||
| 23 | // run | |
| 24 | // | |
| 25 | // Cannot print stack trace: stack tracing is disabled | |
| 26 | // Cannot print stack trace: stack tracing is disabled | |
| 27 | // stack trace index: 0 | |
| 28 | // |