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