Skip to content

Commit 3305e71

Browse files
bjorn3RalfJung
authored andcommitted
Run static initializers
1 parent a8a88fe commit 3305e71

2 files changed

Lines changed: 102 additions & 15 deletions

File tree

‎src/tools/miri/src/bin/miri.rs‎

Lines changed: 27 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,9 @@ use rustc_driver::Compilation;
3232
use rustc_hir::{selfas hir,Node};
3333
use rustc_interface::interface::Config;
3434
use rustc_middle::{
35-
middle::exported_symbols::{
36-
ExportedSymbol,SymbolExportInfo,SymbolExportKind,SymbolExportLevel,
35+
middle::{
36+
codegen_fn_attrs::CodegenFnAttrFlags,
37+
exported_symbols::{ExportedSymbol,SymbolExportInfo,SymbolExportKind,SymbolExportLevel},
3738
},
3839
query::LocalCrate,
3940
ty::TyCtxt,
@@ -136,6 +137,8 @@ impl rustc_driver::Callbacks for MiriBeRustCompilerCalls {
136137
config.override_queries = Some(|_, local_providers| {
137138
// `exported_symbols` and `reachable_non_generics` provided by rustc always returns
138139
// an empty result if `tcx.sess.opts.output_types.should_codegen()` is false.
140+
// In addition we need to add #[used] symbols to exported_symbols for .init_array
141+
// handling.
139142
local_providers.exported_symbols = |tcx,LocalCrate| {
140143
let reachable_set = tcx.with_stable_hashing_context(|hcx| {
141144
tcx.reachable_set(()).to_sorted(&hcx,true)
@@ -160,19 +163,28 @@ impl rustc_driver::Callbacks for MiriBeRustCompilerCalls {
160163
})
161164
if !tcx.generics_of(local_def_id).requires_monomorphization(tcx)
162165
);
163-
(is_reachable_non_generic
164-
&& tcx.codegen_fn_attrs(local_def_id).contains_extern_indicator())
165-
.then_some((
166-
ExportedSymbol::NonGeneric(local_def_id.to_def_id()),
167-
// Some dummy `SymbolExportInfo` here. We only use
168-
// `exported_symbols` in shims/foreign_items.rs and the export info
169-
// is ignored.
170-
SymbolExportInfo{
171-
level:SymbolExportLevel::C,
172-
kind:SymbolExportKind::Text,
173-
used:false,
174-
},
175-
))
166+
if !is_reachable_non_generic {
167+
returnNone;
168+
}
169+
let codegen_fn_attrs = tcx.codegen_fn_attrs(local_def_id);
170+
if codegen_fn_attrs.contains_extern_indicator()
171+
|| codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::USED)
172+
|| codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER)
173+
{
174+
Some((
175+
ExportedSymbol::NonGeneric(local_def_id.to_def_id()),
176+
// Some dummy `SymbolExportInfo` here. We only use
177+
// `exported_symbols` in shims/foreign_items.rs and the export info
178+
// is ignored.
179+
SymbolExportInfo{
180+
level:SymbolExportLevel::C,
181+
kind:SymbolExportKind::Text,
182+
used:false,
183+
},
184+
))
185+
}else{
186+
None
187+
}
176188
}),
177189
)
178190
}

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

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,81 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
158158
Ok(())
159159
}
160160

161+
fnlookup_init_array(&mutself) -> InterpResult<'tcx,Vec<ty::Instance<'tcx>>>{
162+
let this = self.eval_context_mut();
163+
let tcx = this.tcx.tcx;
164+
165+
letmut init_arrays = vec![];
166+
167+
let dependency_formats = tcx.dependency_formats(());
168+
let dependency_format = dependency_formats
169+
.iter()
170+
.find(|(crate_type, _)| *crate_type == CrateType::Executable)
171+
.expect("interpreting a non-executable crate");
172+
for cnum in iter::once(LOCAL_CRATE).chain(
173+
dependency_format.1.iter().enumerate().filter_map(|(num,&linkage)| {
174+
// We add 1 to the number because that's what rustc also does everywhere it
175+
// calls `CrateNum::new`...
176+
#[allow(clippy::arithmetic_side_effects)]
177+
(linkage != Linkage::NotLinked).then_some(CrateNum::new(num + 1))
178+
}),
179+
){
180+
for&(symbol, _export_info)in tcx.exported_symbols(cnum){
181+
ifletExportedSymbol::NonGeneric(def_id) = symbol {
182+
let attrs = tcx.codegen_fn_attrs(def_id);
183+
let link_section = ifletSome(link_section) = attrs.link_section{
184+
if !link_section.as_str().starts_with(".init_array"){
185+
continue;
186+
}
187+
link_section
188+
}else{
189+
continue;
190+
};
191+
192+
init_arrays.push((link_section, def_id));
193+
}
194+
}
195+
}
196+
197+
init_arrays.sort_by(|(a, _),(b, _)| a.as_str().cmp(b.as_str()));
198+
199+
let endianness = tcx.data_layout.endian;
200+
let ptr_size = tcx.data_layout.pointer_size;
201+
202+
letmut init_array = vec![];
203+
204+
for(_, def_id)in init_arrays {
205+
let alloc = tcx.eval_static_initializer(def_id)?.inner();
206+
letmut expected_offset = Size::ZERO;
207+
for&(offset, prov)in alloc.provenance().ptrs().iter(){
208+
if offset != expected_offset {
209+
throw_ub_format!(".init_array.* may not contain any non-function pointer data");
210+
}
211+
expected_offset += ptr_size;
212+
213+
let alloc_id = prov.alloc_id();
214+
215+
let reloc_target_alloc = tcx.global_alloc(alloc_id);
216+
match reloc_target_alloc {
217+
GlobalAlloc::Function(instance) => {
218+
let addend = {
219+
let offset = offset.bytes()asusize;
220+
let bytes = &alloc.inspect_with_uninit_and_ptr_outside_interpreter(
221+
offset..offset + ptr_size.bytes()asusize,
222+
);
223+
read_target_uint(endianness, bytes).unwrap()
224+
};
225+
assert_eq!(addend,0);
226+
init_array.push(instance);
227+
}
228+
_ => throw_ub_format!(".init_array.* member is not a function pointer"),
229+
}
230+
}
231+
}
232+
233+
Ok(init_array)
234+
}
235+
161236
/// Lookup the body of a function that has `link_name` as the symbol name.
162237
fnlookup_exported_symbol(
163238
&mutself,

0 commit comments

Comments
 (0)