aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorYusuf Bham <ybham6@gmail.com>2024-02-16 14:08:23 -0500
committerVeikka Tuominen <git@vexu.eu>2024-07-22 16:23:10 +0300
commit22d964fe22f2e154640f71ef52c1ed552be518bd (patch)
tree76b6ec9b97c5bc5a72fa8a247e94d57ad713f169 /lib
parentc16aeda8a66451e77c0113b5d160413f97fc72b0 (diff)
downloadzig-22d964fe22f2e154640f71ef52c1ed552be518bd.tar.gz
zig-22d964fe22f2e154640f71ef52c1ed552be518bd.zip
std.builtin.panic(uefi): stack allocate panic message
In the case that the allocator is unavailable (OOM, etc.), we can possibly still output the panic message - so now we stack allocate the message and copy it to the exit data for passing to boot services.
Diffstat (limited to 'lib')
-rw-r--r--lib/std/builtin.zig47
1 files changed, 28 insertions, 19 deletions
diff --git a/lib/std/builtin.zig b/lib/std/builtin.zig
index 5591343c3a..0ef5cffd24 100644
--- a/lib/std/builtin.zig
+++ b/lib/std/builtin.zig
@@ -799,44 +799,53 @@ pub fn default_panic(msg: []const u8, error_return_trace: ?*StackTrace, ret_addr
.uefi => {
const uefi = std.os.uefi;
+ const Formatter = struct {
+ pub fn fmt(exit_msg: []const u8, out: []u16) ![:0]u16 {
+ var u8_buf: [256]u8 = undefined;
+ const slice = try std.fmt.bufPrint(&u8_buf, "err: {s}\r\n", .{exit_msg});
+ // We pass len - 1 because we need to add a null terminator after
+ const len = try std.unicode.utf8ToUtf16Le(out[0 .. out.len - 1], slice);
+
+ out[len] = 0;
+
+ return out[0..len :0];
+ }
+ };
+
const ExitData = struct {
- pub fn create_exit_data(exit_msg: []const u8, exit_size: *usize) ![*:0]u16 {
+ pub fn create_exit_data(exit_msg: [:0]u16, exit_size: *usize) ![*:0]u16 {
// Need boot services for pool allocation
if (uefi.system_table.boot_services == null) {
return error.BootServicesUnavailable;
}
- // ExitData buffer must be allocated using boot_services.allocatePool
- var utf16: []u16 = try uefi.raw_pool_allocator.alloc(u16, 256);
- errdefer uefi.raw_pool_allocator.free(utf16);
+ // ExitData buffer must be allocated using boot_services.allocatePool (spec: page 220)
+ const exit_data: []u16 = try uefi.raw_pool_allocator.alloc(u16, exit_msg.len + 1);
- if (exit_msg.len > 255) {
- return error.MessageTooLong;
- }
-
- var fmt: [256]u8 = undefined;
- const slice = try std.fmt.bufPrint(&fmt, "\r\nerr: {s}\r\n", .{exit_msg});
- const len = try std.unicode.utf8ToUtf16Le(utf16, slice);
-
- utf16[len] = 0;
+ @memcpy(exit_data[0 .. exit_msg.len + 1], exit_msg[0 .. exit_msg.len + 1]);
+ exit_size.* = exit_msg.len + 1;
- exit_size.* = 256;
-
- return @as([*:0]u16, @ptrCast(utf16.ptr));
+ return @as([*:0]u16, @ptrCast(exit_data.ptr));
}
};
+ var buf: [256]u16 = undefined;
+ const utf16 = Formatter.fmt(msg, &buf) catch null;
+
var exit_size: usize = 0;
- const exit_data = ExitData.create_exit_data(msg, &exit_size) catch null;
+ const exit_data = if (utf16) |u|
+ ExitData.create_exit_data(u, &exit_size) catch null
+ else
+ null;
- if (exit_data) |data| {
+ if (utf16) |str| {
// Output to both std_err and con_out, as std_err is easier
// to read in stuff like QEMU at times, but, unlike con_out,
// isn't visible on actual hardware if directly booted into
inline for ([_]?*uefi.protocol.SimpleTextOutput{ uefi.system_table.std_err, uefi.system_table.con_out }) |o| {
if (o) |out| {
_ = out.setAttribute(uefi.protocol.SimpleTextOutput.red);
- _ = out.outputString(data);
+ _ = out.outputString(str);
_ = out.setAttribute(uefi.protocol.SimpleTextOutput.white);
}
}