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 @@...@@ -1,6 +1,7 @@
1const std = @import("std");1const std = @import("std");
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const assert = std.debug.assert;3const assert = std.debug.assert;
4const panic = std.debug.panicExtra;
45
5const SourceLocation = extern struct {6const SourceLocation = extern struct {
6 file_name: ?[*:0]const u8,7 file_name: ?[*:0]const u8,
...@@ -175,7 +176,7 @@ fn overflowHandler(...@@ -175,7 +176,7 @@ fn overflowHandler(
175 const fmt = "{s} integer overflow: " ++ "{} " ++176 const fmt = "{s} integer overflow: " ++ "{} " ++
176 operator ++ " {} cannot be represented in type {s}";177 operator ++ " {} cannot be represented in type {s}";
177178
178 logMessage(fmt, .{179 panic(@returnAddress(), fmt, .{
179 if (is_signed) "signed" else "unsigned",180 if (is_signed) "signed" else "unsigned",
180 lhs,181 lhs,
181 rhs,182 rhs,
...@@ -199,7 +200,8 @@ fn negationHandler(...@@ -199,7 +200,8 @@ fn negationHandler(
199 value_handle: ValueHandle,200 value_handle: ValueHandle,
200) callconv(.c) noreturn {201) callconv(.c) noreturn {
201 const value: Value = .{ .handle = value_handle, .td = data.td };202 const value: Value = .{ .handle = value_handle, .td = data.td };
202 logMessage(203 panic(
204 @returnAddress(),
203 "negation of {} cannot be represented in type {s}",205 "negation of {} cannot be represented in type {s}",
204 .{ value, data.td.getName() },206 .{ value, data.td.getName() },
205 );207 );
...@@ -222,11 +224,12 @@ fn divRemHandler(...@@ -222,11 +224,12 @@ fn divRemHandler(
222 const rhs: Value = .{ .handle = rhs_handle, .td = data.td };224 const rhs: Value = .{ .handle = rhs_handle, .td = data.td };
223225
224 if (rhs.isMinusOne()) {226 if (rhs.isMinusOne()) {
225 logMessage(227 panic(
228 @returnAddress(),
226 "division of {} by -1 cannot be represented in type {s}",229 "division of {} by -1 cannot be represented in type {s}",
227 .{ lhs, data.td.getName() },230 .{ lhs, data.td.getName() },
228 );231 );
229 } else logMessage("division by zero", .{});232 } else panic(@returnAddress(), "division by zero", .{});
230}233}
231234
232const AlignmentAssumptionData = extern struct {235const AlignmentAssumptionData = extern struct {
...@@ -263,7 +266,8 @@ fn alignmentAssumptionHandler(...@@ -263,7 +266,8 @@ fn alignmentAssumptionHandler(
263 const alignment: Value = .{ .handle = alignment_handle, .td = data.td };266 const alignment: Value = .{ .handle = alignment_handle, .td = data.td };
264267
265 if (maybe_offset) |offset| {268 if (maybe_offset) |offset| {
266 logMessage(269 panic(
270 @returnAddress(),
267 "assumption of {} byte alignment (with offset of {} byte) for pointer of type {s} failed\n" ++271 "assumption of {} byte alignment (with offset of {} byte) for pointer of type {s} failed\n" ++
268 "offset address is {} aligned, misalignment offset is {} bytes",272 "offset address is {} aligned, misalignment offset is {} bytes",
269 .{273 .{
...@@ -275,7 +279,8 @@ fn alignmentAssumptionHandler(...@@ -275,7 +279,8 @@ fn alignmentAssumptionHandler(
275 },279 },
276 );280 );
277 } else {281 } else {
278 logMessage(282 panic(
283 @returnAddress(),
279 "assumption of {} byte alignment for pointer of type {s} failed\n" ++284 "assumption of {} byte alignment for pointer of type {s} failed\n" ++
280 "address is {} aligned, misalignment offset is {} bytes",285 "address is {} aligned, misalignment offset is {} bytes",
281 .{286 .{
...@@ -314,18 +319,20 @@ fn shiftOob(...@@ -314,18 +319,20 @@ fn shiftOob(
314 rhs.getPositiveInteger() >= data.lhs_type.getIntegerSize())319 rhs.getPositiveInteger() >= data.lhs_type.getIntegerSize())
315 {320 {
316 if (rhs.isNegative()) {321 if (rhs.isNegative()) {
317 logMessage("shift exponent {} is negative", .{rhs});322 panic(@returnAddress(), "shift exponent {} is negative", .{rhs});
318 } else {323 } else {
319 logMessage(324 panic(
325 @returnAddress(),
320 "shift exponent {} is too large for {}-bit type {s}",326 "shift exponent {} is too large for {}-bit type {s}",
321 .{ rhs, data.lhs_type.getIntegerSize(), data.lhs_type.getName() },327 .{ rhs, data.lhs_type.getIntegerSize(), data.lhs_type.getName() },
322 );328 );
323 }329 }
324 } else {330 } else {
325 if (lhs.isNegative()) {331 if (lhs.isNegative()) {
326 logMessage("left shift of negative value {}", .{lhs});332 panic(@returnAddress(), "left shift of negative value {}", .{lhs});
327 } else {333 } else {
328 logMessage(334 panic(
335 @returnAddress(),
329 "left shift of {} by {} places cannot be represented in type {s}",336 "left shift of {} by {} places cannot be represented in type {s}",
330 .{ lhs, rhs, data.lhs_type.getName() },337 .{ lhs, rhs, data.lhs_type.getName() },
331 );338 );
...@@ -351,7 +358,8 @@ fn outOfBounds(...@@ -351,7 +358,8 @@ fn outOfBounds(
351 index_handle: ValueHandle,358 index_handle: ValueHandle,
352) callconv(.c) noreturn {359) callconv(.c) noreturn {
353 const index: Value = .{ .handle = index_handle, .td = data.index_type };360 const index: Value = .{ .handle = index_handle, .td = data.index_type };
354 logMessage(361 panic(
362 @returnAddress(),
355 "index {} out of bounds for type {s}",363 "index {} out of bounds for type {s}",
356 .{ index, data.array_type.getName() },364 .{ index, data.array_type.getName() },
357 );365 );
...@@ -376,13 +384,14 @@ fn pointerOverflow(...@@ -376,13 +384,14 @@ fn pointerOverflow(
376) callconv(.c) noreturn {384) callconv(.c) noreturn {
377 if (base == 0) {385 if (base == 0) {
378 if (result == 0) {386 if (result == 0) {
379 logMessage("applying zero offset to null pointer", .{});387 panic(@returnAddress(), "applying zero offset to null pointer", .{});
380 } else {388 } else {
381 logMessage("applying non-zero offset {} to null pointer", .{result});389 panic(@returnAddress(), "applying non-zero offset {} to null pointer", .{result});
382 }390 }
383 } else {391 } else {
384 if (result == 0) {392 if (result == 0) {
385 logMessage(393 panic(
394 @returnAddress(),
386 "applying non-zero offset to non-null pointer 0x{x} produced null pointer",395 "applying non-zero offset to non-null pointer 0x{x} produced null pointer",
387 .{base},396 .{base},
388 );397 );
...@@ -391,18 +400,21 @@ fn pointerOverflow(...@@ -391,18 +400,21 @@ fn pointerOverflow(
391 const signed_result: isize = @bitCast(result);400 const signed_result: isize = @bitCast(result);
392 if ((signed_base >= 0) == (signed_result >= 0)) {401 if ((signed_base >= 0) == (signed_result >= 0)) {
393 if (base > result) {402 if (base > result) {
394 logMessage(403 panic(
404 @returnAddress(),
395 "addition of unsigned offset to 0x{x} overflowed to 0x{x}",405 "addition of unsigned offset to 0x{x} overflowed to 0x{x}",
396 .{ base, result },406 .{ base, result },
397 );407 );
398 } else {408 } else {
399 logMessage(409 panic(
410 @returnAddress(),
400 "subtraction of unsigned offset to 0x{x} overflowed to 0x{x}",411 "subtraction of unsigned offset to 0x{x} overflowed to 0x{x}",
401 .{ base, result },412 .{ base, result },
402 );413 );
403 }414 }
404 } else {415 } else {
405 logMessage(416 panic(
417 @returnAddress(),
406 "pointer index expression with base 0x{x} overflowed to 0x{x}",418 "pointer index expression with base 0x{x} overflowed to 0x{x}",
407 .{ base, result },419 .{ base, result },
408 );420 );
...@@ -462,17 +474,20 @@ fn typeMismatch(...@@ -462,17 +474,20 @@ fn typeMismatch(
462 const handle: usize = @intFromPtr(pointer);474 const handle: usize = @intFromPtr(pointer);
463475
464 if (pointer == null) {476 if (pointer == null) {
465 logMessage(477 panic(
478 @returnAddress(),
466 "{s} null pointer of type {s}",479 "{s} null pointer of type {s}",
467 .{ data.kind.getName(), data.td.getName() },480 .{ data.kind.getName(), data.td.getName() },
468 );481 );
469 } else if (!std.mem.isAligned(handle, alignment)) {482 } else if (!std.mem.isAligned(handle, alignment)) {
470 logMessage(483 panic(
484 @returnAddress(),
471 "{s} misaligned address 0x{x} for type {s}, which requires {} byte alignment",485 "{s} misaligned address 0x{x} for type {s}, which requires {} byte alignment",
472 .{ data.kind.getName(), handle, data.td.getName(), alignment },486 .{ data.kind.getName(), handle, data.td.getName(), alignment },
473 );487 );
474 } else {488 } else {
475 logMessage(489 panic(
490 @returnAddress(),
476 "{s} address 0x{x} with insufficient space for an object of type {s}",491 "{s} address 0x{x} with insufficient space for an object of type {s}",
477 .{ data.kind.getName(), handle, data.td.getName() },492 .{ data.kind.getName(), handle, data.td.getName() },
478 );493 );
...@@ -484,11 +499,11 @@ const UnreachableData = extern struct {...@@ -484,11 +499,11 @@ const UnreachableData = extern struct {
484};499};
485500
486fn builtinUnreachable(_: *const UnreachableData) callconv(.c) noreturn {501fn builtinUnreachable(_: *const UnreachableData) callconv(.c) noreturn {
487 logMessage("execution reached an unreachable program point", .{});502 panic(@returnAddress(), "execution reached an unreachable program point", .{});
488}503}
489504
490fn missingReturn(_: *const UnreachableData) callconv(.c) noreturn {505fn 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", .{});
492}507}
493508
494const NonNullReturnData = extern struct {509const NonNullReturnData = extern struct {
...@@ -499,7 +514,7 @@ fn nonNullReturnAbort(data: *const NonNullReturnData) callconv(.c) noreturn {...@@ -499,7 +514,7 @@ fn nonNullReturnAbort(data: *const NonNullReturnData) callconv(.c) noreturn {
499 nonNullReturn(data);514 nonNullReturn(data);
500}515}
501fn nonNullReturn(_: *const NonNullReturnData) callconv(.c) noreturn {516fn 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", .{});
503}518}
504519
505const NonNullArgData = extern struct {520const NonNullArgData = extern struct {
...@@ -513,7 +528,8 @@ fn nonNullArgAbort(data: *const NonNullArgData) callconv(.c) noreturn {...@@ -513,7 +528,8 @@ fn nonNullArgAbort(data: *const NonNullArgData) callconv(.c) noreturn {
513}528}
514529
515fn nonNullArg(data: *const NonNullArgData) callconv(.c) noreturn {530fn nonNullArg(data: *const NonNullArgData) callconv(.c) noreturn {
516 logMessage(531 panic(
532 @returnAddress(),
517 "null pointer passed as argument {}, which is declared to never be null",533 "null pointer passed as argument {}, which is declared to never be null",
518 .{data.arg_index},534 .{data.arg_index},
519 );535 );
...@@ -536,7 +552,8 @@ fn loadInvalidValue(...@@ -536,7 +552,8 @@ fn loadInvalidValue(
536 value_handle: ValueHandle,552 value_handle: ValueHandle,
537) callconv(.c) noreturn {553) callconv(.c) noreturn {
538 const value: Value = .{ .handle = value_handle, .td = data.td };554 const value: Value = .{ .handle = value_handle, .td = data.td };
539 logMessage(555 panic(
556 @returnAddress(),
540 "load of value {}, which is not valid for type {s}",557 "load of value {}, which is not valid for type {s}",
541 .{ value, data.td.getName() },558 .{ value, data.td.getName() },
542 );559 );
...@@ -554,7 +571,8 @@ fn invalidBuiltinAbort(data: *const InvalidBuiltinData) callconv(.c) noreturn {...@@ -554,7 +571,8 @@ fn invalidBuiltinAbort(data: *const InvalidBuiltinData) callconv(.c) noreturn {
554}571}
555572
556fn invalidBuiltin(data: *const InvalidBuiltinData) callconv(.c) noreturn {573fn invalidBuiltin(data: *const InvalidBuiltinData) callconv(.c) noreturn {
557 logMessage(574 panic(
575 @returnAddress(),
558 "passing zero to {s}(), which is not a valid argument",576 "passing zero to {s}(), which is not a valid argument",
559 .{@tagName(data.kind)},577 .{@tagName(data.kind)},
560 );578 );
...@@ -577,7 +595,8 @@ fn vlaBoundNotPositive(...@@ -577,7 +595,8 @@ fn vlaBoundNotPositive(
577 bound_handle: ValueHandle,595 bound_handle: ValueHandle,
578) callconv(.c) noreturn {596) callconv(.c) noreturn {
579 const bound: Value = .{ .handle = bound_handle, .td = data.td };597 const bound: Value = .{ .handle = bound_handle, .td = data.td };
580 logMessage(598 panic(
599 @returnAddress(),
581 "variable length array bound evaluates to non-positive value {}",600 "variable length array bound evaluates to non-positive value {}",
582 .{bound},601 .{bound},
583 );602 );
...@@ -611,22 +630,18 @@ fn floatCastOverflow(...@@ -611,22 +630,18 @@ fn floatCastOverflow(
611 if (@as(u16, ptr[0]) + @as(u16, ptr[1]) < 2 or ptr[0] == 0xFF or ptr[1] == 0xFF) {630 if (@as(u16, ptr[0]) + @as(u16, ptr[1]) < 2 or ptr[0] == 0xFF or ptr[1] == 0xFF) {
612 const data: *const FloatCastOverflowData = @ptrCast(data_handle);631 const data: *const FloatCastOverflowData = @ptrCast(data_handle);
613 const from_value: Value = .{ .handle = from_handle, .td = data.from };632 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}", .{
615 from_value, data.to.getName(),634 from_value, data.to.getName(),
616 });635 });
617 } else {636 } else {
618 const data: *const FloatCastOverflowDataV2 = @ptrCast(data_handle);637 const data: *const FloatCastOverflowDataV2 = @ptrCast(data_handle);
619 const from_value: Value = .{ .handle = from_handle, .td = data.from };638 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}", .{
621 from_value, data.to.getName(),640 from_value, data.to.getName(),
622 });641 });
623 }642 }
624}643}
625644
626inline fn logMessage(comptime fmt: []const u8, args: anytype) noreturn {
627 std.debug.panicExtra(@returnAddress(), fmt, args);
628}
629
630fn exportHandler(645fn exportHandler(
631 handler: anytype,646 handler: anytype,
632 comptime sym_name: []const u8,647 comptime sym_name: []const u8,