Skip to content

Commit 28717a0

Browse files
committed
Auto merge of #1776 - hyd-dev:1170, r=RalfJung
Implement calls to exported symbols (#1170) Closes #1170.
2 parents 44122f9 + 57e4f1d commit 28717a0

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+828
-284
lines changed

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,8 @@ environment variable:
200200
`compare_exchange_weak` operations. The default is `0.8` (so 4 out of 5 weak ops will fail).
201201
You can change it to any value between `0.0` and `1.0`, where `1.0` means it
202202
will always fail and `0.0` means it will never fail.
203+
* `-Zmiri-disable-abi-check` disables checking [function ABI]. Using this flag
204+
is **unsound**.
203205
* `-Zmiri-disable-alignment-check` disables checking pointer alignment, so you
204206
can focus on other failures, but it means Miri can miss bugs in your program.
205207
Using this flag is **unsound**.
@@ -263,6 +265,8 @@ environment variable:
263265
with `-Zmiri-track-raw-pointers` also works without
264266
`-Zmiri-track-raw-pointers`, but for the vast majority of code, this will be the case.
265267

268+
[function ABI]: https://doc.rust-lang.org/reference/items/functions.html#extern-function-qualifier
269+
266270
Some native rustc `-Z` flags are also very relevant for Miri:
267271

268272
* `-Zmir-opt-level` controls how many MIR optimizations are performed. Miri

src/bin/miri.rs

Lines changed: 73 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,52 @@
1-
#![feature(rustc_private)]
1+
#![feature(rustc_private, bool_to_option, stmt_expr_attributes)]
22

33
extern crate rustc_driver;
44
extern crate rustc_errors;
55
extern crate rustc_hir;
66
extern crate rustc_interface;
7+
extern crate rustc_metadata;
78
extern crate rustc_middle;
89
extern crate rustc_session;
910

1011
use std::convert::TryFrom;
1112
use std::env;
13+
use std::path::PathBuf;
14+
use std::rc::Rc;
1215
use std::str::FromStr;
1316

1417
use hex::FromHexError;
1518
use log::debug;
1619

1720
use rustc_driver::Compilation;
1821
use rustc_errors::emitter::{ColorConfig, HumanReadableErrorType};
19-
use rustc_middle::ty::TyCtxt;
20-
use rustc_session::{config::ErrorOutputType, CtfeBacktrace};
22+
use rustc_hir::def_id::LOCAL_CRATE;
23+
use rustc_interface::interface::Config;
24+
use rustc_middle::{
25+
middle::exported_symbols::{ExportedSymbol, SymbolExportLevel},
26+
ty::{query::Providers, TyCtxt},
27+
};
28+
use rustc_session::{config::ErrorOutputType, search_paths::PathKind, CtfeBacktrace};
2129

2230
struct MiriCompilerCalls {
2331
miri_config: miri::MiriConfig,
2432
}
2533

2634
impl rustc_driver::Callbacks for MiriCompilerCalls {
35+
fn config(&mut self, config: &mut Config) {
36+
config.override_queries = Some(|_, _, external_providers| {
37+
external_providers.used_crate_source = |tcx, cnum| {
38+
let mut providers = Providers::default();
39+
rustc_metadata::provide_extern(&mut providers);
40+
let mut crate_source = (providers.used_crate_source)(tcx, cnum);
41+
// HACK: rustc will emit "crate ... required to be available in rlib format, but
42+
// was not found in this form" errors once we use `tcx.dependency_formats()` if
43+
// there's no rlib provided, so setting a dummy path here to workaround those errors.
44+
Rc::make_mut(&mut crate_source).rlib = Some((PathBuf::new(), PathKind::All));
45+
crate_source
46+
};
47+
});
48+
}
49+
2750
fn after_analysis<'tcx>(
2851
&mut self,
2952
compiler: &rustc_interface::interface::Compiler,
@@ -67,6 +90,39 @@ impl rustc_driver::Callbacks for MiriCompilerCalls {
6790
}
6891
}
6992

93+
struct MiriBeRustCompilerCalls {
94+
target_crate: bool,
95+
}
96+
97+
impl rustc_driver::Callbacks for MiriBeRustCompilerCalls {
98+
fn config(&mut self, config: &mut Config) {
99+
if config.opts.prints.is_empty() && self.target_crate {
100+
// Queries overriden here affect the data stored in `rmeta` files of dependencies,
101+
// which will be used later in non-`MIRI_BE_RUSTC` mode.
102+
config.override_queries = Some(|_, local_providers, _| {
103+
// `exported_symbols()` provided by rustc always returns empty result if
104+
// `tcx.sess.opts.output_types.should_codegen()` is false.
105+
local_providers.exported_symbols = |tcx, cnum| {
106+
assert_eq!(cnum, LOCAL_CRATE);
107+
tcx.arena.alloc_from_iter(
108+
// This is based on:
109+
// https://github.com/rust-lang/rust/blob/2962e7c0089d5c136f4e9600b7abccfbbde4973d/compiler/rustc_codegen_ssa/src/back/symbol_export.rs#L62-L63
110+
// https://github.com/rust-lang/rust/blob/2962e7c0089d5c136f4e9600b7abccfbbde4973d/compiler/rustc_codegen_ssa/src/back/symbol_export.rs#L174
111+
tcx.reachable_set(()).iter().filter_map(|&local_def_id| {
112+
tcx.codegen_fn_attrs(local_def_id)
113+
.contains_extern_indicator()
114+
.then_some((
115+
ExportedSymbol::NonGeneric(local_def_id.to_def_id()),
116+
SymbolExportLevel::C,
117+
))
118+
}),
119+
)
120+
}
121+
});
122+
}
123+
}
124+
}
125+
70126
fn init_early_loggers() {
71127
// Note that our `extern crate log` is *not* the same as rustc's; as a result, we have to
72128
// initialize them both, and we always initialize `miri`'s first.
@@ -179,11 +235,7 @@ fn main() {
179235
if let Some(crate_kind) = env::var_os("MIRI_BE_RUSTC") {
180236
rustc_driver::init_rustc_env_logger();
181237

182-
// Don't insert `MIRI_DEFAULT_ARGS`, in particular, `--cfg=miri`, if we are building a
183-
// "host" crate. That may cause procedural macros (and probably build scripts) to depend
184-
// on Miri-only symbols, such as `miri_resolve_frame`:
185-
// https://github.com/rust-lang/miri/issues/1760
186-
let insert_default_args = if crate_kind == "target" {
238+
let target_crate = if crate_kind == "target" {
187239
true
188240
} else if crate_kind == "host" {
189241
false
@@ -192,8 +244,16 @@ fn main() {
192244
};
193245

194246
// We cannot use `rustc_driver::main` as we need to adjust the CLI arguments.
195-
let mut callbacks = rustc_driver::TimePassesCallbacks::default();
196-
run_compiler(env::args().collect(), &mut callbacks, insert_default_args)
247+
run_compiler(
248+
env::args().collect(),
249+
&mut MiriBeRustCompilerCalls { target_crate },
250+
// Don't insert `MIRI_DEFAULT_ARGS`, in particular, `--cfg=miri`, if we are building
251+
// a "host" crate. That may cause procedural macros (and probably build scripts) to
252+
// depend on Miri-only symbols, such as `miri_resolve_frame`:
253+
// https://github.com/rust-lang/miri/issues/1760
254+
#[rustfmt::skip]
255+
/* insert_default_args: */ target_crate,
256+
)
197257
}
198258

199259
// Init loggers the Miri way.
@@ -227,6 +287,9 @@ fn main() {
227287
"-Zmiri-symbolic-alignment-check" => {
228288
miri_config.check_alignment = miri::AlignmentCheck::Symbolic;
229289
}
290+
"-Zmiri-disable-abi-check" => {
291+
miri_config.check_abi = false;
292+
}
230293
"-Zmiri-disable-isolation" => {
231294
miri_config.communicate = true;
232295
}

src/diagnostics.rs

Lines changed: 43 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use std::num::NonZeroU64;
55
use log::trace;
66

77
use rustc_middle::ty::{self, TyCtxt};
8-
use rustc_span::{source_map::DUMMY_SP, Span};
8+
use rustc_span::{source_map::DUMMY_SP, Span, SpanData, Symbol};
99

1010
use crate::*;
1111

@@ -14,8 +14,18 @@ pub enum TerminationInfo {
1414
Exit(i64),
1515
Abort(String),
1616
UnsupportedInIsolation(String),
17-
ExperimentalUb { msg: String, url: String },
17+
ExperimentalUb {
18+
msg: String,
19+
url: String,
20+
},
1821
Deadlock,
22+
MultipleSymbolDefinitions {
23+
link_name: Symbol,
24+
first: SpanData,
25+
first_crate: Symbol,
26+
second: SpanData,
27+
second_crate: Symbol,
28+
},
1929
}
2030

2131
impl fmt::Display for TerminationInfo {
@@ -27,6 +37,8 @@ impl fmt::Display for TerminationInfo {
2737
UnsupportedInIsolation(msg) => write!(f, "{}", msg),
2838
ExperimentalUb { msg, .. } => write!(f, "{}", msg),
2939
Deadlock => write!(f, "the evaluated program deadlocked"),
40+
MultipleSymbolDefinitions { link_name, .. } =>
41+
write!(f, "multiple definitions of symbol `{}`", link_name),
3042
}
3143
}
3244
}
@@ -55,19 +67,25 @@ pub fn report_error<'tcx, 'mir>(
5567
use TerminationInfo::*;
5668
let title = match info {
5769
Exit(code) => return Some(*code),
58-
Abort(_) => "abnormal termination",
59-
UnsupportedInIsolation(_) => "unsupported operation",
60-
ExperimentalUb { .. } => "Undefined Behavior",
61-
Deadlock => "deadlock",
70+
Abort(_) => Some("abnormal termination"),
71+
UnsupportedInIsolation(_) => Some("unsupported operation"),
72+
ExperimentalUb { .. } => Some("Undefined Behavior"),
73+
Deadlock => Some("deadlock"),
74+
MultipleSymbolDefinitions { .. } => None,
6275
};
6376
#[rustfmt::skip]
6477
let helps = match info {
6578
UnsupportedInIsolation(_) =>
66-
vec![format!("pass the flag `-Zmiri-disable-isolation` to disable isolation")],
79+
vec![(None, format!("pass the flag `-Zmiri-disable-isolation` to disable isolation"))],
6780
ExperimentalUb { url, .. } =>
6881
vec![
69-
format!("this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental"),
70-
format!("see {} for further information", url),
82+
(None, format!("this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental")),
83+
(None, format!("see {} for further information", url)),
84+
],
85+
MultipleSymbolDefinitions { first, first_crate, second, second_crate, .. } =>
86+
vec![
87+
(Some(*first), format!("it's first defined here, in crate `{}`", first_crate)),
88+
(Some(*second), format!("then it's defined here again, in crate `{}`", second_crate)),
7189
],
7290
_ => vec![],
7391
};
@@ -92,26 +110,26 @@ pub fn report_error<'tcx, 'mir>(
92110
#[rustfmt::skip]
93111
let helps = match e.kind() {
94112
Unsupported(UnsupportedOpInfo::NoMirFor(..)) =>
95-
vec![format!("make sure to use a Miri sysroot, which you can prepare with `cargo miri setup`")],
113+
vec![(None, format!("make sure to use a Miri sysroot, which you can prepare with `cargo miri setup`"))],
96114
Unsupported(UnsupportedOpInfo::ReadBytesAsPointer | UnsupportedOpInfo::ThreadLocalStatic(_) | UnsupportedOpInfo::ReadExternStatic(_)) =>
97115
panic!("Error should never be raised by Miri: {:?}", e.kind()),
98116
Unsupported(_) =>
99-
vec![format!("this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support")],
117+
vec![(None, format!("this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support"))],
100118
UndefinedBehavior(UndefinedBehaviorInfo::AlignmentCheckFailed { .. })
101119
if ecx.memory.extra.check_alignment == AlignmentCheck::Symbolic
102120
=>
103121
vec![
104-
format!("this usually indicates that your program performed an invalid operation and caused Undefined Behavior"),
105-
format!("but due to `-Zmiri-symbolic-alignment-check`, alignment errors can also be false positives"),
122+
(None, format!("this usually indicates that your program performed an invalid operation and caused Undefined Behavior")),
123+
(None, format!("but due to `-Zmiri-symbolic-alignment-check`, alignment errors can also be false positives")),
106124
],
107125
UndefinedBehavior(_) =>
108126
vec![
109-
format!("this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior"),
110-
format!("see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information"),
127+
(None, format!("this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior")),
128+
(None, format!("see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information")),
111129
],
112130
_ => vec![],
113131
};
114-
(title, helps)
132+
(Some(title), helps)
115133
}
116134
};
117135

@@ -120,7 +138,7 @@ pub fn report_error<'tcx, 'mir>(
120138
report_msg(
121139
*ecx.tcx,
122140
/*error*/ true,
123-
&format!("{}: {}", title, msg),
141+
&if let Some(title) = title { format!("{}: {}", title, msg) } else { msg.clone() },
124142
msg,
125143
helps,
126144
&ecx.generate_stacktrace(),
@@ -159,7 +177,7 @@ fn report_msg<'tcx>(
159177
error: bool,
160178
title: &str,
161179
span_msg: String,
162-
mut helps: Vec<String>,
180+
mut helps: Vec<(Option<SpanData>, String)>,
163181
stacktrace: &[FrameInfo<'tcx>],
164182
) {
165183
let span = stacktrace.first().map_or(DUMMY_SP, |fi| fi.span);
@@ -179,9 +197,13 @@ fn report_msg<'tcx>(
179197
// Show help messages.
180198
if !helps.is_empty() {
181199
// Add visual separator before backtrace.
182-
helps.last_mut().unwrap().push_str("\n");
183-
for help in helps {
184-
err.help(&help);
200+
helps.last_mut().unwrap().1.push_str("\n");
201+
for (span_data, help) in helps {
202+
if let Some(span_data) = span_data {
203+
err.span_help(span_data.span(), &help);
204+
} else {
205+
err.help(&help);
206+
}
185207
}
186208
}
187209
// Add backtrace

src/eval.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ pub struct MiriConfig {
3131
pub stacked_borrows: bool,
3232
/// Controls alignment checking.
3333
pub check_alignment: AlignmentCheck,
34+
/// Controls function [ABI](Abi) checking.
35+
pub check_abi: bool,
3436
/// Determines if communication with the host environment is enabled.
3537
pub communicate: bool,
3638
/// Determines if memory leaks should be ignored.
@@ -65,6 +67,7 @@ impl Default for MiriConfig {
6567
validate: true,
6668
stacked_borrows: true,
6769
check_alignment: AlignmentCheck::Int,
70+
check_abi: true,
6871
communicate: false,
6972
ignore_leaks: false,
7073
excluded_env_vars: vec![],

src/helpers.rs

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
165165
let this = self.eval_context_mut();
166166
let param_env = ty::ParamEnv::reveal_all(); // in Miri this is always the param_env we use... and this.param_env is private.
167167
let callee_abi = f.ty(*this.tcx, param_env).fn_sig(*this.tcx).abi();
168-
if callee_abi != caller_abi {
168+
if this.machine.enforce_abi && callee_abi != caller_abi {
169169
throw_ub_format!(
170170
"calling a function with ABI {} using caller ABI {}",
171171
callee_abi.name(),
@@ -616,6 +616,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
616616

617617
Ok(wchars)
618618
}
619+
620+
/// Check that the ABI is what we expect.
621+
fn check_abi<'a>(&self, abi: Abi, exp_abi: Abi) -> InterpResult<'a, ()> {
622+
if self.eval_context_ref().machine.enforce_abi && abi != exp_abi {
623+
throw_ub_format!(
624+
"calling a function with ABI {} using caller ABI {}",
625+
exp_abi.name(),
626+
abi.name()
627+
)
628+
}
629+
Ok(())
630+
}
619631
}
620632

621633
/// Check that the number of args is what we expect.
@@ -631,19 +643,6 @@ where
631643
throw_ub_format!("incorrect number of arguments: got {}, expected {}", args.len(), N)
632644
}
633645

634-
/// Check that the ABI is what we expect.
635-
pub fn check_abi<'a>(abi: Abi, exp_abi: Abi) -> InterpResult<'a, ()> {
636-
if abi == exp_abi {
637-
Ok(())
638-
} else {
639-
throw_ub_format!(
640-
"calling a function with ABI {} using caller ABI {}",
641-
exp_abi.name(),
642-
abi.name()
643-
)
644-
}
645-
}
646-
647646
pub fn isolation_error(name: &str) -> InterpResult<'static> {
648647
throw_machine_stop!(TerminationInfo::UnsupportedInIsolation(format!(
649648
"{} not available when isolation is enabled",

src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#![feature(map_try_insert)]
44
#![feature(never_type)]
55
#![feature(try_blocks)]
6+
#![feature(bool_to_option)]
67
#![warn(rust_2018_idioms)]
78
#![allow(clippy::cast_lossless)]
89

@@ -14,6 +15,7 @@ extern crate rustc_data_structures;
1415
extern crate rustc_hir;
1516
extern crate rustc_index;
1617
extern crate rustc_mir;
18+
extern crate rustc_session;
1719
extern crate rustc_span;
1820
extern crate rustc_target;
1921

0 commit comments

Comments
 (0)