Skip to content

Commit e3c50f7

Browse files
committed
Miri: run .CRT$XLB linker section on thread-end
1 parent 3305e71 commit e3c50f7

File tree

7 files changed

+180
-208
lines changed

7 files changed

+180
-208
lines changed

library/std/src/sys/pal/windows/thread_local_key.rs

+1
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,7 @@ unsafe fn register_dtor(key: &'static StaticKey) {
276276
// the address of the symbol to ensure it sticks around.
277277

278278
#[link_section = ".CRT$XLB"]
279+
#[cfg_attr(miri, used)] // Miri only considers explicitly `#[used]` statics for `lookup_link_section`
279280
pub static p_thread_callback: unsafe extern "system" fn(c::LPVOID, c::DWORD, c::LPVOID) =
280281
on_tls_callback;
281282

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

+1-2
Original file line numberDiff line numberDiff line change
@@ -137,8 +137,7 @@ impl rustc_driver::Callbacks for MiriBeRustCompilerCalls {
137137
config.override_queries = Some(|_, local_providers| {
138138
// `exported_symbols` and `reachable_non_generics` provided by rustc always returns
139139
// 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.
140+
// In addition we need to add #[used] symbols to exported_symbols for `lookup_link_section`.
142141
local_providers.exported_symbols = |tcx, LocalCrate| {
143142
let reachable_set = tcx.with_stable_hashing_context(|hcx| {
144143
tcx.reachable_set(()).to_sorted(&hcx, true)

src/tools/miri/src/concurrency/thread.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ pub struct Thread<'mir, 'tcx> {
158158
}
159159

160160
pub type StackEmptyCallback<'mir, 'tcx> =
161-
Box<dyn FnMut(&mut MiriInterpCx<'mir, 'tcx>) -> InterpResult<'tcx, Poll<()>>>;
161+
Box<dyn FnMut(&mut MiriInterpCx<'mir, 'tcx>) -> InterpResult<'tcx, Poll<()>> + 'tcx>;
162162

163163
impl<'mir, 'tcx> Thread<'mir, 'tcx> {
164164
/// Get the name of the current thread if it was set.

src/tools/miri/src/eval.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -192,18 +192,18 @@ impl Default for MiriConfig {
192192

193193
/// The state of the main thread. Implementation detail of `on_main_stack_empty`.
194194
#[derive(Default, Debug)]
195-
enum MainThreadState {
195+
enum MainThreadState<'tcx> {
196196
#[default]
197197
Running,
198-
TlsDtors(tls::TlsDtorsState),
198+
TlsDtors(tls::TlsDtorsState<'tcx>),
199199
Yield {
200200
remaining: u32,
201201
},
202202
Done,
203203
}
204204

205-
impl MainThreadState {
206-
fn on_main_stack_empty<'tcx>(
205+
impl<'tcx> MainThreadState<'tcx> {
206+
fn on_main_stack_empty(
207207
&mut self,
208208
this: &mut MiriInterpCx<'_, 'tcx>,
209209
) -> InterpResult<'tcx, Poll<()>> {

src/tools/miri/src/helpers.rs

+71-3
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,21 @@ use rand::RngCore;
99

1010
use rustc_apfloat::ieee::{Double, Single};
1111
use rustc_apfloat::Float;
12-
use rustc_hir::def::{DefKind, Namespace};
13-
use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX};
12+
use rustc_hir::{
13+
def::{DefKind, Namespace},
14+
def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE},
15+
};
1416
use rustc_index::IndexVec;
17+
use rustc_middle::middle::dependency_format::Linkage;
18+
use rustc_middle::middle::exported_symbols::ExportedSymbol;
1519
use rustc_middle::mir;
1620
use rustc_middle::ty::{
1721
self,
1822
layout::{LayoutOf, TyAndLayout},
1923
FloatTy, IntTy, Ty, TyCtxt, UintTy,
2024
};
21-
use rustc_span::{def_id::CrateNum, sym, Span, Symbol};
25+
use rustc_session::config::CrateType;
26+
use rustc_span::{sym, Span, Symbol};
2227
use rustc_target::abi::{Align, FieldIdx, FieldsShape, Size, Variants};
2328
use rustc_target::spec::abi::Abi;
2429

@@ -142,6 +147,38 @@ fn try_resolve_did(tcx: TyCtxt<'_>, path: &[&str], namespace: Option<Namespace>)
142147
None
143148
}
144149

150+
/// Call `f` for each exported symbol.
151+
pub fn iter_exported_symbols<'tcx>(
152+
tcx: TyCtxt<'tcx>,
153+
mut f: impl FnMut(CrateNum, DefId) -> InterpResult<'tcx>,
154+
) -> InterpResult<'tcx> {
155+
// `dependency_formats` includes all the transitive informations needed to link a crate,
156+
// which is what we need here since we need to dig out `exported_symbols` from all transitive
157+
// dependencies.
158+
let dependency_formats = tcx.dependency_formats(());
159+
let dependency_format = dependency_formats
160+
.iter()
161+
.find(|(crate_type, _)| *crate_type == CrateType::Executable)
162+
.expect("interpreting a non-executable crate");
163+
for cnum in iter::once(LOCAL_CRATE).chain(dependency_format.1.iter().enumerate().filter_map(
164+
|(num, &linkage)| {
165+
// We add 1 to the number because that's what rustc also does everywhere it
166+
// calls `CrateNum::new`...
167+
#[allow(clippy::arithmetic_side_effects)]
168+
(linkage != Linkage::NotLinked).then_some(CrateNum::new(num + 1))
169+
},
170+
)) {
171+
// We can ignore `_export_info` here: we are a Rust crate, and everything is exported
172+
// from a Rust crate.
173+
for &(symbol, _export_info) in tcx.exported_symbols(cnum) {
174+
if let ExportedSymbol::NonGeneric(def_id) = symbol {
175+
f(cnum, def_id)?;
176+
}
177+
}
178+
}
179+
Ok(())
180+
}
181+
145182
/// Convert a softfloat type to its corresponding hostfloat type.
146183
pub trait ToHost {
147184
type HostFloat;
@@ -1180,6 +1217,37 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
11801217
}
11811218
Ok(())
11821219
}
1220+
1221+
/// Lookup an array of immediates stored as a linker section of name `name`.
1222+
fn lookup_link_section(
1223+
&mut self,
1224+
name: &str,
1225+
) -> InterpResult<'tcx, Vec<ImmTy<'tcx, Provenance>>> {
1226+
let this = self.eval_context_mut();
1227+
let tcx = this.tcx.tcx;
1228+
1229+
let mut array = vec![];
1230+
1231+
iter_exported_symbols(tcx, |_cnum, def_id| {
1232+
let attrs = tcx.codegen_fn_attrs(def_id);
1233+
let Some(link_section) = attrs.link_section else {
1234+
return Ok(());
1235+
};
1236+
if link_section.as_str() == name {
1237+
let instance = ty::Instance::mono(tcx, def_id);
1238+
let const_val = this.eval_global(instance).unwrap_or_else(|err| {
1239+
panic!(
1240+
"failed to evaluate static in required link_section: {def_id:?}\n{err:?}"
1241+
)
1242+
});
1243+
let val = this.read_immediate(&const_val)?;
1244+
array.push(val);
1245+
}
1246+
Ok(())
1247+
})?;
1248+
1249+
Ok(array)
1250+
}
11831251
}
11841252

11851253
impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> {

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

+40-148
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,10 @@ use std::{collections::hash_map::Entry, io::Write, iter, path::Path};
22

33
use rustc_apfloat::Float;
44
use rustc_ast::expand::allocator::AllocatorKind;
5-
use rustc_hir::{
6-
def::DefKind,
7-
def_id::{CrateNum, LOCAL_CRATE},
8-
};
9-
use rustc_middle::middle::{
10-
codegen_fn_attrs::CodegenFnAttrFlags, dependency_format::Linkage,
11-
exported_symbols::ExportedSymbol,
12-
};
5+
use rustc_hir::{def::DefKind, def_id::CrateNum};
6+
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
137
use rustc_middle::mir;
148
use rustc_middle::ty;
15-
use rustc_session::config::CrateType;
169
use rustc_span::Symbol;
1710
use rustc_target::{
1811
abi::{Align, Size},
@@ -158,81 +151,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
158151
Ok(())
159152
}
160153

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-
236154
/// Lookup the body of a function that has `link_name` as the symbol name.
237155
fn lookup_exported_symbol(
238156
&mut self,
@@ -249,74 +167,48 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
249167
Entry::Vacant(e) => {
250168
// Find it if it was not cached.
251169
let mut instance_and_crate: Option<(ty::Instance<'_>, CrateNum)> = None;
252-
// `dependency_formats` includes all the transitive informations needed to link a crate,
253-
// which is what we need here since we need to dig out `exported_symbols` from all transitive
254-
// dependencies.
255-
let dependency_formats = tcx.dependency_formats(());
256-
let dependency_format = dependency_formats
257-
.iter()
258-
.find(|(crate_type, _)| *crate_type == CrateType::Executable)
259-
.expect("interpreting a non-executable crate");
260-
for cnum in iter::once(LOCAL_CRATE).chain(
261-
dependency_format.1.iter().enumerate().filter_map(|(num, &linkage)| {
262-
// We add 1 to the number because that's what rustc also does everywhere it
263-
// calls `CrateNum::new`...
264-
#[allow(clippy::arithmetic_side_effects)]
265-
(linkage != Linkage::NotLinked).then_some(CrateNum::new(num + 1))
266-
}),
267-
) {
268-
// We can ignore `_export_info` here: we are a Rust crate, and everything is exported
269-
// from a Rust crate.
270-
for &(symbol, _export_info) in tcx.exported_symbols(cnum) {
271-
if let ExportedSymbol::NonGeneric(def_id) = symbol {
272-
let attrs = tcx.codegen_fn_attrs(def_id);
273-
let symbol_name = if let Some(export_name) = attrs.export_name {
274-
export_name
275-
} else if attrs.flags.contains(CodegenFnAttrFlags::NO_MANGLE) {
276-
tcx.item_name(def_id)
170+
helpers::iter_exported_symbols(tcx, |cnum, def_id| {
171+
let attrs = tcx.codegen_fn_attrs(def_id);
172+
let symbol_name = if let Some(export_name) = attrs.export_name {
173+
export_name
174+
} else if attrs.flags.contains(CodegenFnAttrFlags::NO_MANGLE) {
175+
tcx.item_name(def_id)
176+
} else {
177+
// Skip over items without an explicitly defined symbol name.
178+
return Ok(());
179+
};
180+
if symbol_name == link_name {
181+
if let Some((original_instance, original_cnum)) = instance_and_crate {
182+
// Make sure we are consistent wrt what is 'first' and 'second'.
183+
let original_span = tcx.def_span(original_instance.def_id()).data();
184+
let span = tcx.def_span(def_id).data();
185+
if original_span < span {
186+
throw_machine_stop!(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+
});
277193
} else {
278-
// Skip over items without an explicitly defined symbol name.
279-
continue;
280-
};
281-
if symbol_name == link_name {
282-
if let Some((original_instance, original_cnum)) = instance_and_crate
283-
{
284-
// Make sure we are consistent wrt what is 'first' and 'second'.
285-
let original_span =
286-
tcx.def_span(original_instance.def_id()).data();
287-
let span = tcx.def_span(def_id).data();
288-
if original_span < span {
289-
throw_machine_stop!(
290-
TerminationInfo::MultipleSymbolDefinitions {
291-
link_name,
292-
first: original_span,
293-
first_crate: tcx.crate_name(original_cnum),
294-
second: span,
295-
second_crate: tcx.crate_name(cnum),
296-
}
297-
);
298-
} else {
299-
throw_machine_stop!(
300-
TerminationInfo::MultipleSymbolDefinitions {
301-
link_name,
302-
first: span,
303-
first_crate: tcx.crate_name(cnum),
304-
second: original_span,
305-
second_crate: tcx.crate_name(original_cnum),
306-
}
307-
);
308-
}
309-
}
310-
if !matches!(tcx.def_kind(def_id), DefKind::Fn | DefKind::AssocFn) {
311-
throw_ub_format!(
312-
"attempt to call an exported symbol that is not defined as a function"
313-
);
314-
}
315-
instance_and_crate = Some((ty::Instance::mono(tcx, def_id), cnum));
194+
throw_machine_stop!(TerminationInfo::MultipleSymbolDefinitions {
195+
link_name,
196+
first: span,
197+
first_crate: tcx.crate_name(cnum),
198+
second: original_span,
199+
second_crate: tcx.crate_name(original_cnum),
200+
});
316201
}
317202
}
203+
if !matches!(tcx.def_kind(def_id), DefKind::Fn | DefKind::AssocFn) {
204+
throw_ub_format!(
205+
"attempt to call an exported symbol that is not defined as a function"
206+
);
207+
}
208+
instance_and_crate = Some((ty::Instance::mono(tcx, def_id), cnum));
318209
}
319-
}
210+
Ok(())
211+
})?;
320212

321213
e.insert(instance_and_crate.map(|ic| ic.0))
322214
}

0 commit comments

Comments
 (0)