Skip to content

Commit b3df0d7

Browse files
committed
Auto merge of rust-lang#122580 - saethlin:compiler-builtins-can-panic, r=pnkfelix
"Handle" calls to upstream monomorphizations in compiler_builtins This is pretty cooked, but I think it works. compiler-builtins has a long-standing problem that at link time, its rlib cannot contain any calls to `core`. And yet, in codegen we _love_ inserting calls to symbols in `core`, generally from various panic entrypoints. I intend this PR to attack that problem as completely as possible. When we generate a function call, we now check if we are generating a function call from `compiler_builtins` and whether the callee is a function which was not lowered in the current crate, meaning we will have to link to it. If those conditions are met, actually generating the call is asking for a linker error. So we don't. If the callee diverges, we lower to an abort with the same behavior as `core::intrinsics::abort`. If the callee does not diverge, we produce an error. This means that compiler-builtins can contain panics, but they'll SIGILL instead of panicking. I made non-diverging calls a compile error because I'm guessing that they'd mostly get into compiler-builtins by someone making a mistake while working on the crate, and compile errors are better than linker errors. We could turn such calls into aborts as well if that's preferred.
2 parents 1447f9d + 2f6fb23 commit b3df0d7

File tree

17 files changed

+284
-29
lines changed

17 files changed

+284
-29
lines changed

Cargo.lock

+32-8
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,7 @@ version = "0.1.5"
214214
source = "registry+https://github.com/rust-lang/crates.io-index"
215215
checksum = "9792d37ca5173d7e7f4fe453739a0671d0557915a030a383d6b866476bbc3e71"
216216
dependencies = [
217-
"object",
217+
"object 0.32.2",
218218
]
219219

220220
[[package]]
@@ -281,7 +281,7 @@ dependencies = [
281281
"cfg-if",
282282
"libc",
283283
"miniz_oxide",
284-
"object",
284+
"object 0.32.2",
285285
"rustc-demangle",
286286
]
287287

@@ -2636,10 +2636,21 @@ dependencies = [
26362636
"memchr",
26372637
"rustc-std-workspace-alloc",
26382638
"rustc-std-workspace-core",
2639-
"ruzstd",
2639+
"ruzstd 0.5.0",
26402640
"wasmparser",
26412641
]
26422642

2643+
[[package]]
2644+
name = "object"
2645+
version = "0.34.0"
2646+
source = "registry+https://github.com/rust-lang/crates.io-index"
2647+
checksum = "d7090bae93f8585aad99e595b7073c5de9ba89fbd6b4e9f0cdd7a10177273ac8"
2648+
dependencies = [
2649+
"flate2",
2650+
"memchr",
2651+
"ruzstd 0.6.0",
2652+
]
2653+
26432654
[[package]]
26442655
name = "odht"
26452656
version = "0.3.1"
@@ -3323,6 +3334,7 @@ dependencies = [
33233334
name = "run_make_support"
33243335
version = "0.0.0"
33253336
dependencies = [
3337+
"object 0.34.0",
33263338
"wasmparser",
33273339
]
33283340

@@ -3634,7 +3646,7 @@ dependencies = [
36343646
"itertools 0.12.1",
36353647
"libc",
36363648
"measureme",
3637-
"object",
3649+
"object 0.32.2",
36383650
"rustc-demangle",
36393651
"rustc_ast",
36403652
"rustc_attr",
@@ -3670,7 +3682,7 @@ dependencies = [
36703682
"itertools 0.12.1",
36713683
"jobserver",
36723684
"libc",
3673-
"object",
3685+
"object 0.32.2",
36743686
"pathdiff",
36753687
"regex",
36763688
"rustc_arena",
@@ -3686,6 +3698,7 @@ dependencies = [
36863698
"rustc_macros",
36873699
"rustc_metadata",
36883700
"rustc_middle",
3701+
"rustc_monomorphize",
36893702
"rustc_query_system",
36903703
"rustc_serialize",
36913704
"rustc_session",
@@ -4630,7 +4643,7 @@ name = "rustc_target"
46304643
version = "0.0.0"
46314644
dependencies = [
46324645
"bitflags 2.4.2",
4633-
"object",
4646+
"object 0.32.2",
46344647
"rustc_abi",
46354648
"rustc_data_structures",
46364649
"rustc_feature",
@@ -4897,6 +4910,17 @@ dependencies = [
48974910
"twox-hash",
48984911
]
48994912

4913+
[[package]]
4914+
name = "ruzstd"
4915+
version = "0.6.0"
4916+
source = "registry+https://github.com/rust-lang/crates.io-index"
4917+
checksum = "5174a470eeb535a721ae9fdd6e291c2411a906b96592182d05217591d5c5cf7b"
4918+
dependencies = [
4919+
"byteorder",
4920+
"derive_more",
4921+
"twox-hash",
4922+
]
4923+
49004924
[[package]]
49014925
name = "ryu"
49024926
version = "1.0.17"
@@ -5200,7 +5224,7 @@ dependencies = [
52005224
"hermit-abi",
52015225
"libc",
52025226
"miniz_oxide",
5203-
"object",
5227+
"object 0.32.2",
52045228
"panic_abort",
52055229
"panic_unwind",
52065230
"profiler_builtins",
@@ -5517,7 +5541,7 @@ checksum = "4db52ee8fec06e119b692ef3dd2c4cf621a99204c1b8c47407870ed050305b9b"
55175541
dependencies = [
55185542
"gimli",
55195543
"hashbrown",
5520-
"object",
5544+
"object 0.32.2",
55215545
"tracing",
55225546
]
55235547

Cargo.toml

-9
Original file line numberDiff line numberDiff line change
@@ -66,15 +66,6 @@ exclude = [
6666
]
6767

6868
[profile.release.package.compiler_builtins]
69-
# The compiler-builtins crate cannot reference libcore, and its own CI will
70-
# verify that this is the case. This requires, however, that the crate is built
71-
# without overflow checks and debug assertions. Forcefully disable debug
72-
# assertions and overflow checks here which should ensure that even if these
73-
# assertions are enabled for libstd we won't enable them for compiler_builtins
74-
# which should ensure we still link everything correctly.
75-
debug-assertions = false
76-
overflow-checks = false
77-
7869
# For compiler-builtins we always use a high number of codegen units.
7970
# The goal here is to place every single intrinsic into its own object
8071
# file to avoid symbol clashes with the system libgcc if possible. Note

compiler/rustc_codegen_cranelift/src/abi/mod.rs

+14
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,11 @@ use std::borrow::Cow;
88

99
use cranelift_codegen::ir::SigRef;
1010
use cranelift_module::ModuleError;
11+
use rustc_codegen_ssa::errors::CompilerBuiltinsCannotCall;
1112
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
1213
use rustc_middle::ty::layout::FnAbiOf;
14+
use rustc_middle::ty::print::with_no_trimmed_paths;
15+
use rustc_monomorphize::is_call_from_compiler_builtins_to_upstream_monomorphization;
1316
use rustc_session::Session;
1417
use rustc_span::source_map::Spanned;
1518
use rustc_target::abi::call::{Conv, FnAbi};
@@ -372,6 +375,17 @@ pub(crate) fn codegen_terminator_call<'tcx>(
372375
ty::Instance::expect_resolve(fx.tcx, ty::ParamEnv::reveal_all(), def_id, fn_args)
373376
.polymorphize(fx.tcx);
374377

378+
if is_call_from_compiler_builtins_to_upstream_monomorphization(fx.tcx, instance) {
379+
if target.is_some() {
380+
let caller = with_no_trimmed_paths!(fx.tcx.def_path_str(fx.instance.def_id()));
381+
let callee = with_no_trimmed_paths!(fx.tcx.def_path_str(def_id));
382+
fx.tcx.dcx().emit_err(CompilerBuiltinsCannotCall { caller, callee });
383+
} else {
384+
fx.bcx.ins().trap(TrapCode::User(0));
385+
return;
386+
}
387+
}
388+
375389
if fx.tcx.symbol_name(instance).name.starts_with("llvm.") {
376390
crate::intrinsics::codegen_llvm_intrinsic_call(
377391
fx,

compiler/rustc_codegen_cranelift/src/base.rs

+7
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use rustc_index::IndexVec;
88
use rustc_middle::ty::adjustment::PointerCoercion;
99
use rustc_middle::ty::layout::FnAbiOf;
1010
use rustc_middle::ty::print::with_no_trimmed_paths;
11+
use rustc_monomorphize::is_call_from_compiler_builtins_to_upstream_monomorphization;
1112

1213
use crate::constant::ConstantCx;
1314
use crate::debuginfo::FunctionDebugContext;
@@ -999,6 +1000,12 @@ fn codegen_panic_inner<'tcx>(
9991000
let def_id = fx.tcx.require_lang_item(lang_item, span);
10001001

10011002
let instance = Instance::mono(fx.tcx, def_id).polymorphize(fx.tcx);
1003+
1004+
if is_call_from_compiler_builtins_to_upstream_monomorphization(fx.tcx, instance) {
1005+
fx.bcx.ins().trap(TrapCode::User(0));
1006+
return;
1007+
}
1008+
10021009
let symbol_name = fx.tcx.symbol_name(instance).name;
10031010

10041011
fx.lib_call(

compiler/rustc_codegen_cranelift/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ extern crate rustc_hir;
2121
extern crate rustc_incremental;
2222
extern crate rustc_index;
2323
extern crate rustc_metadata;
24+
extern crate rustc_monomorphize;
2425
extern crate rustc_session;
2526
extern crate rustc_span;
2627
extern crate rustc_target;

compiler/rustc_codegen_ssa/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ rustc_index = { path = "../rustc_index" }
2525
rustc_macros = { path = "../rustc_macros" }
2626
rustc_metadata = { path = "../rustc_metadata" }
2727
rustc_middle = { path = "../rustc_middle" }
28+
rustc_monomorphize = { path = "../rustc_monomorphize" }
2829
rustc_query_system = { path = "../rustc_query_system" }
2930
rustc_serialize = { path = "../rustc_serialize" }
3031
rustc_session = { path = "../rustc_session" }

compiler/rustc_codegen_ssa/messages.ftl

+3
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ codegen_ssa_cgu_not_recorded =
1616
1717
codegen_ssa_check_installed_visual_studio = please ensure that Visual Studio 2017 or later, or Build Tools for Visual Studio were installed with the Visual C++ option.
1818
19+
codegen_ssa_compiler_builtins_cannot_call =
20+
`compiler_builtins` cannot call functions through upstream monomorphizations; encountered invalid call from `{$caller}` to `{$callee}`
21+
1922
codegen_ssa_copy_path = could not copy {$from} to {$to}: {$error}
2023
2124
codegen_ssa_copy_path_buf = unable to copy {$source_file} to {$output_path}: {$error}

compiler/rustc_codegen_ssa/src/common.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
use rustc_hir::LangItem;
44
use rustc_middle::mir;
5+
use rustc_middle::ty::Instance;
56
use rustc_middle::ty::{self, layout::TyAndLayout, Ty, TyCtxt};
67
use rustc_span::Span;
78

@@ -120,11 +121,11 @@ pub fn build_langcall<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
120121
bx: &Bx,
121122
span: Option<Span>,
122123
li: LangItem,
123-
) -> (Bx::FnAbiOfResult, Bx::Value) {
124+
) -> (Bx::FnAbiOfResult, Bx::Value, Instance<'tcx>) {
124125
let tcx = bx.tcx();
125126
let def_id = tcx.require_lang_item(li, span);
126127
let instance = ty::Instance::mono(tcx, def_id);
127-
(bx.fn_abi_of_instance(instance, ty::List::empty()), bx.get_fn_addr(instance))
128+
(bx.fn_abi_of_instance(instance, ty::List::empty()), bx.get_fn_addr(instance), instance)
128129
}
129130

130131
// To avoid UB from LLVM, these two functions mask RHS with an

compiler/rustc_codegen_ssa/src/errors.rs

+7
Original file line numberDiff line numberDiff line change
@@ -1030,3 +1030,10 @@ pub struct FailedToGetLayout<'tcx> {
10301030
pub struct ErrorCreatingRemarkDir {
10311031
pub error: std::io::Error,
10321032
}
1033+
1034+
#[derive(Diagnostic)]
1035+
#[diag(codegen_ssa_compiler_builtins_cannot_call)]
1036+
pub struct CompilerBuiltinsCannotCall {
1037+
pub caller: String,
1038+
pub callee: String,
1039+
}

compiler/rustc_codegen_ssa/src/mir/block.rs

+41-8
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use super::{CachedLlbb, FunctionCx, LocalRef};
55

66
use crate::base;
77
use crate::common::{self, IntPredicate};
8+
use crate::errors::CompilerBuiltinsCannotCall;
89
use crate::meth;
910
use crate::traits::*;
1011
use crate::MemFlags;
@@ -16,6 +17,7 @@ use rustc_middle::mir::{self, AssertKind, BasicBlock, SwitchTargets, UnwindTermi
1617
use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, ValidityRequirement};
1718
use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths};
1819
use rustc_middle::ty::{self, Instance, Ty};
20+
use rustc_monomorphize::is_call_from_compiler_builtins_to_upstream_monomorphization;
1921
use rustc_session::config::OptLevel;
2022
use rustc_span::{source_map::Spanned, sym, Span};
2123
use rustc_target::abi::call::{ArgAbi, FnAbi, PassMode, Reg};
@@ -157,8 +159,28 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
157159
destination: Option<(ReturnDest<'tcx, Bx::Value>, mir::BasicBlock)>,
158160
mut unwind: mir::UnwindAction,
159161
copied_constant_arguments: &[PlaceRef<'tcx, <Bx as BackendTypes>::Value>],
162+
instance: Option<Instance<'tcx>>,
160163
mergeable_succ: bool,
161164
) -> MergingSucc {
165+
let tcx = bx.tcx();
166+
if let Some(instance) = instance {
167+
if is_call_from_compiler_builtins_to_upstream_monomorphization(tcx, instance) {
168+
if destination.is_some() {
169+
let caller = with_no_trimmed_paths!(tcx.def_path_str(fx.instance.def_id()));
170+
let callee = with_no_trimmed_paths!(tcx.def_path_str(instance.def_id()));
171+
tcx.dcx().emit_err(CompilerBuiltinsCannotCall { caller, callee });
172+
} else {
173+
info!(
174+
"compiler_builtins call to diverging function {:?} replaced with abort",
175+
instance.def_id()
176+
);
177+
bx.abort();
178+
bx.unreachable();
179+
return MergingSucc::False;
180+
}
181+
}
182+
}
183+
162184
// If there is a cleanup block and the function we're calling can unwind, then
163185
// do an invoke, otherwise do a call.
164186
let fn_ty = bx.fn_decl_backend_type(fn_abi);
@@ -480,6 +502,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
480502
let ty = location.ty(self.mir, bx.tcx()).ty;
481503
let ty = self.monomorphize(ty);
482504
let drop_fn = Instance::resolve_drop_in_place(bx.tcx(), ty);
505+
let instance = drop_fn.clone();
483506

484507
if let ty::InstanceDef::DropGlue(_, None) = drop_fn.def {
485508
// we don't actually need to drop anything.
@@ -582,6 +605,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
582605
Some((ReturnDest::Nothing, target)),
583606
unwind,
584607
&[],
608+
Some(instance),
585609
mergeable_succ,
586610
)
587611
}
@@ -658,10 +682,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
658682
}
659683
};
660684

661-
let (fn_abi, llfn) = common::build_langcall(bx, Some(span), lang_item);
685+
let (fn_abi, llfn, instance) = common::build_langcall(bx, Some(span), lang_item);
662686

663687
// Codegen the actual panic invoke/call.
664-
let merging_succ = helper.do_call(self, bx, fn_abi, llfn, &args, None, unwind, &[], false);
688+
let merging_succ =
689+
helper.do_call(self, bx, fn_abi, llfn, &args, None, unwind, &[], Some(instance), false);
665690
assert_eq!(merging_succ, MergingSucc::False);
666691
MergingSucc::False
667692
}
@@ -677,7 +702,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
677702
self.set_debug_loc(bx, terminator.source_info);
678703

679704
// Obtain the panic entry point.
680-
let (fn_abi, llfn) = common::build_langcall(bx, Some(span), reason.lang_item());
705+
let (fn_abi, llfn, instance) = common::build_langcall(bx, Some(span), reason.lang_item());
681706

682707
// Codegen the actual panic invoke/call.
683708
let merging_succ = helper.do_call(
@@ -689,6 +714,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
689714
None,
690715
mir::UnwindAction::Unreachable,
691716
&[],
717+
Some(instance),
692718
false,
693719
);
694720
assert_eq!(merging_succ, MergingSucc::False);
@@ -738,7 +764,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
738764
let msg = bx.const_str(&msg_str);
739765

740766
// Obtain the panic entry point.
741-
let (fn_abi, llfn) =
767+
let (fn_abi, llfn, instance) =
742768
common::build_langcall(bx, Some(source_info.span), LangItem::PanicNounwind);
743769

744770
// Codegen the actual panic invoke/call.
@@ -751,6 +777,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
751777
target.as_ref().map(|bb| (ReturnDest::Nothing, *bb)),
752778
unwind,
753779
&[],
780+
Some(instance),
754781
mergeable_succ,
755782
)
756783
} else {
@@ -798,6 +825,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
798825
ty::FnPtr(_) => (None, Some(callee.immediate())),
799826
_ => bug!("{} is not callable", callee.layout.ty),
800827
};
828+
801829
let def = instance.map(|i| i.def);
802830

803831
if let Some(ty::InstanceDef::DropGlue(_, None)) = def {
@@ -1106,6 +1134,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
11061134
destination,
11071135
unwind,
11081136
&copied_constant_arguments,
1137+
instance,
11091138
mergeable_succ,
11101139
)
11111140
}
@@ -1664,11 +1693,15 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
16641693

16651694
self.set_debug_loc(&mut bx, mir::SourceInfo::outermost(self.mir.span));
16661695

1667-
let (fn_abi, fn_ptr) = common::build_langcall(&bx, None, reason.lang_item());
1668-
let fn_ty = bx.fn_decl_backend_type(fn_abi);
1696+
let (fn_abi, fn_ptr, instance) = common::build_langcall(&bx, None, reason.lang_item());
1697+
if is_call_from_compiler_builtins_to_upstream_monomorphization(bx.tcx(), instance) {
1698+
bx.abort();
1699+
} else {
1700+
let fn_ty = bx.fn_decl_backend_type(fn_abi);
16691701

1670-
let llret = bx.call(fn_ty, None, Some(fn_abi), fn_ptr, &[], funclet.as_ref());
1671-
bx.apply_attrs_to_cleanup_callsite(llret);
1702+
let llret = bx.call(fn_ty, None, Some(fn_abi), fn_ptr, &[], funclet.as_ref());
1703+
bx.apply_attrs_to_cleanup_callsite(llret);
1704+
}
16721705

16731706
bx.unreachable();
16741707

0 commit comments

Comments
 (0)