Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 1a51663

Browse files
committedDec 20, 2024·
[WIP] Use weak linkage instead of compiler generated shims
This is still keeping the allocator shim for the oom handler and the __rust_no_alloc_shim_is_unstable symbol for now. TODO: Update comments everywhere and test on macOS and Windows
1 parent 3bf62cc commit 1a51663

File tree

15 files changed

+107
-245
lines changed

15 files changed

+107
-245
lines changed
 

‎compiler/rustc_ast/src/expand/allocator.rs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,6 @@ pub fn global_fn_name(base: Symbol) -> String {
1111
format!("__rust_{base}")
1212
}
1313

14-
pub fn default_fn_name(base: Symbol) -> String {
15-
format!("__rdl_{base}")
16-
}
17-
1814
pub fn alloc_error_handler_name(alloc_error_handler_kind: AllocatorKind) -> &'static str {
1915
match alloc_error_handler_kind {
2016
AllocatorKind::Global => "__rg_oom",

‎compiler/rustc_codegen_cranelift/src/allocator.rs

Lines changed: 12 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -2,72 +2,34 @@
22
// Adapted from rustc
33

44
use rustc_ast::expand::allocator::{
5-
ALLOCATOR_METHODS, AllocatorKind, AllocatorTy, NO_ALLOC_SHIM_IS_UNSTABLE,
6-
alloc_error_handler_name, default_fn_name, global_fn_name,
5+
AllocatorKind, NO_ALLOC_SHIM_IS_UNSTABLE, alloc_error_handler_name,
76
};
8-
use rustc_codegen_ssa::base::allocator_kind_for_codegen;
7+
use rustc_codegen_ssa::base::needs_allocator_shim;
98
use rustc_session::config::OomStrategy;
109

1110
use crate::prelude::*;
1211

1312
/// Returns whether an allocator shim was created
1413
pub(crate) fn codegen(tcx: TyCtxt<'_>, module: &mut dyn Module) -> bool {
15-
let Some(kind) = allocator_kind_for_codegen(tcx) else { return false };
16-
codegen_inner(
17-
module,
18-
kind,
19-
tcx.alloc_error_handler_kind(()).unwrap(),
20-
tcx.sess.opts.unstable_opts.oom,
21-
);
22-
true
14+
if needs_allocator_shim(tcx) {
15+
codegen_inner(
16+
module,
17+
tcx.alloc_error_handler_kind(()).unwrap(),
18+
tcx.sess.opts.unstable_opts.oom,
19+
);
20+
true
21+
} else {
22+
false
23+
}
2324
}
2425

2526
fn codegen_inner(
2627
module: &mut dyn Module,
27-
kind: AllocatorKind,
2828
alloc_error_handler_kind: AllocatorKind,
2929
oom_strategy: OomStrategy,
3030
) {
3131
let usize_ty = module.target_config().pointer_type();
3232

33-
if kind == AllocatorKind::Default {
34-
for method in ALLOCATOR_METHODS {
35-
let mut arg_tys = Vec::with_capacity(method.inputs.len());
36-
for input in method.inputs.iter() {
37-
match input.ty {
38-
AllocatorTy::Layout => {
39-
arg_tys.push(usize_ty); // size
40-
arg_tys.push(usize_ty); // align
41-
}
42-
AllocatorTy::Ptr => arg_tys.push(usize_ty),
43-
AllocatorTy::Usize => arg_tys.push(usize_ty),
44-
45-
AllocatorTy::ResultPtr | AllocatorTy::Unit => panic!("invalid allocator arg"),
46-
}
47-
}
48-
let output = match method.output {
49-
AllocatorTy::ResultPtr => Some(usize_ty),
50-
AllocatorTy::Unit => None,
51-
52-
AllocatorTy::Layout | AllocatorTy::Usize | AllocatorTy::Ptr => {
53-
panic!("invalid allocator output")
54-
}
55-
};
56-
57-
let sig = Signature {
58-
call_conv: module.target_config().default_call_conv,
59-
params: arg_tys.iter().cloned().map(AbiParam::new).collect(),
60-
returns: output.into_iter().map(AbiParam::new).collect(),
61-
};
62-
crate::common::create_wrapper_function(
63-
module,
64-
sig,
65-
&global_fn_name(method.name),
66-
&default_fn_name(method.name),
67-
);
68-
}
69-
}
70-
7133
let sig = Signature {
7234
call_conv: module.target_config().default_call_conv,
7335
params: vec![AbiParam::new(usize_ty), AbiParam::new(usize_ty)],

‎compiler/rustc_codegen_gcc/src/allocator.rs

Lines changed: 1 addition & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@
22
use gccjit::FnAttribute;
33
use gccjit::{Context, FunctionType, GlobalKind, ToRValue, Type};
44
use rustc_ast::expand::allocator::{
5-
ALLOCATOR_METHODS, AllocatorKind, AllocatorTy, NO_ALLOC_SHIM_IS_UNSTABLE,
6-
alloc_error_handler_name, default_fn_name, global_fn_name,
5+
AllocatorKind, NO_ALLOC_SHIM_IS_UNSTABLE, alloc_error_handler_name,
76
};
87
use rustc_middle::bug;
98
use rustc_middle::ty::TyCtxt;
@@ -15,7 +14,6 @@ pub(crate) unsafe fn codegen(
1514
tcx: TyCtxt<'_>,
1615
mods: &mut GccContext,
1716
_module_name: &str,
18-
kind: AllocatorKind,
1917
alloc_error_handler_kind: AllocatorKind,
2018
) {
2119
let context = &mods.context;
@@ -26,37 +24,6 @@ pub(crate) unsafe fn codegen(
2624
tws => bug!("Unsupported target word size for int: {}", tws),
2725
};
2826
let i8 = context.new_type::<i8>();
29-
let i8p = i8.make_pointer();
30-
31-
if kind == AllocatorKind::Default {
32-
for method in ALLOCATOR_METHODS {
33-
let mut types = Vec::with_capacity(method.inputs.len());
34-
for input in method.inputs.iter() {
35-
match input.ty {
36-
AllocatorTy::Layout => {
37-
types.push(usize);
38-
types.push(usize);
39-
}
40-
AllocatorTy::Ptr => types.push(i8p),
41-
AllocatorTy::Usize => types.push(usize),
42-
43-
AllocatorTy::ResultPtr | AllocatorTy::Unit => panic!("invalid allocator arg"),
44-
}
45-
}
46-
let output = match method.output {
47-
AllocatorTy::ResultPtr => Some(i8p),
48-
AllocatorTy::Unit => None,
49-
50-
AllocatorTy::Layout | AllocatorTy::Usize | AllocatorTy::Ptr => {
51-
panic!("invalid allocator output")
52-
}
53-
};
54-
let from_name = global_fn_name(method.name);
55-
let to_name = default_fn_name(method.name);
56-
57-
create_wrapper_function(tcx, context, &from_name, &to_name, &types, output);
58-
}
59-
}
6027

6128
// FIXME(bjorn3): Add noreturn attribute
6229
create_wrapper_function(

‎compiler/rustc_codegen_gcc/src/lib.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -291,7 +291,6 @@ impl ExtraBackendMethods for GccCodegenBackend {
291291
&self,
292292
tcx: TyCtxt<'_>,
293293
module_name: &str,
294-
kind: AllocatorKind,
295294
alloc_error_handler_kind: AllocatorKind,
296295
) -> Self::Module {
297296
let mut mods = GccContext {
@@ -301,7 +300,7 @@ impl ExtraBackendMethods for GccCodegenBackend {
301300
};
302301

303302
unsafe {
304-
allocator::codegen(tcx, &mut mods, module_name, kind, alloc_error_handler_kind);
303+
allocator::codegen(tcx, &mut mods, module_name, alloc_error_handler_kind);
305304
}
306305
mods
307306
}

‎compiler/rustc_codegen_llvm/src/allocator.rs

Lines changed: 1 addition & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
use libc::c_uint;
22
use rustc_ast::expand::allocator::{
3-
ALLOCATOR_METHODS, AllocatorKind, AllocatorTy, NO_ALLOC_SHIM_IS_UNSTABLE,
4-
alloc_error_handler_name, default_fn_name, global_fn_name,
3+
AllocatorKind, NO_ALLOC_SHIM_IS_UNSTABLE, alloc_error_handler_name,
54
};
65
use rustc_middle::bug;
76
use rustc_middle::ty::TyCtxt;
@@ -15,7 +14,6 @@ pub(crate) unsafe fn codegen(
1514
tcx: TyCtxt<'_>,
1615
module_llvm: &mut ModuleLlvm,
1716
module_name: &str,
18-
kind: AllocatorKind,
1917
alloc_error_handler_kind: AllocatorKind,
2018
) {
2119
let llcx = &*module_llvm.llcx;
@@ -29,38 +27,6 @@ pub(crate) unsafe fn codegen(
2927
}
3028
};
3129
let i8 = unsafe { llvm::LLVMInt8TypeInContext(llcx) };
32-
let i8p = unsafe { llvm::LLVMPointerTypeInContext(llcx, 0) };
33-
34-
if kind == AllocatorKind::Default {
35-
for method in ALLOCATOR_METHODS {
36-
let mut args = Vec::with_capacity(method.inputs.len());
37-
for input in method.inputs.iter() {
38-
match input.ty {
39-
AllocatorTy::Layout => {
40-
args.push(usize); // size
41-
args.push(usize); // align
42-
}
43-
AllocatorTy::Ptr => args.push(i8p),
44-
AllocatorTy::Usize => args.push(usize),
45-
46-
AllocatorTy::ResultPtr | AllocatorTy::Unit => panic!("invalid allocator arg"),
47-
}
48-
}
49-
let output = match method.output {
50-
AllocatorTy::ResultPtr => Some(i8p),
51-
AllocatorTy::Unit => None,
52-
53-
AllocatorTy::Layout | AllocatorTy::Usize | AllocatorTy::Ptr => {
54-
panic!("invalid allocator output")
55-
}
56-
};
57-
58-
let from_name = global_fn_name(method.name);
59-
let to_name = default_fn_name(method.name);
60-
61-
create_wrapper_function(tcx, llcx, llmod, &from_name, &to_name, &args, output, false);
62-
}
63-
}
6430

6531
// rust alloc error handler
6632
create_wrapper_function(

‎compiler/rustc_codegen_llvm/src/lib.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,12 +114,11 @@ impl ExtraBackendMethods for LlvmCodegenBackend {
114114
&self,
115115
tcx: TyCtxt<'tcx>,
116116
module_name: &str,
117-
kind: AllocatorKind,
118117
alloc_error_handler_kind: AllocatorKind,
119118
) -> ModuleLlvm {
120119
let mut module_llvm = ModuleLlvm::new_metadata(tcx, module_name);
121120
unsafe {
122-
allocator::codegen(tcx, &mut module_llvm, module_name, kind, alloc_error_handler_kind);
121+
allocator::codegen(tcx, &mut module_llvm, module_name, alloc_error_handler_kind);
123122
}
124123
module_llvm
125124
}

‎compiler/rustc_codegen_ssa/src/back/symbol_export.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use rustc_session::config::{CrateType, OomStrategy};
1616
use rustc_target::spec::{SanitizerSet, TlsModel};
1717
use tracing::debug;
1818

19-
use crate::base::allocator_kind_for_codegen;
19+
use crate::base::needs_allocator_shim;
2020

2121
fn threshold(tcx: TyCtxt<'_>) -> SymbolExportLevel {
2222
crates_export_threshold(tcx.crate_types())
@@ -206,7 +206,7 @@ fn exported_symbols_provider_local(
206206
}
207207

208208
// Mark allocator shim symbols as exported only if they were generated.
209-
if allocator_kind_for_codegen(tcx).is_some() {
209+
if needs_allocator_shim(tcx) {
210210
for symbol_name in ALLOCATOR_METHODS
211211
.iter()
212212
.map(|method| format!("__rust_{}", method.name))

‎compiler/rustc_codegen_ssa/src/base.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use std::time::{Duration, Instant};
44

55
use itertools::Itertools;
66
use rustc_abi::FIRST_VARIANT;
7-
use rustc_ast::expand::allocator::{ALLOCATOR_METHODS, AllocatorKind, global_fn_name};
7+
use rustc_ast::expand::allocator::{ALLOCATOR_METHODS, global_fn_name};
88
use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
99
use rustc_data_structures::profiling::{get_resident_set_size, print_time_passes_entry};
1010
use rustc_data_structures::sync::{Lrc, par_map};
@@ -584,7 +584,7 @@ pub fn collect_debugger_visualizers_transitive(
584584
/// Decide allocator kind to codegen. If `Some(_)` this will be the same as
585585
/// `tcx.allocator_kind`, but it may be `None` in more cases (e.g. if using
586586
/// allocator definitions from a dylib dependency).
587-
pub fn allocator_kind_for_codegen(tcx: TyCtxt<'_>) -> Option<AllocatorKind> {
587+
pub fn needs_allocator_shim(tcx: TyCtxt<'_>) -> bool {
588588
// If the crate doesn't have an `allocator_kind` set then there's definitely
589589
// no shim to generate. Otherwise we also check our dependency graph for all
590590
// our output crate types. If anything there looks like its a `Dynamic`
@@ -595,7 +595,7 @@ pub fn allocator_kind_for_codegen(tcx: TyCtxt<'_>) -> Option<AllocatorKind> {
595595
use rustc_middle::middle::dependency_format::Linkage;
596596
list.iter().any(|&linkage| linkage == Linkage::Dynamic)
597597
});
598-
if any_dynamic_crate { None } else { tcx.allocator_kind(()) }
598+
if any_dynamic_crate { false } else { tcx.allocator_kind(()).is_some() }
599599
}
600600

601601
pub fn codegen_crate<B: ExtraBackendMethods>(
@@ -664,14 +664,13 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
664664
start_async_codegen(backend.clone(), tcx, target_cpu, metadata, metadata_module);
665665

666666
// Codegen an allocator shim, if necessary.
667-
if let Some(kind) = allocator_kind_for_codegen(tcx) {
667+
if needs_allocator_shim(tcx) {
668668
let llmod_id =
669669
cgu_name_builder.build_cgu_name(LOCAL_CRATE, &["crate"], Some("allocator")).to_string();
670670
let module_llvm = tcx.sess.time("write_allocator_module", || {
671671
backend.codegen_allocator(
672672
tcx,
673673
&llmod_id,
674-
kind,
675674
// If allocator_kind is Some then alloc_error_handler_kind must
676675
// also be Some.
677676
tcx.alloc_error_handler_kind(()).unwrap(),

‎compiler/rustc_codegen_ssa/src/traits/backend.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,6 @@ pub trait ExtraBackendMethods:
104104
&self,
105105
tcx: TyCtxt<'tcx>,
106106
module_name: &str,
107-
kind: AllocatorKind,
108107
alloc_error_handler_kind: AllocatorKind,
109108
) -> Self::Module;
110109

‎compiler/rustc_metadata/src/creader.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1127,6 +1127,8 @@ fn global_allocator_spans(krate: &ast::Crate) -> Vec<Span> {
11271127
fn visit_item(&mut self, item: &'ast ast::Item) {
11281128
if item.ident.name == self.name
11291129
&& attr::contains_name(&item.attrs, sym::rustc_std_internal_symbol)
1130+
// Ignore the default allocator in libstd with weak linkage
1131+
&& attr::find_by_name(&item.attrs, sym::linkage).is_none()
11301132
{
11311133
self.spans.push(item.span);
11321134
}

‎compiler/rustc_monomorphize/src/partitioning.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -887,6 +887,7 @@ fn mono_item_visibility<'tcx>(
887887
// Removal of these functions can't be done by LLVM but rather must be
888888
// done by the linker as it's a non-local decision.
889889
//
890+
// FIXME update comment
890891
// * Second is "std internal symbols". Currently this is primarily used
891892
// for allocator symbols. Allocators are a little weird in their
892893
// implementation, but the idea is that the compiler, at the last

‎library/alloc/src/alloc.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ extern "Rust" {
1414
// These are the magic symbols to call the global allocator. rustc generates
1515
// them to call `__rg_alloc` etc. if there is a `#[global_allocator]` attribute
1616
// (the code expanding that attribute macro generates those functions), or to call
17-
// the default implementations in std (`__rdl_alloc` etc. in `library/std/src/alloc.rs`)
17+
// the default implementations in std (weak symbols in `library/std/src/alloc.rs`)
1818
// otherwise.
1919
// The rustc fork of LLVM 14 and earlier also special-cases these function names to be able to optimize them
2020
// like `malloc`, `realloc`, and `free`, respectively.

‎library/std/src/alloc.rs

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -382,9 +382,8 @@ pub fn rust_oom(layout: Layout) -> ! {
382382
#[unstable(feature = "alloc_internals", issue = "none")]
383383
pub mod __default_lib_allocator {
384384
use super::{GlobalAlloc, Layout, System};
385-
// These magic symbol names are used as a fallback for implementing the
386-
// `__rust_alloc` etc symbols (see `src/liballoc/alloc.rs`) when there is
387-
// no `#[global_allocator]` attribute.
385+
// These are used as a fallback for implementing the `__rust_alloc`, etc symbols
386+
// (see `src/liballoc/alloc.rs`) when there is no `#[global_allocator]` attribute.
388387

389388
// for symbol names src/librustc_ast/expand/allocator.rs
390389
// for signatures src/librustc_allocator/lib.rs
@@ -393,7 +392,8 @@ pub mod __default_lib_allocator {
393392
// ABI
394393

395394
#[rustc_std_internal_symbol]
396-
pub unsafe extern "C" fn __rdl_alloc(size: usize, align: usize) -> *mut u8 {
395+
#[linkage = "weak"]
396+
pub unsafe extern "Rust" fn __rust_alloc(size: usize, align: usize) -> *mut u8 {
397397
// SAFETY: see the guarantees expected by `Layout::from_size_align` and
398398
// `GlobalAlloc::alloc`.
399399
unsafe {
@@ -403,14 +403,16 @@ pub mod __default_lib_allocator {
403403
}
404404

405405
#[rustc_std_internal_symbol]
406-
pub unsafe extern "C" fn __rdl_dealloc(ptr: *mut u8, size: usize, align: usize) {
406+
#[linkage = "weak"]
407+
pub unsafe extern "Rust" fn __rust_dealloc(ptr: *mut u8, size: usize, align: usize) {
407408
// SAFETY: see the guarantees expected by `Layout::from_size_align` and
408409
// `GlobalAlloc::dealloc`.
409410
unsafe { System.dealloc(ptr, Layout::from_size_align_unchecked(size, align)) }
410411
}
411412

412413
#[rustc_std_internal_symbol]
413-
pub unsafe extern "C" fn __rdl_realloc(
414+
#[linkage = "weak"]
415+
pub unsafe extern "Rust" fn __rust_realloc(
414416
ptr: *mut u8,
415417
old_size: usize,
416418
align: usize,
@@ -425,7 +427,8 @@ pub mod __default_lib_allocator {
425427
}
426428

427429
#[rustc_std_internal_symbol]
428-
pub unsafe extern "C" fn __rdl_alloc_zeroed(size: usize, align: usize) -> *mut u8 {
430+
#[linkage = "weak"]
431+
pub unsafe extern "Rust" fn __rust_alloc_zeroed(size: usize, align: usize) -> *mut u8 {
429432
// SAFETY: see the guarantees expected by `Layout::from_size_align` and
430433
// `GlobalAlloc::alloc_zeroed`.
431434
unsafe {

‎src/tools/miri/src/shims/alloc.rs

Lines changed: 7 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
use std::iter;
22

33
use rustc_abi::{Align, Size};
4-
use rustc_ast::expand::allocator::AllocatorKind;
54

65
use crate::*;
76

@@ -53,31 +52,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
5352
}
5453

5554
/// Emulates calling the internal __rust_* allocator functions
56-
fn emulate_allocator(
57-
&mut self,
58-
default: impl FnOnce(&mut MiriInterpCx<'tcx>) -> InterpResult<'tcx>,
59-
) -> InterpResult<'tcx, EmulateItemResult> {
60-
let this = self.eval_context_mut();
61-
62-
let Some(allocator_kind) = this.tcx.allocator_kind(()) else {
63-
// in real code, this symbol does not exist without an allocator
64-
return interp_ok(EmulateItemResult::NotSupported);
65-
};
66-
67-
match allocator_kind {
68-
AllocatorKind::Global => {
69-
// When `#[global_allocator]` is used, `__rust_*` is defined by the macro expansion
70-
// of this attribute. As such we have to call an exported Rust function,
71-
// and not execute any Miri shim. Somewhat unintuitively doing so is done
72-
// by returning `NotSupported`, which triggers the `lookup_exported_symbol`
73-
// fallback case in `emulate_foreign_item`.
74-
interp_ok(EmulateItemResult::NotSupported)
75-
}
76-
AllocatorKind::Default => {
77-
default(this)?;
78-
interp_ok(EmulateItemResult::NeedsReturn)
79-
}
80-
}
55+
fn emulate_allocator(&mut self) -> InterpResult<'tcx, EmulateItemResult> {
56+
// When `#[global_allocator]` is used, `__rust_*` is defined by the macro expansion
57+
// of this attribute. As such we have to call an exported Rust function,
58+
// and not execute any Miri shim. Somewhat unintuitively doing so is done
59+
// by returning `NotSupported`, which triggers the `lookup_exported_symbol`
60+
// fallback case in `emulate_foreign_item`.
61+
interp_ok(EmulateItemResult::NotSupported)
8162
}
8263

8364
fn malloc(&mut self, size: u64, zero_init: bool) -> InterpResult<'tcx, Pointer> {

‎src/tools/miri/src/shims/foreign_items.rs

Lines changed: 64 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
use std::collections::hash_map::Entry;
22
use std::io::Write;
3-
use std::iter;
43
use std::path::Path;
54

65
use rustc_abi::{Align, AlignFromBytesError, ExternAbi, Size};
@@ -9,6 +8,7 @@ use rustc_ast::expand::allocator::alloc_error_handler_name;
98
use rustc_hir::def::DefKind;
109
use rustc_hir::def_id::CrateNum;
1110
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
11+
use rustc_middle::mir::mono::Linkage;
1212
use rustc_middle::{mir, ty};
1313
use rustc_span::Symbol;
1414

@@ -132,7 +132,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
132132
Entry::Occupied(e) => e.into_mut(),
133133
Entry::Vacant(e) => {
134134
// Find it if it was not cached.
135-
let mut instance_and_crate: Option<(ty::Instance<'_>, CrateNum)> = None;
135+
let mut instance_and_crate: Option<(ty::Instance<'_>, CrateNum, bool)> = None;
136136
helpers::iter_exported_symbols(tcx, |cnum, def_id| {
137137
let attrs = tcx.codegen_fn_attrs(def_id);
138138
let symbol_name = if let Some(export_name) = attrs.export_name {
@@ -143,39 +143,71 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
143143
// Skip over items without an explicitly defined symbol name.
144144
return interp_ok(());
145145
};
146+
let is_weak =
147+
attrs.linkage.map_or(false, |linkage| linkage == Linkage::WeakAny);
146148
if symbol_name == link_name {
147-
if let Some((original_instance, original_cnum)) = instance_and_crate {
148-
// Make sure we are consistent wrt what is 'first' and 'second'.
149-
let original_span = tcx.def_span(original_instance.def_id()).data();
150-
let span = tcx.def_span(def_id).data();
151-
if original_span < span {
152-
throw_machine_stop!(TerminationInfo::MultipleSymbolDefinitions {
153-
link_name,
154-
first: original_span,
155-
first_crate: tcx.crate_name(original_cnum),
156-
second: span,
157-
second_crate: tcx.crate_name(cnum),
158-
});
159-
} else {
160-
throw_machine_stop!(TerminationInfo::MultipleSymbolDefinitions {
161-
link_name,
162-
first: span,
163-
first_crate: tcx.crate_name(cnum),
164-
second: original_span,
165-
second_crate: tcx.crate_name(original_cnum),
166-
});
149+
if let Some((original_instance, original_cnum, original_is_weak)) =
150+
instance_and_crate
151+
{
152+
match (is_weak, original_is_weak) {
153+
(false, true) => {
154+
// Original definition is a weak definition. Override it.
155+
156+
instance_and_crate =
157+
Some((ty::Instance::mono(tcx, def_id), cnum, is_weak));
158+
}
159+
(true, false) => {
160+
// Current definition is a weak definition. Keep the original one.
161+
}
162+
(true, true) | (false, false) => {
163+
// Either both definitions are non-weak or both are weak. In
164+
// either case return an error. For weak definitions we error
165+
// because it is undefined which definition would have been
166+
// picked by the linker.
167+
168+
// Make sure we are consistent wrt what is 'first' and 'second'.
169+
let original_span =
170+
tcx.def_span(original_instance.def_id()).data();
171+
let span = tcx.def_span(def_id).data();
172+
if original_span < span {
173+
throw_machine_stop!(
174+
TerminationInfo::MultipleSymbolDefinitions {
175+
link_name,
176+
first: original_span,
177+
first_crate: tcx.crate_name(original_cnum),
178+
second: span,
179+
second_crate: tcx.crate_name(cnum),
180+
}
181+
);
182+
} else {
183+
throw_machine_stop!(
184+
TerminationInfo::MultipleSymbolDefinitions {
185+
link_name,
186+
first: span,
187+
first_crate: tcx.crate_name(cnum),
188+
second: original_span,
189+
second_crate: tcx.crate_name(original_cnum),
190+
}
191+
);
192+
}
193+
}
167194
}
195+
} else {
196+
instance_and_crate =
197+
Some((ty::Instance::mono(tcx, def_id), cnum, is_weak));
168198
}
169-
if !matches!(tcx.def_kind(def_id), DefKind::Fn | DefKind::AssocFn) {
170-
throw_ub_format!(
171-
"attempt to call an exported symbol that is not defined as a function"
172-
);
173-
}
174-
instance_and_crate = Some((ty::Instance::mono(tcx, def_id), cnum));
175199
}
176200
interp_ok(())
177201
})?;
178202

203+
if let Some((instance, _, _)) = instance_and_crate {
204+
if !matches!(tcx.def_kind(instance.def_id()), DefKind::Fn | DefKind::AssocFn) {
205+
throw_ub_format!(
206+
"attempt to call an exported symbol that is not defined as a function"
207+
);
208+
}
209+
}
210+
179211
e.insert(instance_and_crate.map(|ic| ic.0))
180212
}
181213
};
@@ -521,7 +553,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
521553
};
522554

523555
match link_name.as_str() {
524-
"__rust_alloc" => return this.emulate_allocator(default),
556+
"__rust_alloc" => return this.emulate_allocator(),
525557
"miri_alloc" => {
526558
default(this)?;
527559
return interp_ok(EmulateItemResult::NeedsReturn);
@@ -530,29 +562,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
530562
}
531563
}
532564
"__rust_alloc_zeroed" => {
533-
return this.emulate_allocator(|this| {
534-
// See the comment for `__rust_alloc` why `check_shim` is only called in the
535-
// default case.
536-
let [size, align] = this.check_shim(abi, ExternAbi::Rust, link_name, args)?;
537-
let size = this.read_target_usize(size)?;
538-
let align = this.read_target_usize(align)?;
539-
540-
this.check_rustc_alloc_request(size, align)?;
541-
542-
let ptr = this.allocate_ptr(
543-
Size::from_bytes(size),
544-
Align::from_bytes(align).unwrap(),
545-
MiriMemoryKind::Rust.into(),
546-
)?;
547-
548-
// We just allocated this, the access is definitely in-bounds.
549-
this.write_bytes_ptr(
550-
ptr.into(),
551-
iter::repeat(0u8).take(usize::try_from(size).unwrap()),
552-
)
553-
.unwrap();
554-
this.write_pointer(ptr, dest)
555-
});
565+
return this.emulate_allocator();
556566
}
557567
"__rust_dealloc" | "miri_dealloc" => {
558568
let default = |ecx: &mut MiriInterpCx<'tcx>| {
@@ -580,7 +590,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
580590

581591
match link_name.as_str() {
582592
"__rust_dealloc" => {
583-
return this.emulate_allocator(default);
593+
return this.emulate_allocator();
584594
}
585595
"miri_dealloc" => {
586596
default(this)?;
@@ -590,29 +600,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
590600
}
591601
}
592602
"__rust_realloc" => {
593-
return this.emulate_allocator(|this| {
594-
// See the comment for `__rust_alloc` why `check_shim` is only called in the
595-
// default case.
596-
let [ptr, old_size, align, new_size] =
597-
this.check_shim(abi, ExternAbi::Rust, link_name, args)?;
598-
let ptr = this.read_pointer(ptr)?;
599-
let old_size = this.read_target_usize(old_size)?;
600-
let align = this.read_target_usize(align)?;
601-
let new_size = this.read_target_usize(new_size)?;
602-
// No need to check old_size; we anyway check that they match the allocation.
603-
604-
this.check_rustc_alloc_request(new_size, align)?;
605-
606-
let align = Align::from_bytes(align).unwrap();
607-
let new_ptr = this.reallocate_ptr(
608-
ptr,
609-
Some((Size::from_bytes(old_size), align)),
610-
Size::from_bytes(new_size),
611-
align,
612-
MiriMemoryKind::Rust.into(),
613-
)?;
614-
this.write_pointer(new_ptr, dest)
615-
});
603+
return this.emulate_allocator();
616604
}
617605

618606
// C memory handling functions

0 commit comments

Comments
 (0)
Please sign in to comment.