mirror of
https://github.com/ziglang/zig.git
synced 2025-12-06 06:13:07 +00:00
embrace panic helpers
Introduces `std.builtin.Panic` which is a complete interface for panicking. Provide `std.debug.FormattedPanic` and `std.debug.SimplePanic` and let the user choose, or make their own.
This commit is contained in:
parent
fcfbedc2f0
commit
c9c080a187
@ -75,11 +75,14 @@ pub const gnu_f16_abi = switch (builtin.cpu.arch) {
|
||||
|
||||
pub const want_sparc_abi = builtin.cpu.arch.isSPARC();
|
||||
|
||||
// Avoid dragging in the runtime safety mechanisms into this .o file,
|
||||
// unless we're trying to test compiler-rt.
|
||||
pub fn panic(cause: std.builtin.PanicCause, error_return_trace: ?*std.builtin.StackTrace, ret_addr: ?usize) noreturn {
|
||||
// Avoid dragging in the runtime safety mechanisms into this .o file, unless
|
||||
// we're trying to test compiler-rt.
|
||||
pub const Panic = if (builtin.is_test) std.debug.FormattedPanic else struct {};
|
||||
|
||||
/// To be deleted after zig1.wasm is updated.
|
||||
pub fn panic(msg: []const u8, error_return_trace: ?*std.builtin.StackTrace, ret_addr: ?usize) noreturn {
|
||||
if (builtin.is_test) {
|
||||
std.debug.defaultPanic(cause, error_return_trace, ret_addr orelse @returnAddress());
|
||||
std.debug.defaultPanic(msg, error_return_trace, ret_addr orelse @returnAddress());
|
||||
} else {
|
||||
unreachable;
|
||||
}
|
||||
|
||||
@ -761,11 +761,10 @@ pub const TestFn = struct {
|
||||
func: *const fn () anyerror!void,
|
||||
};
|
||||
|
||||
/// This function type is used by the Zig language code generation and
|
||||
/// therefore must be kept in sync with the compiler implementation.
|
||||
pub const PanicFn = fn (PanicCause, ?*StackTrace, ?usize) noreturn;
|
||||
/// Deprecated, use the `Panic` namespace instead.
|
||||
pub const PanicFn = fn ([]const u8, ?*StackTrace, ?usize) noreturn;
|
||||
|
||||
/// The entry point for auto-generated calls by the compiler.
|
||||
/// Deprecated, use the `Panic` namespace instead.
|
||||
pub const panic: PanicFn = if (@hasDecl(root, "panic"))
|
||||
root.panic
|
||||
else if (@hasDecl(root, "os") and @hasDecl(root.os, "panic"))
|
||||
@ -773,143 +772,28 @@ else if (@hasDecl(root, "os") and @hasDecl(root.os, "panic"))
|
||||
else
|
||||
std.debug.defaultPanic;
|
||||
|
||||
/// This data structure is used by the Zig language code generation and
|
||||
/// therefore must be kept in sync with the compiler implementation.
|
||||
pub const PanicCause = union(enum) {
|
||||
reached_unreachable,
|
||||
unwrap_null,
|
||||
cast_to_null,
|
||||
incorrect_alignment,
|
||||
invalid_error_code,
|
||||
cast_truncated_data,
|
||||
negative_to_unsigned,
|
||||
integer_overflow,
|
||||
shl_overflow,
|
||||
shr_overflow,
|
||||
divide_by_zero,
|
||||
exact_division_remainder,
|
||||
inactive_union_field: InactiveUnionField,
|
||||
integer_part_out_of_bounds,
|
||||
corrupt_switch,
|
||||
shift_rhs_too_big,
|
||||
invalid_enum_value,
|
||||
sentinel_mismatch_usize: SentinelMismatchUsize,
|
||||
sentinel_mismatch_other,
|
||||
unwrap_error: anyerror,
|
||||
index_out_of_bounds: IndexOutOfBounds,
|
||||
start_index_greater_than_end: StartIndexGreaterThanEnd,
|
||||
for_len_mismatch,
|
||||
memcpy_len_mismatch,
|
||||
memcpy_alias,
|
||||
noreturn_returned,
|
||||
explicit_call: []const u8,
|
||||
sentinel_mismatch_isize: SentinelMismatchIsize,
|
||||
/// This namespace is used by the Zig compiler to emit various kinds of safety
|
||||
/// panics. These can be overridden by making a public `Panic` namespace in the
|
||||
/// root source file.
|
||||
pub const Panic: type = if (@hasDecl(root, "Panic"))
|
||||
root.Panic
|
||||
else if (std.builtin.zig_backend == .stage2_riscv64)
|
||||
std.debug.SimplePanic // https://github.com/ziglang/zig/issues/21519
|
||||
else
|
||||
std.debug.FormattedPanic;
|
||||
|
||||
pub const IndexOutOfBounds = struct {
|
||||
index: usize,
|
||||
len: usize,
|
||||
};
|
||||
|
||||
pub const StartIndexGreaterThanEnd = struct {
|
||||
start: usize,
|
||||
end: usize,
|
||||
};
|
||||
|
||||
pub const SentinelMismatchUsize = struct {
|
||||
expected: usize,
|
||||
found: usize,
|
||||
};
|
||||
|
||||
pub const SentinelMismatchIsize = struct {
|
||||
expected: isize,
|
||||
found: isize,
|
||||
};
|
||||
|
||||
pub const InactiveUnionField = struct {
|
||||
active: []const u8,
|
||||
accessed: []const u8,
|
||||
};
|
||||
};
|
||||
|
||||
pub fn panicSentinelMismatch(expected: anytype, found: @TypeOf(expected)) noreturn {
|
||||
@branchHint(.cold);
|
||||
if (builtin.zig_backend == .stage2_riscv64) {
|
||||
// https://github.com/ziglang/zig/issues/21519
|
||||
@trap();
|
||||
}
|
||||
switch (@typeInfo(@TypeOf(expected))) {
|
||||
.int => |int| switch (int.signedness) {
|
||||
.unsigned => if (int.bits <= @bitSizeOf(usize)) panic(.{ .sentinel_mismatch_usize = .{
|
||||
.expected = expected,
|
||||
.found = found,
|
||||
} }, null, @returnAddress()),
|
||||
.signed => if (int.bits <= @bitSizeOf(isize)) panic(.{ .sentinel_mismatch_isize = .{
|
||||
.expected = expected,
|
||||
.found = found,
|
||||
} }, null, @returnAddress()),
|
||||
},
|
||||
.@"enum" => |info| switch (@typeInfo(info.tag_type)) {
|
||||
.int => |int| switch (int.signedness) {
|
||||
.unsigned => if (int.bits <= @bitSizeOf(usize)) panic(.{ .sentinel_mismatch_usize = .{
|
||||
.expected = @intFromEnum(expected),
|
||||
.found = @intFromEnum(found),
|
||||
} }, null, @returnAddress()),
|
||||
.signed => if (int.bits <= @bitSizeOf(isize)) panic(.{ .sentinel_mismatch_isize = .{
|
||||
.expected = @intFromEnum(expected),
|
||||
.found = @intFromEnum(found),
|
||||
} }, null, @returnAddress()),
|
||||
},
|
||||
else => comptime unreachable,
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
panic(.sentinel_mismatch_other, null, @returnAddress());
|
||||
}
|
||||
|
||||
pub fn panicUnwrapError(ert: ?*StackTrace, err: anyerror) noreturn {
|
||||
@branchHint(.cold);
|
||||
if (builtin.zig_backend == .stage2_riscv64) {
|
||||
// https://github.com/ziglang/zig/issues/21519
|
||||
@trap();
|
||||
}
|
||||
panic(.{ .unwrap_error = err }, ert, @returnAddress());
|
||||
}
|
||||
|
||||
pub fn panicOutOfBounds(index: usize, len: usize) noreturn {
|
||||
@branchHint(.cold);
|
||||
if (builtin.zig_backend == .stage2_riscv64) {
|
||||
// https://github.com/ziglang/zig/issues/21519
|
||||
@trap();
|
||||
}
|
||||
panic(.{ .index_out_of_bounds = .{
|
||||
.index = index,
|
||||
.len = len,
|
||||
} }, null, @returnAddress());
|
||||
}
|
||||
|
||||
pub fn panicStartGreaterThanEnd(start: usize, end: usize) noreturn {
|
||||
@branchHint(.cold);
|
||||
if (builtin.zig_backend == .stage2_riscv64) {
|
||||
// https://github.com/ziglang/zig/issues/21519
|
||||
@trap();
|
||||
}
|
||||
panic(.{ .start_index_greater_than_end = .{
|
||||
.start = start,
|
||||
.end = end,
|
||||
} }, null, @returnAddress());
|
||||
}
|
||||
|
||||
pub fn panicInactiveUnionField(active: anytype, accessed: @TypeOf(active)) noreturn {
|
||||
@branchHint(.cold);
|
||||
if (builtin.zig_backend == .stage2_riscv64) {
|
||||
// https://github.com/ziglang/zig/issues/21519
|
||||
@trap();
|
||||
}
|
||||
panic(.{ .inactive_union_field = .{
|
||||
.active = @tagName(active),
|
||||
.accessed = @tagName(accessed),
|
||||
} }, null, @returnAddress());
|
||||
}
|
||||
/// To be deleted after zig1.wasm is updated.
|
||||
pub const panicSentinelMismatch = Panic.sentinelMismatch;
|
||||
/// To be deleted after zig1.wasm is updated.
|
||||
pub const panicUnwrapError = Panic.unwrapError;
|
||||
/// To be deleted after zig1.wasm is updated.
|
||||
pub const panicOutOfBounds = Panic.outOfBounds;
|
||||
/// To be deleted after zig1.wasm is updated.
|
||||
pub const panicStartGreaterThanEnd = Panic.startGreaterThanEnd;
|
||||
/// To be deleted after zig1.wasm is updated.
|
||||
pub const panicInactiveUnionField = Panic.inactiveUnionField;
|
||||
/// To be deleted after zig1.wasm is updated.
|
||||
pub const panic_messages = Panic.messages;
|
||||
|
||||
pub noinline fn returnError(st: *StackTrace) void {
|
||||
@branchHint(.unlikely);
|
||||
|
||||
@ -21,6 +21,9 @@ pub const SelfInfo = @import("debug/SelfInfo.zig");
|
||||
pub const Info = @import("debug/Info.zig");
|
||||
pub const Coverage = @import("debug/Coverage.zig");
|
||||
|
||||
pub const FormattedPanic = @import("debug/FormattedPanic.zig");
|
||||
pub const SimplePanic = @import("debug/SimplePanic.zig");
|
||||
|
||||
/// Unresolved source locations can be represented with a single `usize` that
|
||||
/// corresponds to a virtual memory address of the program counter. Combined
|
||||
/// with debug information, those values can be converted into a resolved
|
||||
@ -408,10 +411,16 @@ pub fn assertReadable(slice: []const volatile u8) void {
|
||||
for (slice) |*byte| _ = byte.*;
|
||||
}
|
||||
|
||||
/// By including a call to this function, the caller gains an error return trace
|
||||
/// secret parameter, making `@errorReturnTrace()` more useful. This is not
|
||||
/// necessary if the function already contains a call to an errorable function
|
||||
/// elsewhere.
|
||||
pub fn errorReturnTraceHelper() anyerror!void {}
|
||||
|
||||
/// Equivalent to `@panic` but with a formatted message.
|
||||
pub fn panic(comptime format: []const u8, args: anytype) noreturn {
|
||||
@branchHint(.cold);
|
||||
|
||||
errorReturnTraceHelper() catch unreachable;
|
||||
panicExtra(@errorReturnTrace(), @returnAddress(), format, args);
|
||||
}
|
||||
|
||||
@ -437,7 +446,7 @@ pub fn panicExtra(
|
||||
break :blk &buf;
|
||||
},
|
||||
};
|
||||
std.builtin.panic(.{ .explicit_call = msg }, trace, ret_addr);
|
||||
std.builtin.Panic.call(msg, trace, ret_addr);
|
||||
}
|
||||
|
||||
/// Non-zero whenever the program triggered a panic.
|
||||
@ -448,11 +457,9 @@ var panicking = std.atomic.Value(u8).init(0);
|
||||
/// This is used to catch and handle panics triggered by the panic handler.
|
||||
threadlocal var panic_stage: usize = 0;
|
||||
|
||||
// Dumps a stack trace to standard error, then aborts.
|
||||
//
|
||||
// This function avoids a dependency on formatted printing.
|
||||
/// Dumps a stack trace to standard error, then aborts.
|
||||
pub fn defaultPanic(
|
||||
cause: std.builtin.PanicCause,
|
||||
msg: []const u8,
|
||||
error_return_trace: ?*const std.builtin.StackTrace,
|
||||
first_trace_addr: ?usize,
|
||||
) noreturn {
|
||||
@ -471,18 +478,6 @@ pub fn defaultPanic(
|
||||
@trap();
|
||||
}
|
||||
|
||||
if (builtin.zig_backend == .stage2_riscv64) {
|
||||
var buffer: [1000]u8 = undefined;
|
||||
var i: usize = 0;
|
||||
i += fmtPanicCause(buffer[i..], cause);
|
||||
buffer[i] = '\n';
|
||||
i += 1;
|
||||
const msg = buffer[0..i];
|
||||
lockStdErr();
|
||||
io.getStdErr().writeAll(msg) catch {};
|
||||
@trap();
|
||||
}
|
||||
|
||||
switch (builtin.os.tag) {
|
||||
.freestanding => {
|
||||
@trap();
|
||||
@ -490,14 +485,10 @@ pub fn defaultPanic(
|
||||
.uefi => {
|
||||
const uefi = std.os.uefi;
|
||||
|
||||
var buffer: [1000]u8 = undefined;
|
||||
var i: usize = 0;
|
||||
i += fmtBuf(buffer[i..], "panic: ");
|
||||
i += fmtPanicCause(buffer[i..], cause);
|
||||
i += fmtBuf(buffer[i..], "\r\n\x00");
|
||||
|
||||
var utf16_buffer: [1000]u16 = undefined;
|
||||
const len = std.unicode.utf8ToUtf16Le(&utf16_buffer, buffer[0..i]) catch 0;
|
||||
const len_minus_3 = std.unicode.utf8ToUtf16Le(&utf16_buffer, msg) catch 0;
|
||||
utf16_buffer[len_minus_3][0..3].* = .{ '\r', '\n', 0 };
|
||||
const len = len_minus_3 + 3;
|
||||
const exit_msg = utf16_buffer[0 .. len - 1 :0];
|
||||
|
||||
// Output to both std_err and con_out, as std_err is easier
|
||||
@ -521,15 +512,11 @@ pub fn defaultPanic(
|
||||
},
|
||||
.cuda, .amdhsa => std.posix.abort(),
|
||||
.plan9 => {
|
||||
var buffer: [1000]u8 = undefined;
|
||||
comptime assert(buffer.len > std.os.plan9.ERRMAX);
|
||||
var i: usize = 0;
|
||||
i += fmtPanicCause(buffer[i..], cause);
|
||||
buffer[i] = '\n';
|
||||
i += 1;
|
||||
const len = @min(i, std.os.plan9.ERRMAX - 1);
|
||||
buffer[len] = 0;
|
||||
std.os.plan9.exits(buffer[0..len :0]);
|
||||
var status: [std.os.plan9.ERRMAX]u8 = undefined;
|
||||
const len = @min(msg.len, status.len - 1);
|
||||
@memcpy(status[0..len], msg[0..len]);
|
||||
status[len] = 0;
|
||||
std.os.plan9.exits(status[0..len :0]);
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
@ -548,26 +535,18 @@ pub fn defaultPanic(
|
||||
_ = panicking.fetchAdd(1, .seq_cst);
|
||||
|
||||
{
|
||||
// This code avoids a dependency on formatted printing, the writer interface,
|
||||
// and limits to only 1 syscall made to print the panic message to stderr.
|
||||
var buffer: [0x1000]u8 = undefined;
|
||||
var i: usize = 0;
|
||||
if (builtin.single_threaded) {
|
||||
i += fmtBuf(buffer[i..], "panic: ");
|
||||
} else {
|
||||
i += fmtBuf(buffer[i..], "thread ");
|
||||
i += fmtInt10(buffer[i..], std.Thread.getCurrentId());
|
||||
i += fmtBuf(buffer[i..], " panic: ");
|
||||
}
|
||||
i += fmtPanicCause(buffer[i..], cause);
|
||||
buffer[i] = '\n';
|
||||
i += 1;
|
||||
const msg = buffer[0..i];
|
||||
|
||||
lockStdErr();
|
||||
defer unlockStdErr();
|
||||
|
||||
io.getStdErr().writeAll(msg) catch posix.abort();
|
||||
const stderr = io.getStdErr().writer();
|
||||
if (builtin.single_threaded) {
|
||||
stderr.print("panic: ", .{}) catch posix.abort();
|
||||
} else {
|
||||
const current_thread_id = std.Thread.getCurrentId();
|
||||
stderr.print("thread {} panic: ", .{current_thread_id}) catch posix.abort();
|
||||
}
|
||||
stderr.print("{s}\n", .{msg}) catch posix.abort();
|
||||
|
||||
if (error_return_trace) |t| dumpStackTrace(t.*);
|
||||
dumpCurrentStackTrace(first_trace_addr orelse @returnAddress());
|
||||
}
|
||||
@ -588,108 +567,6 @@ pub fn defaultPanic(
|
||||
posix.abort();
|
||||
}
|
||||
|
||||
pub fn fmtPanicCause(buffer: []u8, cause: std.builtin.PanicCause) usize {
|
||||
var i: usize = 0;
|
||||
|
||||
switch (cause) {
|
||||
.reached_unreachable => i += fmtBuf(buffer[i..], "reached unreachable code"),
|
||||
.unwrap_null => i += fmtBuf(buffer[i..], "attempt to use null value"),
|
||||
.cast_to_null => i += fmtBuf(buffer[i..], "cast causes pointer to be null"),
|
||||
.incorrect_alignment => i += fmtBuf(buffer[i..], "incorrect alignment"),
|
||||
.invalid_error_code => i += fmtBuf(buffer[i..], "invalid error code"),
|
||||
.cast_truncated_data => i += fmtBuf(buffer[i..], "integer cast truncated bits"),
|
||||
.negative_to_unsigned => i += fmtBuf(buffer[i..], "attempt to cast negative value to unsigned integer"),
|
||||
.integer_overflow => i += fmtBuf(buffer[i..], "integer overflow"),
|
||||
.shl_overflow => i += fmtBuf(buffer[i..], "left shift overflowed bits"),
|
||||
.shr_overflow => i += fmtBuf(buffer[i..], "right shift overflowed bits"),
|
||||
.divide_by_zero => i += fmtBuf(buffer[i..], "division by zero"),
|
||||
.exact_division_remainder => i += fmtBuf(buffer[i..], "exact division produced remainder"),
|
||||
.inactive_union_field => |info| {
|
||||
i += fmtBuf(buffer[i..], "access of union field '");
|
||||
i += fmtBuf(buffer[i..], info.accessed);
|
||||
i += fmtBuf(buffer[i..], "' while field '");
|
||||
i += fmtBuf(buffer[i..], info.active);
|
||||
i += fmtBuf(buffer[i..], "' is active");
|
||||
},
|
||||
.integer_part_out_of_bounds => i += fmtBuf(buffer[i..], "integer part of floating point value out of bounds"),
|
||||
.corrupt_switch => i += fmtBuf(buffer[i..], "switch on corrupt value"),
|
||||
.shift_rhs_too_big => i += fmtBuf(buffer[i..], "shift amount is greater than the type size"),
|
||||
.invalid_enum_value => i += fmtBuf(buffer[i..], "invalid enum value"),
|
||||
.sentinel_mismatch_usize => |mm| {
|
||||
i += fmtBuf(buffer[i..], "sentinel mismatch: expected ");
|
||||
i += fmtInt10(buffer[i..], mm.expected);
|
||||
i += fmtBuf(buffer[i..], ", found ");
|
||||
i += fmtInt10(buffer[i..], mm.found);
|
||||
},
|
||||
.sentinel_mismatch_isize => |mm| {
|
||||
i += fmtBuf(buffer[i..], "sentinel mismatch: expected ");
|
||||
i += fmtInt10s(buffer[i..], mm.expected);
|
||||
i += fmtBuf(buffer[i..], ", found ");
|
||||
i += fmtInt10s(buffer[i..], mm.found);
|
||||
},
|
||||
.sentinel_mismatch_other => i += fmtBuf(buffer[i..], "sentinel mismatch"),
|
||||
.unwrap_error => |err| {
|
||||
if (builtin.zig_backend == .stage2_riscv64) {
|
||||
// https://github.com/ziglang/zig/issues/21519
|
||||
i += fmtBuf(buffer[i..], "attempt to unwrap error");
|
||||
return i;
|
||||
}
|
||||
i += fmtBuf(buffer[i..], "attempt to unwrap error: ");
|
||||
i += fmtBuf(buffer[i..], @errorName(err));
|
||||
},
|
||||
.index_out_of_bounds => |oob| {
|
||||
i += fmtBuf(buffer[i..], "index ");
|
||||
i += fmtInt10(buffer[i..], oob.index);
|
||||
i += fmtBuf(buffer[i..], " exceeds length ");
|
||||
i += fmtInt10(buffer[i..], oob.len);
|
||||
},
|
||||
.start_index_greater_than_end => |oob| {
|
||||
i += fmtBuf(buffer[i..], "start index ");
|
||||
i += fmtInt10(buffer[i..], oob.start);
|
||||
i += fmtBuf(buffer[i..], " exceeds end index ");
|
||||
i += fmtInt10(buffer[i..], oob.end);
|
||||
},
|
||||
.for_len_mismatch => i += fmtBuf(buffer[i..], "for loop over objects with non-equal lengths"),
|
||||
.memcpy_len_mismatch => i += fmtBuf(buffer[i..], "@memcpy arguments have non-equal lengths"),
|
||||
.memcpy_alias => i += fmtBuf(buffer[i..], "@memcpy arguments alias"),
|
||||
.noreturn_returned => i += fmtBuf(buffer[i..], "'noreturn' function returned"),
|
||||
.explicit_call => |msg| i += fmtBuf(buffer[i..], msg),
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
fn fmtBuf(out_buf: []u8, s: []const u8) usize {
|
||||
@memcpy(out_buf[0..s.len], s);
|
||||
return s.len;
|
||||
}
|
||||
|
||||
fn fmtInt10s(out_buf: []u8, integer_value: isize) usize {
|
||||
if (integer_value < 0) {
|
||||
out_buf[0] = '-';
|
||||
return 1 + fmtInt10(out_buf[1..], @abs(integer_value));
|
||||
} else {
|
||||
return fmtInt10(out_buf, @abs(integer_value));
|
||||
}
|
||||
}
|
||||
|
||||
fn fmtInt10(out_buf: []u8, integer_value: usize) usize {
|
||||
var tmp_buf: [50]u8 = undefined;
|
||||
var i: usize = tmp_buf.len;
|
||||
var a: usize = integer_value;
|
||||
|
||||
while (true) {
|
||||
i -= 1;
|
||||
tmp_buf[i] = '0' + @as(u8, @intCast(a % 10));
|
||||
a /= 10;
|
||||
if (a == 0) break;
|
||||
}
|
||||
|
||||
const result = tmp_buf[i..];
|
||||
@memcpy(out_buf[0..result.len], result);
|
||||
return result.len;
|
||||
}
|
||||
|
||||
/// Must be called only after adding 1 to `panicking`. There are three callsites.
|
||||
fn waitForOtherThreadToFinishPanicking() void {
|
||||
if (panicking.fetchSub(1, .seq_cst) != 1) {
|
||||
|
||||
45
lib/std/debug/FormattedPanic.zig
Normal file
45
lib/std/debug/FormattedPanic.zig
Normal file
@ -0,0 +1,45 @@
|
||||
//! This namespace is the default one used by the Zig compiler to emit various
|
||||
//! kinds of safety panics, due to the logic in `std.builtin.Panic`.
|
||||
//!
|
||||
//! Since Zig does not have interfaces, this file serves as an example template
|
||||
//! for users to provide their own alternative panic handling.
|
||||
//!
|
||||
//! As an alternative, see `std.debug.SimplePanic`.
|
||||
|
||||
const std = @import("../std.zig");
|
||||
|
||||
/// Dumps a stack trace to standard error, then aborts.
|
||||
///
|
||||
/// Explicit calls to `@panic` lower to calling this function.
|
||||
pub const call: fn ([]const u8, ?*std.builtin.StackTrace, ?usize) noreturn = std.debug.defaultPanic;
|
||||
|
||||
pub fn sentinelMismatch(expected: anytype, found: @TypeOf(expected)) noreturn {
|
||||
@branchHint(.cold);
|
||||
std.debug.panicExtra(null, @returnAddress(), "sentinel mismatch: expected {any}, found {any}", .{
|
||||
expected, found,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn unwrapError(ert: ?*std.builtin.StackTrace, err: anyerror) noreturn {
|
||||
@branchHint(.cold);
|
||||
std.debug.panicExtra(ert, @returnAddress(), "attempt to unwrap error: {s}", .{@errorName(err)});
|
||||
}
|
||||
|
||||
pub fn outOfBounds(index: usize, len: usize) noreturn {
|
||||
@branchHint(.cold);
|
||||
std.debug.panicExtra(null, @returnAddress(), "index out of bounds: index {d}, len {d}", .{ index, len });
|
||||
}
|
||||
|
||||
pub fn startGreaterThanEnd(start: usize, end: usize) noreturn {
|
||||
@branchHint(.cold);
|
||||
std.debug.panicExtra(null, @returnAddress(), "start index {d} is larger than end index {d}", .{ start, end });
|
||||
}
|
||||
|
||||
pub fn inactiveUnionField(active: anytype, accessed: @TypeOf(active)) noreturn {
|
||||
@branchHint(.cold);
|
||||
std.debug.panicExtra(null, @returnAddress(), "access of union field '{s}' while field '{s}' is active", .{
|
||||
@tagName(accessed), @tagName(active),
|
||||
});
|
||||
}
|
||||
|
||||
pub const messages = std.debug.SimplePanic.messages;
|
||||
86
lib/std/debug/SimplePanic.zig
Normal file
86
lib/std/debug/SimplePanic.zig
Normal file
@ -0,0 +1,86 @@
|
||||
//! This namespace is the default one used by the Zig compiler to emit various
|
||||
//! kinds of safety panics, due to the logic in `std.builtin.Panic`.
|
||||
//!
|
||||
//! Since Zig does not have interfaces, this file serves as an example template
|
||||
//! for users to provide their own alternative panic handling.
|
||||
//!
|
||||
//! As an alternative, see `std.debug.FormattedPanic`.
|
||||
|
||||
const std = @import("../std.zig");
|
||||
|
||||
/// Prints the message to stderr without a newline and then traps.
|
||||
///
|
||||
/// Explicit calls to `@panic` lower to calling this function.
|
||||
pub fn call(msg: []const u8, ert: ?*std.builtin.StackTrace, ra: ?usize) noreturn {
|
||||
@branchHint(.cold);
|
||||
_ = ert;
|
||||
_ = ra;
|
||||
std.debug.lockStdErr();
|
||||
const stderr = std.io.getStdErr();
|
||||
stderr.writeAll(msg) catch {};
|
||||
@trap();
|
||||
}
|
||||
|
||||
pub fn sentinelMismatch(expected: anytype, found: @TypeOf(expected)) noreturn {
|
||||
_ = found;
|
||||
call("sentinel mismatch", null, null);
|
||||
}
|
||||
|
||||
pub fn unwrapError(ert: ?*std.builtin.StackTrace, err: anyerror) noreturn {
|
||||
_ = ert;
|
||||
_ = err;
|
||||
call("attempt to unwrap error", null, null);
|
||||
}
|
||||
|
||||
pub fn outOfBounds(index: usize, len: usize) noreturn {
|
||||
_ = index;
|
||||
_ = len;
|
||||
call("index out of bounds", null, null);
|
||||
}
|
||||
|
||||
pub fn startGreaterThanEnd(start: usize, end: usize) noreturn {
|
||||
_ = start;
|
||||
_ = end;
|
||||
call("start index is larger than end index", null, null);
|
||||
}
|
||||
|
||||
pub fn inactiveUnionField(active: anytype, accessed: @TypeOf(active)) noreturn {
|
||||
_ = accessed;
|
||||
call("access of inactive union field", null, null);
|
||||
}
|
||||
|
||||
pub const messages = struct {
|
||||
pub const reached_unreachable = "reached unreachable code";
|
||||
pub const unwrap_null = "attempt to use null value";
|
||||
pub const cast_to_null = "cast causes pointer to be null";
|
||||
pub const incorrect_alignment = "incorrect alignment";
|
||||
pub const invalid_error_code = "invalid error code";
|
||||
pub const cast_truncated_data = "integer cast truncated bits";
|
||||
pub const negative_to_unsigned = "attempt to cast negative value to unsigned integer";
|
||||
pub const integer_overflow = "integer overflow";
|
||||
pub const shl_overflow = "left shift overflowed bits";
|
||||
pub const shr_overflow = "right shift overflowed bits";
|
||||
pub const divide_by_zero = "division by zero";
|
||||
pub const exact_division_remainder = "exact division produced remainder";
|
||||
pub const integer_part_out_of_bounds = "integer part of floating point value out of bounds";
|
||||
pub const corrupt_switch = "switch on corrupt value";
|
||||
pub const shift_rhs_too_big = "shift amount is greater than the type size";
|
||||
pub const invalid_enum_value = "invalid enum value";
|
||||
pub const for_len_mismatch = "for loop over objects with non-equal lengths";
|
||||
pub const memcpy_len_mismatch = "@memcpy arguments have non-equal lengths";
|
||||
pub const memcpy_alias = "@memcpy arguments alias";
|
||||
pub const noreturn_returned = "'noreturn' function returned";
|
||||
|
||||
/// To be deleted after zig1.wasm is updated.
|
||||
pub const inactive_union_field = "access of inactive union field";
|
||||
/// To be deleted after zig1.wasm is updated.
|
||||
pub const sentinel_mismatch = "sentinel mismatch";
|
||||
/// To be deleted after zig1.wasm is updated.
|
||||
pub const unwrap_error = "attempt to unwrap error";
|
||||
/// To be deleted after zig1.wasm is updated.
|
||||
pub const index_out_of_bounds = "index out of bounds";
|
||||
/// To be deleted after zig1.wasm is updated.
|
||||
pub const start_index_greater_than_end = "start index is larger than end index";
|
||||
/// To be deleted after zig1.wasm is updated.
|
||||
pub const unreach = reached_unreachable;
|
||||
};
|
||||
143
src/Sema.zig
143
src/Sema.zig
@ -2566,7 +2566,7 @@ pub fn failWithOwnedErrorMsg(sema: *Sema, block: ?*Block, err_msg: *Zcu.ErrorMsg
|
||||
std.debug.print("compile error during Sema:\n", .{});
|
||||
var error_bundle = wip_errors.toOwnedBundle("") catch @panic("out of memory");
|
||||
error_bundle.renderToStdErr(.{ .ttyconf = .no_color });
|
||||
crash_report.compilerPanic(.{ .explicit_call = "unexpected compile error occurred" }, null, null);
|
||||
crash_report.compilerPanic("unexpected compile error occurred", null, null);
|
||||
}
|
||||
|
||||
if (block) |start_block| {
|
||||
@ -5810,6 +5810,8 @@ fn zirPanic(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void
|
||||
const src = block.nodeOffset(inst_data.src_node);
|
||||
const msg_inst = try sema.resolveInst(inst_data.operand);
|
||||
|
||||
// `panicWithMsg` would perform this coercion for us, but we can get a better
|
||||
// source location if we do it here.
|
||||
const coerced_msg = try sema.coerce(block, Type.slice_const_u8, msg_inst, block.builtinCallArgSrc(inst_data.src_node, 0));
|
||||
|
||||
if (block.is_comptime) {
|
||||
@ -5822,7 +5824,7 @@ fn zirPanic(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void
|
||||
sema.branch_hint = .cold;
|
||||
}
|
||||
|
||||
try callPanic(sema, block, src, .explicit_call, coerced_msg, .@"@panic");
|
||||
try sema.panicWithMsg(block, src, coerced_msg, .@"@panic");
|
||||
}
|
||||
|
||||
fn zirTrap(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {
|
||||
@ -7303,33 +7305,6 @@ fn callBuiltin(
|
||||
);
|
||||
}
|
||||
|
||||
const PanicCauseTag = @typeInfo(std.builtin.PanicCause).@"union".tag_type.?;
|
||||
|
||||
fn callPanic(
|
||||
sema: *Sema,
|
||||
block: *Block,
|
||||
call_src: LazySrcLoc,
|
||||
tag: PanicCauseTag,
|
||||
payload: Air.Inst.Ref,
|
||||
call_operation: CallOperation,
|
||||
) !void {
|
||||
const pt = sema.pt;
|
||||
const zcu = pt.zcu;
|
||||
if (!zcu.backendSupportsFeature(.panic_fn)) {
|
||||
_ = try block.addNoOp(.trap);
|
||||
return;
|
||||
}
|
||||
const panic_cause_ty = try pt.getBuiltinType("PanicCause");
|
||||
const panic_cause = try unionInitFromEnumTag(sema, block, call_src, panic_cause_ty, @intFromEnum(tag), payload);
|
||||
try preparePanic(sema, block, call_src);
|
||||
const panic_fn = Air.internedToRef(zcu.panic_func_index);
|
||||
const err_return_trace = try sema.getErrorReturnTrace(block);
|
||||
const opt_usize_ty = try pt.optionalType(.usize_type);
|
||||
const null_usize = try pt.nullValue(opt_usize_ty);
|
||||
const args: [3]Air.Inst.Ref = .{ panic_cause, err_return_trace, Air.internedToRef(null_usize.toIntern()) };
|
||||
try sema.callBuiltin(block, call_src, panic_fn, .auto, &args, call_operation);
|
||||
}
|
||||
|
||||
const CallOperation = enum {
|
||||
call,
|
||||
@"@call",
|
||||
@ -14233,7 +14208,11 @@ fn maybeErrorUnwrap(
|
||||
.panic => {
|
||||
const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;
|
||||
const msg_inst = try sema.resolveInst(inst_data.operand);
|
||||
try callPanic(sema, block, operand_src, .explicit_call, msg_inst, .@"@panic");
|
||||
|
||||
const panic_fn = try pt.getBuiltinInnerType("Panic", "call");
|
||||
const err_return_trace = try sema.getErrorReturnTrace(block);
|
||||
const args: [3]Air.Inst.Ref = .{ msg_inst, err_return_trace, .null_value };
|
||||
try sema.callBuiltin(block, operand_src, panic_fn, .auto, &args, .@"safety check");
|
||||
return true;
|
||||
},
|
||||
else => unreachable,
|
||||
@ -17380,7 +17359,9 @@ fn analyzeArithmetic(
|
||||
|
||||
if (block.wantSafety() and want_safety and scalar_tag == .int) {
|
||||
if (zcu.backendSupportsFeature(.safety_checked_instructions)) {
|
||||
if (air_tag != air_tag_safe) try sema.preparePanicIntegerOverflow(block, src);
|
||||
if (air_tag != air_tag_safe) {
|
||||
_ = try sema.preparePanicId(block, src, .integer_overflow);
|
||||
}
|
||||
return block.addBinOp(air_tag_safe, casted_lhs, casted_rhs);
|
||||
} else {
|
||||
const maybe_op_ov: ?Air.Inst.Tag = switch (air_tag) {
|
||||
@ -21683,16 +21664,6 @@ fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
|
||||
const operand_src = block.builtinCallArgSrc(inst_data.src_node, 0);
|
||||
const src = block.nodeOffset(inst_data.src_node);
|
||||
const operand = try sema.resolveInst(inst_data.operand);
|
||||
return analyzeTagName(sema, block, src, operand_src, operand);
|
||||
}
|
||||
|
||||
fn analyzeTagName(
|
||||
sema: *Sema,
|
||||
block: *Block,
|
||||
src: LazySrcLoc,
|
||||
operand_src: LazySrcLoc,
|
||||
operand: Air.Inst.Ref,
|
||||
) CompileError!Air.Inst.Ref {
|
||||
const operand_ty = sema.typeOf(operand);
|
||||
const pt = sema.pt;
|
||||
const zcu = pt.zcu;
|
||||
@ -27663,7 +27634,7 @@ fn explainWhyTypeIsNotPacked(
|
||||
}
|
||||
}
|
||||
|
||||
fn preparePanic(sema: *Sema, block: *Block, src: LazySrcLoc) !void {
|
||||
fn prepareSimplePanic(sema: *Sema, block: *Block, src: LazySrcLoc) !void {
|
||||
const pt = sema.pt;
|
||||
const zcu = pt.zcu;
|
||||
|
||||
@ -27694,30 +27665,33 @@ fn preparePanic(sema: *Sema, block: *Block, src: LazySrcLoc) !void {
|
||||
.val = .none,
|
||||
} });
|
||||
}
|
||||
|
||||
if (zcu.panic_cause_type == .none) {
|
||||
const panic_cause_ty = try pt.getBuiltinType("PanicCause");
|
||||
try panic_cause_ty.resolveFields(pt);
|
||||
zcu.panic_cause_type = panic_cause_ty.toIntern();
|
||||
zcu.panic_cause_tag_type = panic_cause_ty.unionTagType(zcu).?.toIntern();
|
||||
}
|
||||
}
|
||||
|
||||
fn preparePanicIntegerOverflow(sema: *Sema, block: *Block, src: LazySrcLoc) !void {
|
||||
/// Backends depend on panic decls being available when lowering safety-checked
|
||||
/// instructions. This function ensures the panic function will be available to
|
||||
/// be called during that time.
|
||||
fn preparePanicId(sema: *Sema, block: *Block, src: LazySrcLoc, panic_id: Zcu.PanicId) !InternPool.Nav.Index {
|
||||
const pt = sema.pt;
|
||||
const zcu = pt.zcu;
|
||||
try preparePanic(sema, block, src);
|
||||
if (zcu.panic_cause_integer_overflow == .none) {
|
||||
const union_val = try pt.unionValue(
|
||||
Type.fromInterned(zcu.panic_cause_type),
|
||||
try pt.enumValueFieldIndex(
|
||||
Type.fromInterned(zcu.panic_cause_tag_type),
|
||||
@intFromEnum(PanicCauseTag.integer_overflow),
|
||||
),
|
||||
Value.void,
|
||||
);
|
||||
zcu.panic_cause_integer_overflow = try pt.refValue(union_val.toIntern());
|
||||
}
|
||||
const gpa = sema.gpa;
|
||||
if (zcu.panic_messages[@intFromEnum(panic_id)].unwrap()) |x| return x;
|
||||
|
||||
try sema.prepareSimplePanic(block, src);
|
||||
|
||||
const panic_messages_ty = try pt.getBuiltinType("panic_messages");
|
||||
const msg_nav_index = (sema.namespaceLookup(
|
||||
block,
|
||||
LazySrcLoc.unneeded,
|
||||
panic_messages_ty.getNamespaceIndex(zcu),
|
||||
try zcu.intern_pool.getOrPutString(gpa, pt.tid, @tagName(panic_id), .no_embedded_nulls),
|
||||
) catch |err| switch (err) {
|
||||
error.AnalysisFail => @panic("std.builtin.panic_messages is corrupt"),
|
||||
error.GenericPoison, error.ComptimeReturn, error.ComptimeBreak => unreachable,
|
||||
error.OutOfMemory => |e| return e,
|
||||
}).?;
|
||||
try sema.ensureNavResolved(src, msg_nav_index);
|
||||
zcu.panic_messages[@intFromEnum(panic_id)] = msg_nav_index.toOptional();
|
||||
return msg_nav_index;
|
||||
}
|
||||
|
||||
fn addSafetyCheck(
|
||||
@ -27725,7 +27699,7 @@ fn addSafetyCheck(
|
||||
parent_block: *Block,
|
||||
src: LazySrcLoc,
|
||||
ok: Air.Inst.Ref,
|
||||
panic_cause_tag: PanicCauseTag,
|
||||
panic_id: Zcu.PanicId,
|
||||
) !void {
|
||||
const gpa = sema.gpa;
|
||||
assert(!parent_block.is_comptime);
|
||||
@ -27743,7 +27717,7 @@ fn addSafetyCheck(
|
||||
|
||||
defer fail_block.instructions.deinit(gpa);
|
||||
|
||||
try sema.safetyPanic(&fail_block, src, panic_cause_tag);
|
||||
try sema.safetyPanic(&fail_block, src, panic_id);
|
||||
try sema.addSafetyCheckExtra(parent_block, ok, &fail_block);
|
||||
}
|
||||
|
||||
@ -27812,6 +27786,29 @@ fn addSafetyCheckExtra(
|
||||
parent_block.instructions.appendAssumeCapacity(block_inst);
|
||||
}
|
||||
|
||||
fn panicWithMsg(sema: *Sema, block: *Block, src: LazySrcLoc, msg_inst: Air.Inst.Ref, operation: CallOperation) !void {
|
||||
const pt = sema.pt;
|
||||
const zcu = pt.zcu;
|
||||
|
||||
if (!zcu.backendSupportsFeature(.panic_fn)) {
|
||||
_ = try block.addNoOp(.trap);
|
||||
return;
|
||||
}
|
||||
|
||||
try sema.prepareSimplePanic(block, src);
|
||||
|
||||
const panic_func = zcu.funcInfo(zcu.panic_func_index);
|
||||
const panic_fn = try sema.analyzeNavVal(block, src, panic_func.owner_nav);
|
||||
const null_stack_trace = Air.internedToRef(zcu.null_stack_trace);
|
||||
|
||||
const opt_usize_ty = try pt.optionalType(.usize_type);
|
||||
const null_ret_addr = Air.internedToRef((try pt.intern(.{ .opt = .{
|
||||
.ty = opt_usize_ty.toIntern(),
|
||||
.val = .none,
|
||||
} })));
|
||||
try sema.callBuiltin(block, src, panic_fn, .auto, &.{ msg_inst, null_stack_trace, null_ret_addr }, operation);
|
||||
}
|
||||
|
||||
fn addSafetyCheckUnwrapError(
|
||||
sema: *Sema,
|
||||
parent_block: *Block,
|
||||
@ -27849,7 +27846,7 @@ fn safetyPanicUnwrapError(sema: *Sema, block: *Block, src: LazySrcLoc, err: Air.
|
||||
if (!zcu.backendSupportsFeature(.panic_fn)) {
|
||||
_ = try block.addNoOp(.trap);
|
||||
} else {
|
||||
const panic_fn = try pt.getBuiltin("panicUnwrapError");
|
||||
const panic_fn = try pt.getBuiltinInnerType("Panic", "unwrapError");
|
||||
const err_return_trace = try sema.getErrorReturnTrace(block);
|
||||
const args: [2]Air.Inst.Ref = .{ err_return_trace, err };
|
||||
try sema.callBuiltin(block, src, panic_fn, .auto, &args, .@"safety check");
|
||||
@ -27866,7 +27863,7 @@ fn addSafetyCheckIndexOob(
|
||||
) !void {
|
||||
assert(!parent_block.is_comptime);
|
||||
const ok = try parent_block.addBinOp(cmp_op, index, len);
|
||||
return addSafetyCheckCall(sema, parent_block, src, ok, "panicOutOfBounds", &.{ index, len });
|
||||
return addSafetyCheckCall(sema, parent_block, src, ok, "outOfBounds", &.{ index, len });
|
||||
}
|
||||
|
||||
fn addSafetyCheckInactiveUnionField(
|
||||
@ -27878,7 +27875,7 @@ fn addSafetyCheckInactiveUnionField(
|
||||
) !void {
|
||||
assert(!parent_block.is_comptime);
|
||||
const ok = try parent_block.addBinOp(.cmp_eq, active_tag, wanted_tag);
|
||||
return addSafetyCheckCall(sema, parent_block, src, ok, "panicInactiveUnionField", &.{ active_tag, wanted_tag });
|
||||
return addSafetyCheckCall(sema, parent_block, src, ok, "inactiveUnionField", &.{ active_tag, wanted_tag });
|
||||
}
|
||||
|
||||
fn addSafetyCheckSentinelMismatch(
|
||||
@ -27919,7 +27916,7 @@ fn addSafetyCheckSentinelMismatch(
|
||||
break :ok try parent_block.addBinOp(.cmp_eq, expected_sentinel, actual_sentinel);
|
||||
};
|
||||
|
||||
return addSafetyCheckCall(sema, parent_block, src, ok, "panicSentinelMismatch", &.{
|
||||
return addSafetyCheckCall(sema, parent_block, src, ok, "sentinelMismatch", &.{
|
||||
expected_sentinel, actual_sentinel,
|
||||
});
|
||||
}
|
||||
@ -27953,7 +27950,7 @@ fn addSafetyCheckCall(
|
||||
if (!zcu.backendSupportsFeature(.panic_fn)) {
|
||||
_ = try fail_block.addNoOp(.trap);
|
||||
} else {
|
||||
const panic_fn = try pt.getBuiltin(func_name);
|
||||
const panic_fn = try pt.getBuiltinInnerType("Panic", func_name);
|
||||
try sema.callBuiltin(&fail_block, src, panic_fn, .auto, args, .@"safety check");
|
||||
}
|
||||
|
||||
@ -27961,8 +27958,10 @@ fn addSafetyCheckCall(
|
||||
}
|
||||
|
||||
/// This does not set `sema.branch_hint`.
|
||||
fn safetyPanic(sema: *Sema, block: *Block, src: LazySrcLoc, panic_cause_tag: PanicCauseTag) CompileError!void {
|
||||
try callPanic(sema, block, src, panic_cause_tag, .void_value, .@"safety check");
|
||||
fn safetyPanic(sema: *Sema, block: *Block, src: LazySrcLoc, panic_id: Zcu.PanicId) CompileError!void {
|
||||
const msg_nav_index = try sema.preparePanicId(block, src, panic_id);
|
||||
const msg_inst = try sema.analyzeNavVal(block, src, msg_nav_index);
|
||||
try sema.panicWithMsg(block, src, msg_inst, .@"safety check");
|
||||
}
|
||||
|
||||
fn emitBackwardBranch(sema: *Sema, block: *Block, src: LazySrcLoc) !void {
|
||||
@ -33456,7 +33455,7 @@ fn analyzeSlice(
|
||||
assert(!block.is_comptime);
|
||||
try sema.requireRuntimeBlock(block, src, runtime_src.?);
|
||||
const ok = try block.addBinOp(.cmp_lte, start, end);
|
||||
try sema.addSafetyCheckCall(block, src, ok, "panicStartGreaterThanEnd", &.{ start, end });
|
||||
try sema.addSafetyCheckCall(block, src, ok, "startGreaterThanEnd", &.{ start, end });
|
||||
}
|
||||
const new_len = if (by_length)
|
||||
try sema.coerce(block, Type.usize, uncasted_end_opt, end_src)
|
||||
|
||||
29
src/Zcu.zig
29
src/Zcu.zig
@ -210,17 +210,40 @@ all_type_references: std.ArrayListUnmanaged(TypeReference) = .empty,
|
||||
/// Freelist of indices in `all_type_references`.
|
||||
free_type_references: std.ArrayListUnmanaged(u32) = .empty,
|
||||
|
||||
panic_messages: [PanicId.len]InternPool.Nav.Index.Optional = .{.none} ** PanicId.len,
|
||||
/// The panic function body.
|
||||
panic_func_index: InternPool.Index = .none,
|
||||
null_stack_trace: InternPool.Index = .none,
|
||||
panic_cause_type: InternPool.Index = .none,
|
||||
panic_cause_tag_type: InternPool.Index = .none,
|
||||
panic_cause_integer_overflow: InternPool.Index = .none,
|
||||
|
||||
generation: u32 = 0,
|
||||
|
||||
pub const PerThread = @import("Zcu/PerThread.zig");
|
||||
|
||||
pub const PanicId = enum {
|
||||
reached_unreachable,
|
||||
unwrap_null,
|
||||
cast_to_null,
|
||||
incorrect_alignment,
|
||||
invalid_error_code,
|
||||
cast_truncated_data,
|
||||
negative_to_unsigned,
|
||||
integer_overflow,
|
||||
shl_overflow,
|
||||
shr_overflow,
|
||||
divide_by_zero,
|
||||
exact_division_remainder,
|
||||
integer_part_out_of_bounds,
|
||||
corrupt_switch,
|
||||
shift_rhs_too_big,
|
||||
invalid_enum_value,
|
||||
for_len_mismatch,
|
||||
memcpy_len_mismatch,
|
||||
memcpy_alias,
|
||||
noreturn_returned,
|
||||
|
||||
pub const len = @typeInfo(PanicId).@"enum".fields.len;
|
||||
};
|
||||
|
||||
pub const GlobalErrorSet = std.AutoArrayHashMapUnmanaged(InternPool.NullTerminatedString, void);
|
||||
|
||||
pub const CImportError = struct {
|
||||
|
||||
@ -152,16 +152,12 @@ fn writeFilePath(file: *Zcu.File, writer: anytype) !void {
|
||||
try writer.writeAll(file.sub_file_path);
|
||||
}
|
||||
|
||||
pub fn compilerPanic(
|
||||
cause: std.builtin.PanicCause,
|
||||
error_return_trace: ?*std.builtin.StackTrace,
|
||||
maybe_ret_addr: ?usize,
|
||||
) noreturn {
|
||||
pub fn compilerPanic(msg: []const u8, error_return_trace: ?*std.builtin.StackTrace, maybe_ret_addr: ?usize) noreturn {
|
||||
@branchHint(.cold);
|
||||
PanicSwitch.preDispatch();
|
||||
const ret_addr = maybe_ret_addr orelse @returnAddress();
|
||||
const stack_ctx: StackContext = .{ .current = .{ .ret_addr = ret_addr } };
|
||||
PanicSwitch.dispatch(error_return_trace, stack_ctx, cause);
|
||||
PanicSwitch.dispatch(error_return_trace, stack_ctx, msg);
|
||||
}
|
||||
|
||||
/// Attaches a global SIGSEGV handler
|
||||
@ -212,7 +208,7 @@ fn handleSegfaultPosix(sig: i32, info: *const posix.siginfo_t, ctx_ptr: ?*anyopa
|
||||
else => .not_supported,
|
||||
};
|
||||
|
||||
PanicSwitch.dispatch(null, stack_ctx, .{ .explicit_call = error_msg });
|
||||
PanicSwitch.dispatch(null, stack_ctx, error_msg);
|
||||
}
|
||||
|
||||
const WindowsSegfaultMessage = union(enum) {
|
||||
@ -335,7 +331,7 @@ const PanicSwitch = struct {
|
||||
// it's happening and print a message.
|
||||
var panic_state: *volatile PanicState = &panic_state_raw;
|
||||
if (panic_state.awaiting_dispatch) {
|
||||
dispatch(null, .{ .current = .{ .ret_addr = null } }, .{ .explicit_call = "Panic while preparing callstack" });
|
||||
dispatch(null, .{ .current = .{ .ret_addr = null } }, "Panic while preparing callstack");
|
||||
}
|
||||
panic_state.awaiting_dispatch = true;
|
||||
}
|
||||
@ -355,17 +351,17 @@ const PanicSwitch = struct {
|
||||
pub fn dispatch(
|
||||
trace: ?*const std.builtin.StackTrace,
|
||||
stack_ctx: StackContext,
|
||||
panic_cause: std.builtin.PanicCause,
|
||||
msg: []const u8,
|
||||
) noreturn {
|
||||
var panic_state: *volatile PanicState = &panic_state_raw;
|
||||
debug.assert(panic_state.awaiting_dispatch);
|
||||
panic_state.awaiting_dispatch = false;
|
||||
nosuspend switch (panic_state.recover_stage) {
|
||||
.initialize => goTo(initPanic, .{ panic_state, trace, stack_ctx, panic_cause }),
|
||||
.report_stack => goTo(recoverReportStack, .{ panic_state, trace, stack_ctx, panic_cause }),
|
||||
.release_mutex => goTo(recoverReleaseMutex, .{ panic_state, trace, stack_ctx, panic_cause }),
|
||||
.release_ref_count => goTo(recoverReleaseRefCount, .{ panic_state, trace, stack_ctx, panic_cause }),
|
||||
.abort => goTo(recoverAbort, .{ panic_state, trace, stack_ctx, panic_cause }),
|
||||
.initialize => goTo(initPanic, .{ panic_state, trace, stack_ctx, msg }),
|
||||
.report_stack => goTo(recoverReportStack, .{ panic_state, trace, stack_ctx, msg }),
|
||||
.release_mutex => goTo(recoverReleaseMutex, .{ panic_state, trace, stack_ctx, msg }),
|
||||
.release_ref_count => goTo(recoverReleaseRefCount, .{ panic_state, trace, stack_ctx, msg }),
|
||||
.abort => goTo(recoverAbort, .{ panic_state, trace, stack_ctx, msg }),
|
||||
.silent_abort => goTo(abort, .{}),
|
||||
};
|
||||
}
|
||||
@ -374,7 +370,7 @@ const PanicSwitch = struct {
|
||||
state: *volatile PanicState,
|
||||
trace: ?*const std.builtin.StackTrace,
|
||||
stack: StackContext,
|
||||
panic_cause: std.builtin.PanicCause,
|
||||
msg: []const u8,
|
||||
) noreturn {
|
||||
// use a temporary so there's only one volatile store
|
||||
const new_state = PanicState{
|
||||
@ -399,8 +395,6 @@ const PanicSwitch = struct {
|
||||
const current_thread_id = std.Thread.getCurrentId();
|
||||
stderr.print("thread {} panic: ", .{current_thread_id}) catch goTo(releaseMutex, .{state});
|
||||
}
|
||||
var buffer: [1000]u8 = undefined;
|
||||
const msg = buffer[0..std.debug.fmtPanicCause(&buffer, panic_cause)];
|
||||
stderr.print("{s}\n", .{msg}) catch goTo(releaseMutex, .{state});
|
||||
|
||||
state.recover_stage = .report_stack;
|
||||
@ -416,9 +410,9 @@ const PanicSwitch = struct {
|
||||
state: *volatile PanicState,
|
||||
trace: ?*const std.builtin.StackTrace,
|
||||
stack: StackContext,
|
||||
panic_cause: std.builtin.PanicCause,
|
||||
msg: []const u8,
|
||||
) noreturn {
|
||||
recover(state, trace, stack, panic_cause);
|
||||
recover(state, trace, stack, msg);
|
||||
|
||||
state.recover_stage = .release_mutex;
|
||||
const stderr = io.getStdErr().writer();
|
||||
@ -441,9 +435,9 @@ const PanicSwitch = struct {
|
||||
state: *volatile PanicState,
|
||||
trace: ?*const std.builtin.StackTrace,
|
||||
stack: StackContext,
|
||||
panic_cause: std.builtin.PanicCause,
|
||||
msg: []const u8,
|
||||
) noreturn {
|
||||
recover(state, trace, stack, panic_cause);
|
||||
recover(state, trace, stack, msg);
|
||||
goTo(releaseMutex, .{state});
|
||||
}
|
||||
|
||||
@ -459,9 +453,9 @@ const PanicSwitch = struct {
|
||||
state: *volatile PanicState,
|
||||
trace: ?*const std.builtin.StackTrace,
|
||||
stack: StackContext,
|
||||
panic_cause: std.builtin.PanicCause,
|
||||
msg: []const u8,
|
||||
) noreturn {
|
||||
recover(state, trace, stack, panic_cause);
|
||||
recover(state, trace, stack, msg);
|
||||
goTo(releaseRefCount, .{state});
|
||||
}
|
||||
|
||||
@ -487,9 +481,9 @@ const PanicSwitch = struct {
|
||||
state: *volatile PanicState,
|
||||
trace: ?*const std.builtin.StackTrace,
|
||||
stack: StackContext,
|
||||
panic_cause: std.builtin.PanicCause,
|
||||
msg: []const u8,
|
||||
) noreturn {
|
||||
recover(state, trace, stack, panic_cause);
|
||||
recover(state, trace, stack, msg);
|
||||
|
||||
state.recover_stage = .silent_abort;
|
||||
const stderr = io.getStdErr().writer();
|
||||
@ -513,9 +507,8 @@ const PanicSwitch = struct {
|
||||
state: *volatile PanicState,
|
||||
trace: ?*const std.builtin.StackTrace,
|
||||
stack: StackContext,
|
||||
panic_cause: std.builtin.PanicCause,
|
||||
msg: []const u8,
|
||||
) void {
|
||||
var buffer: [1000]u8 = undefined;
|
||||
switch (state.recover_verbosity) {
|
||||
.message_and_stack => {
|
||||
// lower the verbosity, and restore it at the end if we don't panic.
|
||||
@ -523,7 +516,6 @@ const PanicSwitch = struct {
|
||||
|
||||
const stderr = io.getStdErr().writer();
|
||||
stderr.writeAll("\nPanicked during a panic: ") catch {};
|
||||
const msg = buffer[0..std.debug.fmtPanicCause(&buffer, panic_cause)];
|
||||
stderr.writeAll(msg) catch {};
|
||||
stderr.writeAll("\nInner panic stack:\n") catch {};
|
||||
if (trace) |t| {
|
||||
@ -538,7 +530,6 @@ const PanicSwitch = struct {
|
||||
|
||||
const stderr = io.getStdErr().writer();
|
||||
stderr.writeAll("\nPanicked while dumping inner panic stack: ") catch {};
|
||||
const msg = buffer[0..std.debug.fmtPanicCause(&buffer, panic_cause)];
|
||||
stderr.writeAll(msg) catch {};
|
||||
stderr.writeAll("\n") catch {};
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user