authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-02-23 20:25:07-08:00
committergravatar for david@vortan.devDavid Rubin <david@vortan.dev> 2025-02-25 11:22:33-08:00
logd4413e3504cf7b260a2fd29546ab29d6fd3de079
tree658514da412420f6ee8e523681c88dc6ad7ea801
parent44d3b5a6e47c0caa3b5b3fe998ad52ef1d83e032

ubsan: avoid depending on `@returnAddress` combined with `inline`


1 files changed, 48 insertions(+), 33 deletions(-)

lib/ubsan_rt.zig+48-33
......@@ -1,6 +1,7 @@
11const std = @import("std");
22const builtin = @import("builtin");
33const assert = std.debug.assert;
4const panic = std.debug.panicExtra;
45
56const SourceLocation = extern struct {
67 file_name: ?[*:0]const u8,
......@@ -175,7 +176,7 @@ fn overflowHandler(
175176 const fmt = "{s} integer overflow: " ++ "{} " ++
176177 operator ++ " {} cannot be represented in type {s}";
177178
178 logMessage(fmt, .{
179 panic(@returnAddress(), fmt, .{
179180 if (is_signed) "signed" else "unsigned",
180181 lhs,
181182 rhs,
......@@ -199,7 +200,8 @@ fn negationHandler(
199200 value_handle: ValueHandle,
200201) callconv(.c) noreturn {
201202 const value: Value = .{ .handle = value_handle, .td = data.td };
202 logMessage(
203 panic(
204 @returnAddress(),
203205 "negation of {} cannot be represented in type {s}",
204206 .{ value, data.td.getName() },
205207 );
......@@ -222,11 +224,12 @@ fn divRemHandler(
222224 const rhs: Value = .{ .handle = rhs_handle, .td = data.td };
223225
224226 if (rhs.isMinusOne()) {
225 logMessage(
227 panic(
228 @returnAddress(),
226229 "division of {} by -1 cannot be represented in type {s}",
227230 .{ lhs, data.td.getName() },
228231 );
229 } else logMessage("division by zero", .{});
232 } else panic(@returnAddress(), "division by zero", .{});
230233}
231234
232235const AlignmentAssumptionData = extern struct {
......@@ -263,7 +266,8 @@ fn alignmentAssumptionHandler(
263266 const alignment: Value = .{ .handle = alignment_handle, .td = data.td };
264267
265268 if (maybe_offset) |offset| {
266 logMessage(
269 panic(
270 @returnAddress(),
267271 "assumption of {} byte alignment (with offset of {} byte) for pointer of type {s} failed\n" ++
268272 "offset address is {} aligned, misalignment offset is {} bytes",
269273 .{
......@@ -275,7 +279,8 @@ fn alignmentAssumptionHandler(
275279 },
276280 );
277281 } else {
278 logMessage(
282 panic(
283 @returnAddress(),
279284 "assumption of {} byte alignment for pointer of type {s} failed\n" ++
280285 "address is {} aligned, misalignment offset is {} bytes",
281286 .{
......@@ -314,18 +319,20 @@ fn shiftOob(
314319 rhs.getPositiveInteger() >= data.lhs_type.getIntegerSize())
315320 {
316321 if (rhs.isNegative()) {
317 logMessage("shift exponent {} is negative", .{rhs});
322 panic(@returnAddress(), "shift exponent {} is negative", .{rhs});
318323 } else {
319 logMessage(
324 panic(
325 @returnAddress(),
320326 "shift exponent {} is too large for {}-bit type {s}",
321327 .{ rhs, data.lhs_type.getIntegerSize(), data.lhs_type.getName() },
322328 );
323329 }
324330 } else {
325331 if (lhs.isNegative()) {
326 logMessage("left shift of negative value {}", .{lhs});
332 panic(@returnAddress(), "left shift of negative value {}", .{lhs});
327333 } else {
328 logMessage(
334 panic(
335 @returnAddress(),
329336 "left shift of {} by {} places cannot be represented in type {s}",
330337 .{ lhs, rhs, data.lhs_type.getName() },
331338 );
......@@ -351,7 +358,8 @@ fn outOfBounds(
351358 index_handle: ValueHandle,
352359) callconv(.c) noreturn {
353360 const index: Value = .{ .handle = index_handle, .td = data.index_type };
354 logMessage(
361 panic(
362 @returnAddress(),
355363 "index {} out of bounds for type {s}",
356364 .{ index, data.array_type.getName() },
357365 );
......@@ -376,13 +384,14 @@ fn pointerOverflow(
376384) callconv(.c) noreturn {
377385 if (base == 0) {
378386 if (result == 0) {
379 logMessage("applying zero offset to null pointer", .{});
387 panic(@returnAddress(), "applying zero offset to null pointer", .{});
380388 } else {
381 logMessage("applying non-zero offset {} to null pointer", .{result});
389 panic(@returnAddress(), "applying non-zero offset {} to null pointer", .{result});
382390 }
383391 } else {
384392 if (result == 0) {
385 logMessage(
393 panic(
394 @returnAddress(),
386395 "applying non-zero offset to non-null pointer 0x{x} produced null pointer",
387396 .{base},
388397 );
......@@ -391,18 +400,21 @@ fn pointerOverflow(
391400 const signed_result: isize = @bitCast(result);
392401 if ((signed_base >= 0) == (signed_result >= 0)) {
393402 if (base > result) {
394 logMessage(
403 panic(
404 @returnAddress(),
395405 "addition of unsigned offset to 0x{x} overflowed to 0x{x}",
396406 .{ base, result },
397407 );
398408 } else {
399 logMessage(
409 panic(
410 @returnAddress(),
400411 "subtraction of unsigned offset to 0x{x} overflowed to 0x{x}",
401412 .{ base, result },
402413 );
403414 }
404415 } else {
405 logMessage(
416 panic(
417 @returnAddress(),
406418 "pointer index expression with base 0x{x} overflowed to 0x{x}",
407419 .{ base, result },
408420 );
......@@ -462,17 +474,20 @@ fn typeMismatch(
462474 const handle: usize = @intFromPtr(pointer);
463475
464476 if (pointer == null) {
465 logMessage(
477 panic(
478 @returnAddress(),
466479 "{s} null pointer of type {s}",
467480 .{ data.kind.getName(), data.td.getName() },
468481 );
469482 } else if (!std.mem.isAligned(handle, alignment)) {
470 logMessage(
483 panic(
484 @returnAddress(),
471485 "{s} misaligned address 0x{x} for type {s}, which requires {} byte alignment",
472486 .{ data.kind.getName(), handle, data.td.getName(), alignment },
473487 );
474488 } else {
475 logMessage(
489 panic(
490 @returnAddress(),
476491 "{s} address 0x{x} with insufficient space for an object of type {s}",
477492 .{ data.kind.getName(), handle, data.td.getName() },
478493 );
......@@ -484,11 +499,11 @@ const UnreachableData = extern struct {
484499};
485500
486501fn builtinUnreachable(_: *const UnreachableData) callconv(.c) noreturn {
487 logMessage("execution reached an unreachable program point", .{});
502 panic(@returnAddress(), "execution reached an unreachable program point", .{});
488503}
489504
490505fn missingReturn(_: *const UnreachableData) callconv(.c) noreturn {
491 logMessage("execution reached the end of a value-returning function without returning a value", .{});
506 panic(@returnAddress(), "execution reached the end of a value-returning function without returning a value", .{});
492507}
493508
494509const NonNullReturnData = extern struct {
......@@ -499,7 +514,7 @@ fn nonNullReturnAbort(data: *const NonNullReturnData) callconv(.c) noreturn {
499514 nonNullReturn(data);
500515}
501516fn nonNullReturn(_: *const NonNullReturnData) callconv(.c) noreturn {
502 logMessage("null pointer returned from function declared to never return null", .{});
517 panic(@returnAddress(), "null pointer returned from function declared to never return null", .{});
503518}
504519
505520const NonNullArgData = extern struct {
......@@ -513,7 +528,8 @@ fn nonNullArgAbort(data: *const NonNullArgData) callconv(.c) noreturn {
513528}
514529
515530fn nonNullArg(data: *const NonNullArgData) callconv(.c) noreturn {
516 logMessage(
531 panic(
532 @returnAddress(),
517533 "null pointer passed as argument {}, which is declared to never be null",
518534 .{data.arg_index},
519535 );
......@@ -536,7 +552,8 @@ fn loadInvalidValue(
536552 value_handle: ValueHandle,
537553) callconv(.c) noreturn {
538554 const value: Value = .{ .handle = value_handle, .td = data.td };
539 logMessage(
555 panic(
556 @returnAddress(),
540557 "load of value {}, which is not valid for type {s}",
541558 .{ value, data.td.getName() },
542559 );
......@@ -554,7 +571,8 @@ fn invalidBuiltinAbort(data: *const InvalidBuiltinData) callconv(.c) noreturn {
554571}
555572
556573fn invalidBuiltin(data: *const InvalidBuiltinData) callconv(.c) noreturn {
557 logMessage(
574 panic(
575 @returnAddress(),
558576 "passing zero to {s}(), which is not a valid argument",
559577 .{@tagName(data.kind)},
560578 );
......@@ -577,7 +595,8 @@ fn vlaBoundNotPositive(
577595 bound_handle: ValueHandle,
578596) callconv(.c) noreturn {
579597 const bound: Value = .{ .handle = bound_handle, .td = data.td };
580 logMessage(
598 panic(
599 @returnAddress(),
581600 "variable length array bound evaluates to non-positive value {}",
582601 .{bound},
583602 );
......@@ -611,22 +630,18 @@ fn floatCastOverflow(
611630 if (@as(u16, ptr[0]) + @as(u16, ptr[1]) < 2 or ptr[0] == 0xFF or ptr[1] == 0xFF) {
612631 const data: *const FloatCastOverflowData = @ptrCast(data_handle);
613632 const from_value: Value = .{ .handle = from_handle, .td = data.from };
614 logMessage("{} is outside the range of representable values of type {s}", .{
633 panic(@returnAddress(), "{} is outside the range of representable values of type {s}", .{
615634 from_value, data.to.getName(),
616635 });
617636 } else {
618637 const data: *const FloatCastOverflowDataV2 = @ptrCast(data_handle);
619638 const from_value: Value = .{ .handle = from_handle, .td = data.from };
620 logMessage("{} is outside the range of representable values of type {s}", .{
639 panic(@returnAddress(), "{} is outside the range of representable values of type {s}", .{
621640 from_value, data.to.getName(),
622641 });
623642 }
624643}
625644
626inline fn logMessage(comptime fmt: []const u8, args: anytype) noreturn {
627 std.debug.panicExtra(@returnAddress(), fmt, args);
628}
629
630645fn exportHandler(
631646 handler: anytype,
632647 comptime sym_name: []const u8,