-
Notifications
You must be signed in to change notification settings - Fork 390
Support weak definitions #4414
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Support weak definitions #4414
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
@@ -9,6 +9,7 @@ use rustc_hir::def::DefKind; | |||||||||
use rustc_hir::def_id::CrateNum; | ||||||||||
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; | ||||||||||
use rustc_middle::mir::interpret::AllocInit; | ||||||||||
use rustc_middle::mir::mono::Linkage; | ||||||||||
use rustc_middle::ty::{Instance, Ty}; | ||||||||||
use rustc_middle::{mir, ty}; | ||||||||||
use rustc_span::Symbol; | ||||||||||
|
@@ -138,7 +139,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { | |||||||||
Entry::Occupied(e) => e.into_mut(), | ||||||||||
Entry::Vacant(e) => { | ||||||||||
// Find it if it was not cached. | ||||||||||
let mut instance_and_crate: Option<(ty::Instance<'_>, CrateNum)> = None; | ||||||||||
let mut instance_and_crate: Option<(ty::Instance<'_>, CrateNum, bool)> = None; | ||||||||||
helpers::iter_exported_symbols(tcx, |cnum, def_id| { | ||||||||||
let attrs = tcx.codegen_fn_attrs(def_id); | ||||||||||
// Skip over imports of items. | ||||||||||
|
@@ -155,39 +156,70 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { | |||||||||
|
||||||||||
let instance = Instance::mono(tcx, def_id); | ||||||||||
let symbol_name = tcx.symbol_name(instance).name; | ||||||||||
let is_weak = attrs.linkage == Some(Linkage::WeakAny); | ||||||||||
if symbol_name == link_name.as_str() { | ||||||||||
if let Some((original_instance, original_cnum)) = instance_and_crate { | ||||||||||
// Make sure we are consistent wrt what is 'first' and 'second'. | ||||||||||
let original_span = tcx.def_span(original_instance.def_id()).data(); | ||||||||||
let span = tcx.def_span(def_id).data(); | ||||||||||
if original_span < span { | ||||||||||
throw_machine_stop!(TerminationInfo::MultipleSymbolDefinitions { | ||||||||||
link_name, | ||||||||||
first: original_span, | ||||||||||
first_crate: tcx.crate_name(original_cnum), | ||||||||||
second: span, | ||||||||||
second_crate: tcx.crate_name(cnum), | ||||||||||
}); | ||||||||||
} else { | ||||||||||
throw_machine_stop!(TerminationInfo::MultipleSymbolDefinitions { | ||||||||||
link_name, | ||||||||||
first: span, | ||||||||||
first_crate: tcx.crate_name(cnum), | ||||||||||
second: original_span, | ||||||||||
second_crate: tcx.crate_name(original_cnum), | ||||||||||
}); | ||||||||||
if let Some((original_instance, original_cnum, original_is_weak)) = | ||||||||||
instance_and_crate | ||||||||||
{ | ||||||||||
match (is_weak, original_is_weak) { | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||
(false, true) => { | ||||||||||
// Original definition is a weak definition. Override it. | ||||||||||
|
||||||||||
instance_and_crate = | ||||||||||
Some((ty::Instance::mono(tcx, def_id), cnum, is_weak)); | ||||||||||
} | ||||||||||
(true, false) => { | ||||||||||
// Current definition is a weak definition. Keep the original one. | ||||||||||
} | ||||||||||
(true, true) | (false, false) => { | ||||||||||
// Either both definitions are non-weak or both are weak. In | ||||||||||
// either case return an error. For weak definitions we error | ||||||||||
// because it is undefined which definition would have been | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||
// picked by the linker. | ||||||||||
|
||||||||||
// Make sure we are consistent wrt what is 'first' and 'second'. | ||||||||||
let original_span = | ||||||||||
tcx.def_span(original_instance.def_id()).data(); | ||||||||||
let span = tcx.def_span(def_id).data(); | ||||||||||
if original_span < span { | ||||||||||
throw_machine_stop!( | ||||||||||
TerminationInfo::MultipleSymbolDefinitions { | ||||||||||
link_name, | ||||||||||
first: original_span, | ||||||||||
first_crate: tcx.crate_name(original_cnum), | ||||||||||
second: span, | ||||||||||
second_crate: tcx.crate_name(cnum), | ||||||||||
} | ||||||||||
); | ||||||||||
} else { | ||||||||||
throw_machine_stop!( | ||||||||||
TerminationInfo::MultipleSymbolDefinitions { | ||||||||||
link_name, | ||||||||||
first: span, | ||||||||||
first_crate: tcx.crate_name(cnum), | ||||||||||
second: original_span, | ||||||||||
second_crate: tcx.crate_name(original_cnum), | ||||||||||
} | ||||||||||
); | ||||||||||
} | ||||||||||
} | ||||||||||
} | ||||||||||
} else { | ||||||||||
instance_and_crate = | ||||||||||
Some((ty::Instance::mono(tcx, def_id), cnum, is_weak)); | ||||||||||
} | ||||||||||
if !matches!(tcx.def_kind(def_id), DefKind::Fn | DefKind::AssocFn) { | ||||||||||
throw_ub_format!( | ||||||||||
"attempt to call an exported symbol that is not defined as a function" | ||||||||||
); | ||||||||||
} | ||||||||||
instance_and_crate = Some((ty::Instance::mono(tcx, def_id), cnum)); | ||||||||||
} | ||||||||||
interp_ok(()) | ||||||||||
})?; | ||||||||||
|
||||||||||
if let Some((instance, _, _)) = instance_and_crate { | ||||||||||
if !matches!(tcx.def_kind(instance.def_id()), DefKind::Fn | DefKind::AssocFn) { | ||||||||||
throw_ub_format!( | ||||||||||
"attempt to call an exported symbol that is not defined as a function" | ||||||||||
); | ||||||||||
} | ||||||||||
} | ||||||||||
|
||||||||||
Comment on lines
+215
to
+222
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I guess this logic can live here as well, but is there a specific reason you moved it? |
||||||||||
e.insert(instance_and_crate.map(|ic| ic.0)) | ||||||||||
} | ||||||||||
}; | ||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please rename this to |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
#![feature(linkage)] | ||
|
||
// FIXME move this module to a separate crate once aux-build is allowed | ||
// This currently depends on the fact that miri skips the codegen check | ||
// that denies multiple symbols with the same name. | ||
mod first { | ||
#[no_mangle] | ||
#[linkage = "weak"] | ||
extern "C" fn foo() -> i32 { | ||
1 | ||
} | ||
|
||
#[no_mangle] | ||
#[linkage = "weak"] | ||
extern "C" fn bar() -> i32 { | ||
2 | ||
} | ||
} | ||
|
||
mod second { | ||
#[no_mangle] | ||
extern "C" fn bar() -> i32 { | ||
3 | ||
} | ||
} | ||
|
||
extern "C" { | ||
fn foo() -> i32; | ||
fn bar() -> i32; | ||
} | ||
|
||
fn main() { | ||
unsafe { | ||
// If there is no non-weak definition, the weak definition will be used. | ||
assert_eq!(foo(), 1); | ||
// Non-weak definition takes presedence. | ||
assert_eq!(bar(), 3); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please explain what the
bool
means, or use a self-explaining type. It might be worth using a struct instead of a tuple.