Skip to content

Commit 3305e71

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

File tree

2 files changed

+102
-15
lines changed

2 files changed

+102
-15
lines changed

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

+27-15
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,9 @@ use rustc_driver::Compilation;
3232
use rustc_hir::{self as 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+
return None;
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

+75
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+
fn lookup_init_array(&mut self) -> InterpResult<'tcx, Vec<ty::Instance<'tcx>>> {
162+
let this = self.eval_context_mut();
163+
let tcx = this.tcx.tcx;
164+
165+
let mut 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+
if let ExportedSymbol::NonGeneric(def_id) = symbol {
182+
let attrs = tcx.codegen_fn_attrs(def_id);
183+
let link_section = if let Some(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+
let mut init_array = vec![];
203+
204+
for (_, def_id) in init_arrays {
205+
let alloc = tcx.eval_static_initializer(def_id)?.inner();
206+
let mut 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() as usize;
220+
let bytes = &alloc.inspect_with_uninit_and_ptr_outside_interpreter(
221+
offset..offset + ptr_size.bytes() as usize,
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
fn lookup_exported_symbol(
163238
&mut self,

0 commit comments

Comments
 (0)