| author | |
| committer | |
| log | 35b9db3b1549668c5a3a464f97aed1441b18d791 |
| tree | 446b9a52420255c82adad39a9d1eb150ae7dfc1b |
| parent | 931178494f4c77631e5eb9c567f64492d6592eeb |
11 files changed, 195 insertions(+), 60 deletions(-)
lib/ubsan_rt.zig+151-27| ... | @@ -79,12 +79,16 @@ const Value = extern struct { | ... | @@ -79,12 +79,16 @@ const Value = extern struct { |
| 79 | }; | 79 | }; |
| 80 | } | 80 | } |
| 81 | 81 | ||
| 82 | fn getFloat(value: Value) c_longdouble { | 82 | fn getFloat(value: Value) f128 { |
| 83 | assert(value.td.kind == .float); | 83 | assert(value.td.kind == .float); |
| 84 | const size = value.td.info.float; | 84 | const size = value.td.info.float; |
| 85 | const max_inline_size = @bitSizeOf(ValueHandle); | 85 | const max_inline_size = @bitSizeOf(ValueHandle); |
| 86 | if (size <= max_inline_size) { | 86 | if (size <= max_inline_size) { |
| 87 | return @bitCast(@intFromPtr(value.handle)); | 87 | return @as(switch (@bitSizeOf(usize)) { |
| 88 | 32 => f32, | ||
| 89 | 64 => f64, | ||
| 90 | else => @compileError("unsupported target"), | ||
| 91 | }, @bitCast(@intFromPtr(value.handle))); | ||
| 88 | } | 92 | } |
| 89 | return @floatCast(switch (size) { | 93 | return @floatCast(switch (size) { |
| 90 | 64 => @as(*const f64, @alignCast(@ptrCast(value.handle))).*, | 94 | 64 => @as(*const f64, @alignCast(@ptrCast(value.handle))).*, |
| ... | @@ -122,6 +126,11 @@ const Value = extern struct { | ... | @@ -122,6 +126,11 @@ const Value = extern struct { |
| 122 | ) !void { | 126 | ) !void { |
| 123 | comptime assert(fmt.len == 0); | 127 | comptime assert(fmt.len == 0); |
| 124 | 128 | ||
| 129 | if (builtin.zig_backend == .stage2_x86_64 and builtin.os.tag == .windows) { | ||
| 130 | try writer.writeAll("(unknown)"); | ||
| 131 | return; | ||
| 132 | } | ||
| 133 | |||
| 125 | switch (value.td.kind) { | 134 | switch (value.td.kind) { |
| 126 | .integer => { | 135 | .integer => { |
| 127 | if (value.td.isSigned()) { | 136 | if (value.td.isSigned()) { |
| ... | @@ -146,6 +155,14 @@ fn overflowHandler( | ... | @@ -146,6 +155,14 @@ fn overflowHandler( |
| 146 | comptime operator: []const u8, | 155 | comptime operator: []const u8, |
| 147 | ) void { | 156 | ) void { |
| 148 | const S = struct { | 157 | const S = struct { |
| 158 | fn abort( | ||
| 159 | data: *const OverflowData, | ||
| 160 | lhs_handle: ValueHandle, | ||
| 161 | rhs_handle: ValueHandle, | ||
| 162 | ) callconv(.c) noreturn { | ||
| 163 | handler(data, lhs_handle, rhs_handle); | ||
| 164 | } | ||
| 165 | |||
| 149 | fn handler( | 166 | fn handler( |
| 150 | data: *const OverflowData, | 167 | data: *const OverflowData, |
| 151 | lhs_handle: ValueHandle, | 168 | lhs_handle: ValueHandle, |
| ... | @@ -167,7 +184,14 @@ fn overflowHandler( | ... | @@ -167,7 +184,14 @@ fn overflowHandler( |
| 167 | } | 184 | } |
| 168 | }; | 185 | }; |
| 169 | 186 | ||
| 170 | exportHandler(&S.handler, sym_name, true); | 187 | exportHandlerWithAbort(&S.handler, &S.abort, sym_name); |
| 188 | } | ||
| 189 | |||
| 190 | fn negationHandlerAbort( | ||
| 191 | data: *const OverflowData, | ||
| 192 | value_handle: ValueHandle, | ||
| 193 | ) callconv(.c) noreturn { | ||
| 194 | negationHandler(data, value_handle); | ||
| 171 | } | 195 | } |
| 172 | 196 | ||
| 173 | fn negationHandler( | 197 | fn negationHandler( |
| ... | @@ -181,6 +205,14 @@ fn negationHandler( | ... | @@ -181,6 +205,14 @@ fn negationHandler( |
| 181 | ); | 205 | ); |
| 182 | } | 206 | } |
| 183 | 207 | ||
| 208 | fn divRemHandlerAbort( | ||
| 209 | data: *const OverflowData, | ||
| 210 | lhs_handle: ValueHandle, | ||
| 211 | rhs_handle: ValueHandle, | ||
| 212 | ) callconv(.c) noreturn { | ||
| 213 | divRemHandler(data, lhs_handle, rhs_handle); | ||
| 214 | } | ||
| 215 | |||
| 184 | fn divRemHandler( | 216 | fn divRemHandler( |
| 185 | data: *const OverflowData, | 217 | data: *const OverflowData, |
| 186 | lhs_handle: ValueHandle, | 218 | lhs_handle: ValueHandle, |
| ... | @@ -203,6 +235,20 @@ const AlignmentAssumptionData = extern struct { | ... | @@ -203,6 +235,20 @@ const AlignmentAssumptionData = extern struct { |
| 203 | td: *const TypeDescriptor, | 235 | td: *const TypeDescriptor, |
| 204 | }; | 236 | }; |
| 205 | 237 | ||
| 238 | fn alignmentAssumptionHandlerAbort( | ||
| 239 | data: *const AlignmentAssumptionData, | ||
| 240 | pointer: ValueHandle, | ||
| 241 | alignment_handle: ValueHandle, | ||
| 242 | maybe_offset: ?ValueHandle, | ||
| 243 | ) callconv(.c) noreturn { | ||
| 244 | alignmentAssumptionHandler( | ||
| 245 | data, | ||
| 246 | pointer, | ||
| 247 | alignment_handle, | ||
| 248 | maybe_offset, | ||
| 249 | ); | ||
| 250 | } | ||
| 251 | |||
| 206 | fn alignmentAssumptionHandler( | 252 | fn alignmentAssumptionHandler( |
| 207 | data: *const AlignmentAssumptionData, | 253 | data: *const AlignmentAssumptionData, |
| 208 | pointer: ValueHandle, | 254 | pointer: ValueHandle, |
| ... | @@ -248,6 +294,14 @@ const ShiftOobData = extern struct { | ... | @@ -248,6 +294,14 @@ const ShiftOobData = extern struct { |
| 248 | rhs_type: *const TypeDescriptor, | 294 | rhs_type: *const TypeDescriptor, |
| 249 | }; | 295 | }; |
| 250 | 296 | ||
| 297 | fn shiftOobAbort( | ||
| 298 | data: *const ShiftOobData, | ||
| 299 | lhs_handle: ValueHandle, | ||
| 300 | rhs_handle: ValueHandle, | ||
| 301 | ) callconv(.c) noreturn { | ||
| 302 | shiftOob(data, lhs_handle, rhs_handle); | ||
| 303 | } | ||
| 304 | |||
| 251 | fn shiftOob( | 305 | fn shiftOob( |
| 252 | data: *const ShiftOobData, | 306 | data: *const ShiftOobData, |
| 253 | lhs_handle: ValueHandle, | 307 | lhs_handle: ValueHandle, |
| ... | @@ -285,7 +339,17 @@ const OutOfBoundsData = extern struct { | ... | @@ -285,7 +339,17 @@ const OutOfBoundsData = extern struct { |
| 285 | index_type: *const TypeDescriptor, | 339 | index_type: *const TypeDescriptor, |
| 286 | }; | 340 | }; |
| 287 | 341 | ||
| 288 | fn outOfBounds(data: *const OutOfBoundsData, index_handle: ValueHandle) callconv(.c) noreturn { | 342 | fn outOfBoundsAbort( |
| 343 | data: *const OutOfBoundsData, | ||
| 344 | index_handle: ValueHandle, | ||
| 345 | ) callconv(.c) noreturn { | ||
| 346 | outOfBounds(data, index_handle); | ||
| 347 | } | ||
| 348 | |||
| 349 | fn outOfBounds( | ||
| 350 | data: *const OutOfBoundsData, | ||
| 351 | index_handle: ValueHandle, | ||
| 352 | ) callconv(.c) noreturn { | ||
| 289 | const index: Value = .{ .handle = index_handle, .td = data.index_type }; | 353 | const index: Value = .{ .handle = index_handle, .td = data.index_type }; |
| 290 | logMessage( | 354 | logMessage( |
| 291 | "index {} out of bounds for type {s}", | 355 | "index {} out of bounds for type {s}", |
| ... | @@ -297,6 +361,14 @@ const PointerOverflowData = extern struct { | ... | @@ -297,6 +361,14 @@ const PointerOverflowData = extern struct { |
| 297 | loc: SourceLocation, | 361 | loc: SourceLocation, |
| 298 | }; | 362 | }; |
| 299 | 363 | ||
| 364 | fn pointerOverflowAbort( | ||
| 365 | data: *const PointerOverflowData, | ||
| 366 | base: usize, | ||
| 367 | result: usize, | ||
| 368 | ) callconv(.c) noreturn { | ||
| 369 | pointerOverflow(data, base, result); | ||
| 370 | } | ||
| 371 | |||
| 300 | fn pointerOverflow( | 372 | fn pointerOverflow( |
| 301 | _: *const PointerOverflowData, | 373 | _: *const PointerOverflowData, |
| 302 | base: usize, | 374 | base: usize, |
| ... | @@ -375,6 +447,13 @@ const TypeMismatchData = extern struct { | ... | @@ -375,6 +447,13 @@ const TypeMismatchData = extern struct { |
| 375 | }, | 447 | }, |
| 376 | }; | 448 | }; |
| 377 | 449 | ||
| 450 | fn typeMismatchAbort( | ||
| 451 | data: *const TypeMismatchData, | ||
| 452 | pointer: ?ValueHandle, | ||
| 453 | ) callconv(.c) noreturn { | ||
| 454 | typeMismatch(data, pointer); | ||
| 455 | } | ||
| 456 | |||
| 378 | fn typeMismatch( | 457 | fn typeMismatch( |
| 379 | data: *const TypeMismatchData, | 458 | data: *const TypeMismatchData, |
| 380 | pointer: ?ValueHandle, | 459 | pointer: ?ValueHandle, |
| ... | @@ -416,6 +495,9 @@ const NonNullReturnData = extern struct { | ... | @@ -416,6 +495,9 @@ const NonNullReturnData = extern struct { |
| 416 | attribute_loc: SourceLocation, | 495 | attribute_loc: SourceLocation, |
| 417 | }; | 496 | }; |
| 418 | 497 | ||
| 498 | fn nonNullReturnAbort(data: *const NonNullReturnData) callconv(.c) noreturn { | ||
| 499 | nonNullReturn(data); | ||
| 500 | } | ||
| 419 | fn nonNullReturn(_: *const NonNullReturnData) callconv(.c) noreturn { | 501 | fn nonNullReturn(_: *const NonNullReturnData) callconv(.c) noreturn { |
| 420 | logMessage("null pointer returned from function declared to never return null", .{}); | 502 | logMessage("null pointer returned from function declared to never return null", .{}); |
| 421 | } | 503 | } |
| ... | @@ -426,6 +508,10 @@ const NonNullArgData = extern struct { | ... | @@ -426,6 +508,10 @@ const NonNullArgData = extern struct { |
| 426 | arg_index: i32, | 508 | arg_index: i32, |
| 427 | }; | 509 | }; |
| 428 | 510 | ||
| 511 | fn nonNullArgAbort(data: *const NonNullArgData) callconv(.c) noreturn { | ||
| 512 | nonNullArg(data); | ||
| 513 | } | ||
| 514 | |||
| 429 | fn nonNullArg(data: *const NonNullArgData) callconv(.c) noreturn { | 515 | fn nonNullArg(data: *const NonNullArgData) callconv(.c) noreturn { |
| 430 | logMessage( | 516 | logMessage( |
| 431 | "null pointer passed as argument {}, which is declared to never be null", | 517 | "null pointer passed as argument {}, which is declared to never be null", |
| ... | @@ -438,6 +524,13 @@ const InvalidValueData = extern struct { | ... | @@ -438,6 +524,13 @@ const InvalidValueData = extern struct { |
| 438 | td: *const TypeDescriptor, | 524 | td: *const TypeDescriptor, |
| 439 | }; | 525 | }; |
| 440 | 526 | ||
| 527 | fn loadInvalidValueAbort( | ||
| 528 | data: *const InvalidValueData, | ||
| 529 | value_handle: ValueHandle, | ||
| 530 | ) callconv(.c) noreturn { | ||
| 531 | loadInvalidValue(data, value_handle); | ||
| 532 | } | ||
| 533 | |||
| 441 | fn loadInvalidValue( | 534 | fn loadInvalidValue( |
| 442 | data: *const InvalidValueData, | 535 | data: *const InvalidValueData, |
| 443 | value_handle: ValueHandle, | 536 | value_handle: ValueHandle, |
| ... | @@ -456,6 +549,9 @@ const InvalidBuiltinData = extern struct { | ... | @@ -456,6 +549,9 @@ const InvalidBuiltinData = extern struct { |
| 456 | clz, | 549 | clz, |
| 457 | }, | 550 | }, |
| 458 | }; | 551 | }; |
| 552 | fn invalidBuiltinAbort(data: *const InvalidBuiltinData) callconv(.c) noreturn { | ||
| 553 | invalidBuiltin(data); | ||
| 554 | } | ||
| 459 | 555 | ||
| 460 | fn invalidBuiltin(data: *const InvalidBuiltinData) callconv(.c) noreturn { | 556 | fn invalidBuiltin(data: *const InvalidBuiltinData) callconv(.c) noreturn { |
| 461 | logMessage( | 557 | logMessage( |
| ... | @@ -469,6 +565,13 @@ const VlaBoundNotPositive = extern struct { | ... | @@ -469,6 +565,13 @@ const VlaBoundNotPositive = extern struct { |
| 469 | td: *const TypeDescriptor, | 565 | td: *const TypeDescriptor, |
| 470 | }; | 566 | }; |
| 471 | 567 | ||
| 568 | fn vlaBoundNotPositiveAbort( | ||
| 569 | data: *const VlaBoundNotPositive, | ||
| 570 | bound_handle: ValueHandle, | ||
| 571 | ) callconv(.c) noreturn { | ||
| 572 | vlaBoundNotPositive(data, bound_handle); | ||
| 573 | } | ||
| 574 | |||
| 472 | fn vlaBoundNotPositive( | 575 | fn vlaBoundNotPositive( |
| 473 | data: *const VlaBoundNotPositive, | 576 | data: *const VlaBoundNotPositive, |
| 474 | bound_handle: ValueHandle, | 577 | bound_handle: ValueHandle, |
| ... | @@ -491,6 +594,13 @@ const FloatCastOverflowDataV2 = extern struct { | ... | @@ -491,6 +594,13 @@ const FloatCastOverflowDataV2 = extern struct { |
| 491 | to: *const TypeDescriptor, | 594 | to: *const TypeDescriptor, |
| 492 | }; | 595 | }; |
| 493 | 596 | ||
| 597 | fn floatCastOverflowAbort( | ||
| 598 | data_handle: *align(8) const anyopaque, | ||
| 599 | from_handle: ValueHandle, | ||
| 600 | ) callconv(.c) noreturn { | ||
| 601 | floatCastOverflow(data_handle, from_handle); | ||
| 602 | } | ||
| 603 | |||
| 494 | fn floatCastOverflow( | 604 | fn floatCastOverflow( |
| 495 | data_handle: *align(8) const anyopaque, | 605 | data_handle: *align(8) const anyopaque, |
| 496 | from_handle: ValueHandle, | 606 | from_handle: ValueHandle, |
| ... | @@ -514,22 +624,31 @@ fn floatCastOverflow( | ... | @@ -514,22 +624,31 @@ fn floatCastOverflow( |
| 514 | } | 624 | } |
| 515 | 625 | ||
| 516 | inline fn logMessage(comptime fmt: []const u8, args: anytype) noreturn { | 626 | inline fn logMessage(comptime fmt: []const u8, args: anytype) noreturn { |
| 517 | std.debug.panicExtra(null, @returnAddress(), fmt, args); | 627 | std.debug.panicExtra(@returnAddress(), fmt, args); |
| 518 | } | 628 | } |
| 519 | 629 | ||
| 520 | fn exportHandler( | 630 | fn exportHandler( |
| 521 | handler: anytype, | 631 | handler: anytype, |
| 522 | comptime sym_name: []const u8, | 632 | comptime sym_name: []const u8, |
| 523 | comptime abort: bool, | ||
| 524 | ) void { | 633 | ) void { |
| 525 | const linkage = if (builtin.is_test) .internal else .weak; | 634 | const linkage = if (builtin.zig_backend == .stage2_x86_64 and builtin.os.tag == .windows) .internal else .weak; |
| 635 | const N = "__ubsan_handle_" ++ sym_name; | ||
| 636 | @export(handler, .{ .name = N, .linkage = linkage }); | ||
| 637 | } | ||
| 638 | |||
| 639 | fn exportHandlerWithAbort( | ||
| 640 | handler: anytype, | ||
| 641 | abort_handler: anytype, | ||
| 642 | comptime sym_name: []const u8, | ||
| 643 | ) void { | ||
| 644 | const linkage = if (builtin.zig_backend == .stage2_x86_64 and builtin.os.tag == .windows) .internal else .weak; | ||
| 526 | { | 645 | { |
| 527 | const N = "__ubsan_handle_" ++ sym_name; | 646 | const N = "__ubsan_handle_" ++ sym_name; |
| 528 | @export(handler, .{ .name = N, .linkage = linkage }); | 647 | @export(handler, .{ .name = N, .linkage = linkage }); |
| 529 | } | 648 | } |
| 530 | if (abort) { | 649 | { |
| 531 | const N = "__ubsan_handle_" ++ sym_name ++ "_abort"; | 650 | const N = "__ubsan_handle_" ++ sym_name ++ "_abort"; |
| 532 | @export(handler, .{ .name = N, .linkage = linkage }); | 651 | @export(abort_handler, .{ .name = N, .linkage = linkage }); |
| 533 | } | 652 | } |
| 534 | } | 653 | } |
| 535 | 654 | ||
| ... | @@ -539,24 +658,29 @@ const can_build_ubsan = switch (builtin.zig_backend) { | ... | @@ -539,24 +658,29 @@ const can_build_ubsan = switch (builtin.zig_backend) { |
| 539 | }; | 658 | }; |
| 540 | 659 | ||
| 541 | comptime { | 660 | comptime { |
| 542 | overflowHandler("add_overflow", "+"); | 661 | if (can_build_ubsan) { |
| 543 | overflowHandler("mul_overflow", "*"); | 662 | overflowHandler("add_overflow", "+"); |
| 544 | overflowHandler("sub_overflow", "-"); | 663 | overflowHandler("mul_overflow", "*"); |
| 545 | exportHandler(&alignmentAssumptionHandler, "alignment_assumption", true); | 664 | overflowHandler("sub_overflow", "-"); |
| 546 | exportHandler(&builtinUnreachable, "builtin_unreachable", false); | 665 | exportHandlerWithAbort(&alignmentAssumptionHandler, &alignmentAssumptionHandlerAbort, "alignment_assumption"); |
| 547 | exportHandler(&divRemHandler, "divrem_overflow", true); | 666 | |
| 548 | exportHandler(&floatCastOverflow, "float_cast_overflow", true); | 667 | exportHandlerWithAbort(&divRemHandler, &divRemHandlerAbort, "divrem_overflow"); |
| 549 | exportHandler(&invalidBuiltin, "invalid_builtin", true); | 668 | exportHandlerWithAbort(&floatCastOverflow, &floatCastOverflowAbort, "float_cast_overflow"); |
| 550 | exportHandler(&loadInvalidValue, "load_invalid_value", true); | 669 | exportHandlerWithAbort(&invalidBuiltin, &invalidBuiltinAbort, "invalid_builtin"); |
| 551 | exportHandler(&missingReturn, "missing_return", false); | 670 | exportHandlerWithAbort(&loadInvalidValue, &loadInvalidValueAbort, "load_invalid_value"); |
| 552 | exportHandler(&negationHandler, "negate_overflow", true); | 671 | |
| 553 | exportHandler(&nonNullArg, "nonnull_arg", true); | 672 | exportHandlerWithAbort(&negationHandler, &negationHandlerAbort, "negate_overflow"); |
| 554 | exportHandler(&nonNullReturn, "nonnull_return_v1", true); | 673 | exportHandlerWithAbort(&nonNullArg, &nonNullArgAbort, "nonnull_arg"); |
| 555 | exportHandler(&outOfBounds, "out_of_bounds", true); | 674 | exportHandlerWithAbort(&nonNullReturn, &nonNullReturnAbort, "nonnull_return_v1"); |
| 556 | exportHandler(&pointerOverflow, "pointer_overflow", true); | 675 | exportHandlerWithAbort(&outOfBounds, &outOfBoundsAbort, "out_of_bounds"); |
| 557 | exportHandler(&shiftOob, "shift_out_of_bounds", true); | 676 | exportHandlerWithAbort(&pointerOverflow, &pointerOverflowAbort, "pointer_overflow"); |
| 558 | exportHandler(&typeMismatch, "type_mismatch_v1", true); | 677 | exportHandlerWithAbort(&shiftOob, &shiftOobAbort, "shift_out_of_bounds"); |
| 559 | exportHandler(&vlaBoundNotPositive, "vla_bound_not_positive", true); | 678 | exportHandlerWithAbort(&typeMismatch, &typeMismatchAbort, "type_mismatch_v1"); |
| 679 | exportHandlerWithAbort(&vlaBoundNotPositive, &vlaBoundNotPositiveAbort, "vla_bound_not_positive"); | ||
| 680 | |||
| 681 | exportHandler(&builtinUnreachable, "builtin_unreachable"); | ||
| 682 | exportHandler(&missingReturn, "missing_return"); | ||
| 683 | } | ||
| 560 | 684 | ||
| 561 | // these checks are nearly impossible to duplicate in zig, as they rely on nuances | 685 | // these checks are nearly impossible to duplicate in zig, as they rely on nuances |
| 562 | // in the Itanium C++ ABI. | 686 | // in the Itanium C++ ABI. |
src/Compilation.zig+23-33| ... | @@ -1317,15 +1317,6 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil | ... | @@ -1317,15 +1317,6 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil |
| 1317 | break :s .obj; | 1317 | break :s .obj; |
| 1318 | }; | 1318 | }; |
| 1319 | 1319 | ||
| 1320 | const ubsan_rt_strat: RtStrat = s: { | ||
| 1321 | const want_ubsan_rt = options.want_ubsan_rt orelse (any_sanitize_c and output_mode != .Obj); | ||
| 1322 | if (!want_ubsan_rt) break :s .none; | ||
| 1323 | if (options.skip_linker_dependencies) break :s .none; | ||
| 1324 | if (have_zcu) break :s .zcu; | ||
| 1325 | if (is_exe_or_dyn_lib) break :s .lib; | ||
| 1326 | break :s .obj; | ||
| 1327 | }; | ||
| 1328 | |||
| 1329 | if (compiler_rt_strat == .zcu) { | 1320 | if (compiler_rt_strat == .zcu) { |
| 1330 | // For objects, this mechanism relies on essentially `_ = @import("compiler-rt");` | 1321 | // For objects, this mechanism relies on essentially `_ = @import("compiler-rt");` |
| 1331 | // injected into the object. | 1322 | // injected into the object. |
| ... | @@ -1355,6 +1346,15 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil | ... | @@ -1355,6 +1346,15 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil |
| 1355 | // unlike compiler_rt, we always want to go through the `_ = @import("ubsan-rt")` | 1346 | // unlike compiler_rt, we always want to go through the `_ = @import("ubsan-rt")` |
| 1356 | // approach, since the ubsan runtime uses quite a lot of the standard library | 1347 | // approach, since the ubsan runtime uses quite a lot of the standard library |
| 1357 | // and this reduces unnecessary bloat. | 1348 | // and this reduces unnecessary bloat. |
| 1349 | const ubsan_rt_strat: RtStrat = s: { | ||
| 1350 | const want_ubsan_rt = options.want_ubsan_rt orelse (any_sanitize_c and output_mode != .Obj); | ||
| 1351 | if (!want_ubsan_rt) break :s .none; | ||
| 1352 | if (options.skip_linker_dependencies) break :s .none; | ||
| 1353 | if (have_zcu) break :s .zcu; | ||
| 1354 | if (is_exe_or_dyn_lib) break :s .lib; | ||
| 1355 | break :s .obj; | ||
| 1356 | }; | ||
| 1357 | |||
| 1358 | if (ubsan_rt_strat == .zcu) { | 1358 | if (ubsan_rt_strat == .zcu) { |
| 1359 | const ubsan_rt_mod = try Package.Module.create(arena, .{ | 1359 | const ubsan_rt_mod = try Package.Module.create(arena, .{ |
| 1360 | .global_cache_directory = options.global_cache_directory, | 1360 | .global_cache_directory = options.global_cache_directory, |
| ... | @@ -1362,7 +1362,7 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil | ... | @@ -1362,7 +1362,7 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil |
| 1362 | .root = .{ | 1362 | .root = .{ |
| 1363 | .root_dir = options.zig_lib_directory, | 1363 | .root_dir = options.zig_lib_directory, |
| 1364 | }, | 1364 | }, |
| 1365 | .root_src_path = "ubsan.zig", | 1365 | .root_src_path = "ubsan_rt.zig", |
| 1366 | }, | 1366 | }, |
| 1367 | .fully_qualified_name = "ubsan_rt", | 1367 | .fully_qualified_name = "ubsan_rt", |
| 1368 | .cc_argv = &.{}, | 1368 | .cc_argv = &.{}, |
| ... | @@ -1925,25 +1925,8 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil | ... | @@ -1925,25 +1925,8 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil |
| 1925 | comp.remaining_prelink_tasks += 1; | 1925 | comp.remaining_prelink_tasks += 1; |
| 1926 | } | 1926 | } |
| 1927 | 1927 | ||
| 1928 | <<<<<<< HEAD | ||
| 1929 | if (comp.include_compiler_rt and capable_of_building_compiler_rt) { | ||
| 1930 | if (is_exe_or_dyn_lib) { | ||
| 1931 | ======= | ||
| 1932 | if (target.isMinGW() and comp.config.any_non_single_threaded) { | ||
| 1933 | // LLD might drop some symbols as unused during LTO and GCing, therefore, | ||
| 1934 | // we force mark them for resolution here. | ||
| 1935 | |||
| 1936 | const tls_index_sym = switch (target.cpu.arch) { | ||
| 1937 | .x86 => "__tls_index", | ||
| 1938 | else => "_tls_index", | ||
| 1939 | }; | ||
| 1940 | |||
| 1941 | try comp.force_undefined_symbols.put(comp.gpa, tls_index_sym, {}); | ||
| 1942 | } | ||
| 1943 | |||
| 1944 | if (capable_of_building_compiler_rt) { | 1928 | if (capable_of_building_compiler_rt) { |
| 1945 | if (comp.compiler_rt_strat == .lib) { | 1929 | if (comp.compiler_rt_strat == .lib) { |
| 1946 | >>>>>>> 050e3e69ac (Compilation: correct when to include ubsan) | ||
| 1947 | log.debug("queuing a job to build compiler_rt_lib", .{}); | 1930 | log.debug("queuing a job to build compiler_rt_lib", .{}); |
| 1948 | comp.queued_jobs.compiler_rt_lib = true; | 1931 | comp.queued_jobs.compiler_rt_lib = true; |
| 1949 | comp.remaining_prelink_tasks += 1; | 1932 | comp.remaining_prelink_tasks += 1; |
| ... | @@ -1957,11 +1940,11 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil | ... | @@ -1957,11 +1940,11 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil |
| 1957 | 1940 | ||
| 1958 | if (comp.ubsan_rt_strat == .lib) { | 1941 | if (comp.ubsan_rt_strat == .lib) { |
| 1959 | log.debug("queuing a job to build ubsan_rt_lib", .{}); | 1942 | log.debug("queuing a job to build ubsan_rt_lib", .{}); |
| 1960 | comp.job_queued_ubsan_rt_lib = true; | 1943 | comp.queued_jobs.ubsan_rt_lib = true; |
| 1961 | comp.remaining_prelink_tasks += 1; | 1944 | comp.remaining_prelink_tasks += 1; |
| 1962 | } else if (comp.ubsan_rt_strat == .obj) { | 1945 | } else if (comp.ubsan_rt_strat == .obj) { |
| 1963 | log.debug("queuing a job to build ubsan_rt_obj", .{}); | 1946 | log.debug("queuing a job to build ubsan_rt_obj", .{}); |
| 1964 | comp.job_queued_ubsan_rt_obj = true; | 1947 | comp.queued_jobs.ubsan_rt_obj = true; |
| 1965 | comp.remaining_prelink_tasks += 1; | 1948 | comp.remaining_prelink_tasks += 1; |
| 1966 | } | 1949 | } |
| 1967 | 1950 | ||
| ... | @@ -3782,11 +3765,11 @@ fn performAllTheWorkInner( | ... | @@ -3782,11 +3765,11 @@ fn performAllTheWorkInner( |
| 3782 | } | 3765 | } |
| 3783 | 3766 | ||
| 3784 | if (comp.queued_jobs.ubsan_rt_lib and comp.ubsan_rt_lib == null) { | 3767 | if (comp.queued_jobs.ubsan_rt_lib and comp.ubsan_rt_lib == null) { |
| 3785 | comp.link_task_wait_group.spawnManager(buildRt, .{ comp, "ubsan_rt.zig", .libubsan, .Lib, &comp.ubsan_rt_lib, main_progress_node }); | 3768 | comp.link_task_wait_group.spawnManager(buildRt, .{ comp, "ubsan_rt.zig", .libubsan, .Lib, false, &comp.ubsan_rt_lib, main_progress_node }); |
| 3786 | } | 3769 | } |
| 3787 | 3770 | ||
| 3788 | if (comp.queued_jobs.ubsan_rt_obj and comp.ubsan_rt_obj == null) { | 3771 | if (comp.queued_jobs.ubsan_rt_obj and comp.ubsan_rt_obj == null) { |
| 3789 | comp.link_task_wait_group.spawnManager(buildRt, .{ comp, "ubsan_rt.zig", .libubsan, .Obj, &comp.ubsan_rt_obj, main_progress_node }); | 3772 | comp.link_task_wait_group.spawnManager(buildRt, .{ comp, "ubsan_rt.zig", .libubsan, .Obj, false, &comp.ubsan_rt_obj, main_progress_node }); |
| 3790 | } | 3773 | } |
| 3791 | 3774 | ||
| 3792 | if (comp.queued_jobs.glibc_shared_objects) { | 3775 | if (comp.queued_jobs.glibc_shared_objects) { |
| ... | @@ -6037,9 +6020,16 @@ pub fn addCCArgs( | ... | @@ -6037,9 +6020,16 @@ pub fn addCCArgs( |
| 6037 | try argv.append("-fno-sanitize=function"); | 6020 | try argv.append("-fno-sanitize=function"); |
| 6038 | 6021 | ||
| 6039 | // It's recommended to use the minimal runtime in production environments | 6022 | // It's recommended to use the minimal runtime in production environments |
| 6040 | // due to the security implications of the full runtime. | 6023 | // due to the security implications of the full runtime. The minimal runtime |
| 6024 | // doesn't provide much benefit over simply trapping. | ||
| 6041 | if (mod.optimize_mode == .ReleaseSafe) { | 6025 | if (mod.optimize_mode == .ReleaseSafe) { |
| 6042 | try argv.append("-fsanitize-minimal-runtime"); | 6026 | try argv.append("-fsanitize-trap=undefined"); |
| 6027 | } | ||
| 6028 | |||
| 6029 | // This is necessary because, by default, Clang instructs LLVM to embed a COFF link | ||
| 6030 | // dependency on `libclang_rt.ubsan_standalone.a` when the UBSan runtime is used. | ||
| 6031 | if (target.os.tag == .windows) { | ||
| 6032 | try argv.append("-fno-rtlib-defaultlib"); | ||
| 6043 | } | 6033 | } |
| 6044 | } | 6034 | } |
| 6045 | } | 6035 | } |
test/link/elf.zig+4| ... | @@ -2049,6 +2049,8 @@ fn testLargeBss(b: *Build, opts: Options) *Step { | ... | @@ -2049,6 +2049,8 @@ fn testLargeBss(b: *Build, opts: Options) *Step { |
| 2049 | \\} | 2049 | \\} |
| 2050 | , &.{}); | 2050 | , &.{}); |
| 2051 | exe.linkLibC(); | 2051 | exe.linkLibC(); |
| 2052 | // Disabled to work around an ELF linker bug. | ||
| 2053 | exe.root_module.sanitize_c = false; | ||
| 2052 | 2054 | ||
| 2053 | const run = addRunArtifact(exe); | 2055 | const run = addRunArtifact(exe); |
| 2054 | run.expectExitCode(0); | 2056 | run.expectExitCode(0); |
| ... | @@ -3552,6 +3554,8 @@ fn testTlsLargeTbss(b: *Build, opts: Options) *Step { | ... | @@ -3552,6 +3554,8 @@ fn testTlsLargeTbss(b: *Build, opts: Options) *Step { |
| 3552 | \\} | 3554 | \\} |
| 3553 | , &.{}); | 3555 | , &.{}); |
| 3554 | exe.linkLibC(); | 3556 | exe.linkLibC(); |
| 3557 | // Disabled to work around an ELF linker bug. | ||
| 3558 | exe.root_module.sanitize_c = false; | ||
| 3555 | 3559 | ||
| 3556 | const run = addRunArtifact(exe); | 3560 | const run = addRunArtifact(exe); |
| 3557 | run.expectStdOutEqual("3 0 5 0 0 0\n"); | 3561 | run.expectStdOutEqual("3 0 5 0 0 0\n"); |
test/link/glibc_compat/build.zig+6| ... | @@ -22,6 +22,8 @@ pub fn build(b: *std.Build) void { | ... | @@ -22,6 +22,8 @@ pub fn build(b: *std.Build) void { |
| 22 | .link_libc = true, | 22 | .link_libc = true, |
| 23 | }), | 23 | }), |
| 24 | }); | 24 | }); |
| 25 | exe.bundle_ubsan_rt = false; | ||
| 26 | exe.root_module.sanitize_c = false; | ||
| 25 | exe.root_module.addCSourceFile(.{ .file = b.path("main.c") }); | 27 | exe.root_module.addCSourceFile(.{ .file = b.path("main.c") }); |
| 26 | // TODO: actually test the output | 28 | // TODO: actually test the output |
| 27 | _ = exe.getEmittedBin(); | 29 | _ = exe.getEmittedBin(); |
| ... | @@ -62,6 +64,8 @@ pub fn build(b: *std.Build) void { | ... | @@ -62,6 +64,8 @@ pub fn build(b: *std.Build) void { |
| 62 | .link_libc = true, | 64 | .link_libc = true, |
| 63 | }), | 65 | }), |
| 64 | }); | 66 | }); |
| 67 | exe.bundle_ubsan_rt = false; | ||
| 68 | exe.root_module.sanitize_c = false; | ||
| 65 | exe.root_module.addCSourceFile(.{ .file = b.path("glibc_runtime_check.c") }); | 69 | exe.root_module.addCSourceFile(.{ .file = b.path("glibc_runtime_check.c") }); |
| 66 | 70 | ||
| 67 | // Only try running the test if the host glibc is known to be good enough. Ideally, the Zig | 71 | // Only try running the test if the host glibc is known to be good enough. Ideally, the Zig |
| ... | @@ -161,6 +165,8 @@ pub fn build(b: *std.Build) void { | ... | @@ -161,6 +165,8 @@ pub fn build(b: *std.Build) void { |
| 161 | .link_libc = true, | 165 | .link_libc = true, |
| 162 | }), | 166 | }), |
| 163 | }); | 167 | }); |
| 168 | exe.bundle_ubsan_rt = false; | ||
| 169 | exe.root_module.sanitize_c = false; | ||
| 164 | 170 | ||
| 165 | // Only try running the test if the host glibc is known to be good enough. Ideally, the Zig | 171 | // Only try running the test if the host glibc is known to be good enough. Ideally, the Zig |
| 166 | // test runner would be able to check this, but see https://github.com/ziglang/zig/pull/17702#issuecomment-1831310453 | 172 | // test runner would be able to check this, but see https://github.com/ziglang/zig/pull/17702#issuecomment-1831310453 |
test/link/wasm/export-data/build.zig+1| ... | @@ -13,6 +13,7 @@ pub fn build(b: *std.Build) void { | ... | @@ -13,6 +13,7 @@ pub fn build(b: *std.Build) void { |
| 13 | }), | 13 | }), |
| 14 | }); | 14 | }); |
| 15 | lib.entry = .disabled; | 15 | lib.entry = .disabled; |
| 16 | lib.bundle_ubsan_rt = false; | ||
| 16 | lib.use_lld = false; | 17 | lib.use_lld = false; |
| 17 | lib.root_module.export_symbol_names = &.{ "foo", "bar" }; | 18 | lib.root_module.export_symbol_names = &.{ "foo", "bar" }; |
| 18 | // Object being linked has neither functions nor globals named "foo" or "bar" and | 19 | // Object being linked has neither functions nor globals named "foo" or "bar" and |
test/link/wasm/export/build.zig+4| ... | @@ -19,6 +19,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize | ... | @@ -19,6 +19,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize |
| 19 | no_export.entry = .disabled; | 19 | no_export.entry = .disabled; |
| 20 | no_export.use_llvm = false; | 20 | no_export.use_llvm = false; |
| 21 | no_export.use_lld = false; | 21 | no_export.use_lld = false; |
| 22 | no_export.bundle_ubsan_rt = false; | ||
| 22 | 23 | ||
| 23 | const dynamic_export = b.addExecutable(.{ | 24 | const dynamic_export = b.addExecutable(.{ |
| 24 | .name = "dynamic", | 25 | .name = "dynamic", |
| ... | @@ -32,6 +33,8 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize | ... | @@ -32,6 +33,8 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize |
| 32 | dynamic_export.rdynamic = true; | 33 | dynamic_export.rdynamic = true; |
| 33 | dynamic_export.use_llvm = false; | 34 | dynamic_export.use_llvm = false; |
| 34 | dynamic_export.use_lld = false; | 35 | dynamic_export.use_lld = false; |
| 36 | // don't pull in ubsan, since we're just expecting a minimal executable | ||
| 37 | dynamic_export.bundle_ubsan_rt = false; | ||
| 35 | 38 | ||
| 36 | const force_export = b.addExecutable(.{ | 39 | const force_export = b.addExecutable(.{ |
| 37 | .name = "force", | 40 | .name = "force", |
| ... | @@ -45,6 +48,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize | ... | @@ -45,6 +48,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize |
| 45 | force_export.root_module.export_symbol_names = &.{"foo"}; | 48 | force_export.root_module.export_symbol_names = &.{"foo"}; |
| 46 | force_export.use_llvm = false; | 49 | force_export.use_llvm = false; |
| 47 | force_export.use_lld = false; | 50 | force_export.use_lld = false; |
| 51 | force_export.bundle_ubsan_rt = false; | ||
| 48 | 52 | ||
| 49 | const check_no_export = no_export.checkObject(); | 53 | const check_no_export = no_export.checkObject(); |
| 50 | check_no_export.checkInHeaders(); | 54 | check_no_export.checkInHeaders(); |
test/link/wasm/function-table/build.zig+2| ... | @@ -21,6 +21,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize | ... | @@ -21,6 +21,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize |
| 21 | export_table.use_lld = false; | 21 | export_table.use_lld = false; |
| 22 | export_table.export_table = true; | 22 | export_table.export_table = true; |
| 23 | export_table.link_gc_sections = false; | 23 | export_table.link_gc_sections = false; |
| 24 | export_table.bundle_ubsan_rt = false; | ||
| 24 | 25 | ||
| 25 | const regular_table = b.addExecutable(.{ | 26 | const regular_table = b.addExecutable(.{ |
| 26 | .name = "regular_table", | 27 | .name = "regular_table", |
| ... | @@ -34,6 +35,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize | ... | @@ -34,6 +35,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize |
| 34 | regular_table.use_llvm = false; | 35 | regular_table.use_llvm = false; |
| 35 | regular_table.use_lld = false; | 36 | regular_table.use_lld = false; |
| 36 | regular_table.link_gc_sections = false; // Ensure function table is not empty | 37 | regular_table.link_gc_sections = false; // Ensure function table is not empty |
| 38 | regular_table.bundle_ubsan_rt = false; | ||
| 37 | 39 | ||
| 38 | const check_export = export_table.checkObject(); | 40 | const check_export = export_table.checkObject(); |
| 39 | const check_regular = regular_table.checkObject(); | 41 | const check_regular = regular_table.checkObject(); |
test/link/wasm/shared-memory/build.zig+1| ... | @@ -31,6 +31,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize_mode: std.builtin.Opt | ... | @@ -31,6 +31,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize_mode: std.builtin.Opt |
| 31 | exe.shared_memory = true; | 31 | exe.shared_memory = true; |
| 32 | exe.max_memory = 67108864; | 32 | exe.max_memory = 67108864; |
| 33 | exe.root_module.export_symbol_names = &.{"foo"}; | 33 | exe.root_module.export_symbol_names = &.{"foo"}; |
| 34 | exe.bundle_ubsan_rt = false; | ||
| 34 | 35 | ||
| 35 | const check_exe = exe.checkObject(); | 36 | const check_exe = exe.checkObject(); |
| 36 | 37 |
test/link/wasm/type/build.zig+1| ... | @@ -21,6 +21,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize | ... | @@ -21,6 +21,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize |
| 21 | exe.use_llvm = false; | 21 | exe.use_llvm = false; |
| 22 | exe.use_lld = false; | 22 | exe.use_lld = false; |
| 23 | exe.root_module.export_symbol_names = &.{"foo"}; | 23 | exe.root_module.export_symbol_names = &.{"foo"}; |
| 24 | exe.bundle_ubsan_rt = false; | ||
| 24 | b.installArtifact(exe); | 25 | b.installArtifact(exe); |
| 25 | 26 | ||
| 26 | const check_exe = exe.checkObject(); | 27 | const check_exe = exe.checkObject(); |
test/src/StackTrace.zig+1| ... | @@ -81,6 +81,7 @@ fn addExpect( | ... | @@ -81,6 +81,7 @@ fn addExpect( |
| 81 | }), | 81 | }), |
| 82 | .use_llvm = use_llvm, | 82 | .use_llvm = use_llvm, |
| 83 | }); | 83 | }); |
| 84 | exe.bundle_ubsan_rt = false; | ||
| 84 | 85 | ||
| 85 | const run = b.addRunArtifact(exe); | 86 | const run = b.addRunArtifact(exe); |
| 86 | run.removeEnvironmentVariable("CLICOLOR_FORCE"); | 87 | run.removeEnvironmentVariable("CLICOLOR_FORCE"); |
tools/incr-check.zig+1| ... | @@ -108,6 +108,7 @@ pub fn main() !void { | ... | @@ -108,6 +108,7 @@ pub fn main() !void { |
| 108 | "build-exe", | 108 | "build-exe", |
| 109 | case.root_source_file, | 109 | case.root_source_file, |
| 110 | "-fincremental", | 110 | "-fincremental", |
| 111 | "-fno-ubsan-rt", | ||
| 111 | "-target", | 112 | "-target", |
| 112 | target.query, | 113 | target.query, |
| 113 | "--cache-dir", | 114 | "--cache-dir", |