about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbjorn3 <17426603+bjorn3@users.noreply.github.com>2024-02-23 20:13:51 +0000
committerRalf Jung <post@ralfj.de>2024-04-14 18:19:52 +0200
commit3305e71095ecf05ae2b108608fa35ae5e9b47de3 (patch)
tree772e2937e91d592cbfc86d17e3d308e5a9d75c17
parenta8a88fe5243cbeb37d8a9de8c5ca63136c0604b0 (diff)
downloadrust-3305e71095ecf05ae2b108608fa35ae5e9b47de3.tar.gz
rust-3305e71095ecf05ae2b108608fa35ae5e9b47de3.zip
Run static initializers
-rw-r--r--src/tools/miri/src/bin/miri.rs42
-rw-r--r--src/tools/miri/src/shims/foreign_items.rs75
2 files changed, 102 insertions, 15 deletions
diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs
index 8fffb91542f..c75d1b0cc64 100644
--- a/src/tools/miri/src/bin/miri.rs
+++ b/src/tools/miri/src/bin/miri.rs
@@ -32,8 +32,9 @@ use rustc_driver::Compilation;
 use rustc_hir::{self as hir, Node};
 use rustc_interface::interface::Config;
 use rustc_middle::{
-    middle::exported_symbols::{
-        ExportedSymbol, SymbolExportInfo, SymbolExportKind, SymbolExportLevel,
+    middle::{
+        codegen_fn_attrs::CodegenFnAttrFlags,
+        exported_symbols::{ExportedSymbol, SymbolExportInfo, SymbolExportKind, SymbolExportLevel},
     },
     query::LocalCrate,
     ty::TyCtxt,
@@ -136,6 +137,8 @@ impl rustc_driver::Callbacks for MiriBeRustCompilerCalls {
             config.override_queries = Some(|_, local_providers| {
                 // `exported_symbols` and `reachable_non_generics` provided by rustc always returns
                 // an empty result if `tcx.sess.opts.output_types.should_codegen()` is false.
+                // In addition we need to add #[used] symbols to exported_symbols for .init_array
+                // handling.
                 local_providers.exported_symbols = |tcx, LocalCrate| {
                     let reachable_set = tcx.with_stable_hashing_context(|hcx| {
                         tcx.reachable_set(()).to_sorted(&hcx, true)
@@ -160,19 +163,28 @@ impl rustc_driver::Callbacks for MiriBeRustCompilerCalls {
                                 })
                                 if !tcx.generics_of(local_def_id).requires_monomorphization(tcx)
                             );
-                            (is_reachable_non_generic
-                                && tcx.codegen_fn_attrs(local_def_id).contains_extern_indicator())
-                            .then_some((
-                                ExportedSymbol::NonGeneric(local_def_id.to_def_id()),
-                                // Some dummy `SymbolExportInfo` here. We only use
-                                // `exported_symbols` in shims/foreign_items.rs and the export info
-                                // is ignored.
-                                SymbolExportInfo {
-                                    level: SymbolExportLevel::C,
-                                    kind: SymbolExportKind::Text,
-                                    used: false,
-                                },
-                            ))
+                            if !is_reachable_non_generic {
+                                return None;
+                            }
+                            let codegen_fn_attrs = tcx.codegen_fn_attrs(local_def_id);
+                            if codegen_fn_attrs.contains_extern_indicator()
+                                || codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::USED)
+                                || codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER)
+                            {
+                                Some((
+                                    ExportedSymbol::NonGeneric(local_def_id.to_def_id()),
+                                    // Some dummy `SymbolExportInfo` here. We only use
+                                    // `exported_symbols` in shims/foreign_items.rs and the export info
+                                    // is ignored.
+                                    SymbolExportInfo {
+                                        level: SymbolExportLevel::C,
+                                        kind: SymbolExportKind::Text,
+                                        used: false,
+                                    },
+                                ))
+                            } else {
+                                None
+                            }
                         }),
                     )
                 }
diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs
index a25d377f3a7..5498d9b83f2 100644
--- a/src/tools/miri/src/shims/foreign_items.rs
+++ b/src/tools/miri/src/shims/foreign_items.rs
@@ -158,6 +158,81 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
         Ok(())
     }
 
+    fn lookup_init_array(&mut self) -> InterpResult<'tcx, Vec<ty::Instance<'tcx>>> {
+        let this = self.eval_context_mut();
+        let tcx = this.tcx.tcx;
+
+        let mut init_arrays = vec![];
+
+        let dependency_formats = tcx.dependency_formats(());
+        let dependency_format = dependency_formats
+            .iter()
+            .find(|(crate_type, _)| *crate_type == CrateType::Executable)
+            .expect("interpreting a non-executable crate");
+        for cnum in iter::once(LOCAL_CRATE).chain(
+            dependency_format.1.iter().enumerate().filter_map(|(num, &linkage)| {
+                // We add 1 to the number because that's what rustc also does everywhere it
+                // calls `CrateNum::new`...
+                #[allow(clippy::arithmetic_side_effects)]
+                (linkage != Linkage::NotLinked).then_some(CrateNum::new(num + 1))
+            }),
+        ) {
+            for &(symbol, _export_info) in tcx.exported_symbols(cnum) {
+                if let ExportedSymbol::NonGeneric(def_id) = symbol {
+                    let attrs = tcx.codegen_fn_attrs(def_id);
+                    let link_section = if let Some(link_section) = attrs.link_section {
+                        if !link_section.as_str().starts_with(".init_array") {
+                            continue;
+                        }
+                        link_section
+                    } else {
+                        continue;
+                    };
+
+                    init_arrays.push((link_section, def_id));
+                }
+            }
+        }
+
+        init_arrays.sort_by(|(a, _), (b, _)| a.as_str().cmp(b.as_str()));
+
+        let endianness = tcx.data_layout.endian;
+        let ptr_size = tcx.data_layout.pointer_size;
+
+        let mut init_array = vec![];
+
+        for (_, def_id) in init_arrays {
+            let alloc = tcx.eval_static_initializer(def_id)?.inner();
+            let mut expected_offset = Size::ZERO;
+            for &(offset, prov) in alloc.provenance().ptrs().iter() {
+                if offset != expected_offset {
+                    throw_ub_format!(".init_array.* may not contain any non-function pointer data");
+                }
+                expected_offset += ptr_size;
+
+                let alloc_id = prov.alloc_id();
+
+                let reloc_target_alloc = tcx.global_alloc(alloc_id);
+                match reloc_target_alloc {
+                    GlobalAlloc::Function(instance) => {
+                        let addend = {
+                            let offset = offset.bytes() as usize;
+                            let bytes = &alloc.inspect_with_uninit_and_ptr_outside_interpreter(
+                                offset..offset + ptr_size.bytes() as usize,
+                            );
+                            read_target_uint(endianness, bytes).unwrap()
+                        };
+                        assert_eq!(addend, 0);
+                        init_array.push(instance);
+                    }
+                    _ => throw_ub_format!(".init_array.* member is not a function pointer"),
+                }
+            }
+        }
+
+        Ok(init_array)
+    }
+
     /// Lookup the body of a function that has `link_name` as the symbol name.
     fn lookup_exported_symbol(
         &mut self,