Skip to content

Commit 222f5a0

Browse files
committed
Support weak definitions
When a symbol only has a weak definition, this definition will be picked. When a symbol has both a weak and a regular definition, the regular definition will be picked instead.
1 parent 0b76b73 commit 222f5a0

File tree

1 file changed

+59
-27
lines changed

1 file changed

+59
-27
lines changed

src/shims/foreign_items.rs

Lines changed: 59 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use rustc_hir::def::DefKind;
99
use rustc_hir::def_id::CrateNum;
1010
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
1111
use rustc_middle::mir::interpret::AllocInit;
12+
use rustc_middle::mir::mono::Linkage;
1213
use rustc_middle::ty::{Instance, Ty};
1314
use rustc_middle::{mir, ty};
1415
use rustc_span::Symbol;
@@ -138,7 +139,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
138139
Entry::Occupied(e) => e.into_mut(),
139140
Entry::Vacant(e) => {
140141
// Find it if it was not cached.
141-
let mut instance_and_crate: Option<(ty::Instance<'_>, CrateNum)> = None;
142+
let mut instance_and_crate: Option<(ty::Instance<'_>, CrateNum, bool)> = None;
142143
helpers::iter_exported_symbols(tcx, |cnum, def_id| {
143144
let attrs = tcx.codegen_fn_attrs(def_id);
144145
// Skip over imports of items.
@@ -155,39 +156,70 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
155156

156157
let instance = Instance::mono(tcx, def_id);
157158
let symbol_name = tcx.symbol_name(instance).name;
159+
let is_weak = attrs.linkage == Some(Linkage::WeakAny);
158160
if symbol_name == link_name.as_str() {
159-
if let Some((original_instance, original_cnum)) = instance_and_crate {
160-
// Make sure we are consistent wrt what is 'first' and 'second'.
161-
let original_span = tcx.def_span(original_instance.def_id()).data();
162-
let span = tcx.def_span(def_id).data();
163-
if original_span < span {
164-
throw_machine_stop!(TerminationInfo::MultipleSymbolDefinitions {
165-
link_name,
166-
first: original_span,
167-
first_crate: tcx.crate_name(original_cnum),
168-
second: span,
169-
second_crate: tcx.crate_name(cnum),
170-
});
171-
} else {
172-
throw_machine_stop!(TerminationInfo::MultipleSymbolDefinitions {
173-
link_name,
174-
first: span,
175-
first_crate: tcx.crate_name(cnum),
176-
second: original_span,
177-
second_crate: tcx.crate_name(original_cnum),
178-
});
161+
if let Some((original_instance, original_cnum, original_is_weak)) =
162+
instance_and_crate
163+
{
164+
match (is_weak, original_is_weak) {
165+
(false, true) => {
166+
// Original definition is a weak definition. Override it.
167+
168+
instance_and_crate =
169+
Some((ty::Instance::mono(tcx, def_id), cnum, is_weak));
170+
}
171+
(true, false) => {
172+
// Current definition is a weak definition. Keep the original one.
173+
}
174+
(true, true) | (false, false) => {
175+
// Either both definitions are non-weak or both are weak. In
176+
// either case return an error. For weak definitions we error
177+
// because it is undefined which definition would have been
178+
// picked by the linker.
179+
180+
// Make sure we are consistent wrt what is 'first' and 'second'.
181+
let original_span =
182+
tcx.def_span(original_instance.def_id()).data();
183+
let span = tcx.def_span(def_id).data();
184+
if original_span < span {
185+
throw_machine_stop!(
186+
TerminationInfo::MultipleSymbolDefinitions {
187+
link_name,
188+
first: original_span,
189+
first_crate: tcx.crate_name(original_cnum),
190+
second: span,
191+
second_crate: tcx.crate_name(cnum),
192+
}
193+
);
194+
} else {
195+
throw_machine_stop!(
196+
TerminationInfo::MultipleSymbolDefinitions {
197+
link_name,
198+
first: span,
199+
first_crate: tcx.crate_name(cnum),
200+
second: original_span,
201+
second_crate: tcx.crate_name(original_cnum),
202+
}
203+
);
204+
}
205+
}
179206
}
207+
} else {
208+
instance_and_crate =
209+
Some((ty::Instance::mono(tcx, def_id), cnum, is_weak));
180210
}
181-
if !matches!(tcx.def_kind(def_id), DefKind::Fn | DefKind::AssocFn) {
182-
throw_ub_format!(
183-
"attempt to call an exported symbol that is not defined as a function"
184-
);
185-
}
186-
instance_and_crate = Some((ty::Instance::mono(tcx, def_id), cnum));
187211
}
188212
interp_ok(())
189213
})?;
190214

215+
if let Some((instance, _, _)) = instance_and_crate {
216+
if !matches!(tcx.def_kind(instance.def_id()), DefKind::Fn | DefKind::AssocFn) {
217+
throw_ub_format!(
218+
"attempt to call an exported symbol that is not defined as a function"
219+
);
220+
}
221+
}
222+
191223
e.insert(instance_and_crate.map(|ic| ic.0))
192224
}
193225
};

0 commit comments

Comments
 (0)