Skip to content

Commit 9cd86c3

Browse files
committed
Target modifiers (special marked options) are recorded in metainfo and compared to be equal in different crates
1 parent bca5fde commit 9cd86c3

File tree

18 files changed

+478
-21
lines changed

18 files changed

+478
-21
lines changed

Diff for: compiler/rustc_driver_impl/src/lib.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -1160,11 +1160,12 @@ fn describe_codegen_flags() {
11601160

11611161
fn print_flag_list<T>(
11621162
cmdline_opt: &str,
1163-
flag_list: &[(&'static str, T, &'static str, &'static str)],
1163+
flag_list: &[(&'static str, T, &'static str, &'static str, bool)],
11641164
) {
1165-
let max_len = flag_list.iter().map(|&(name, _, _, _)| name.chars().count()).max().unwrap_or(0);
1165+
let max_len =
1166+
flag_list.iter().map(|&(name, _, _, _, _)| name.chars().count()).max().unwrap_or(0);
11661167

1167-
for &(name, _, _, desc) in flag_list {
1168+
for &(name, _, _, desc, _) in flag_list {
11681169
safe_println!(
11691170
" {} {:>width$}=val -- {}",
11701171
cmdline_opt,

Diff for: compiler/rustc_interface/src/passes.rs

+1
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,7 @@ fn configure_and_expand(
281281

282282
resolver.resolve_crate(&krate);
283283

284+
CStore::from_tcx(tcx).report_incompatible_target_modifiers(tcx, &krate, resolver.lint_buffer());
284285
krate
285286
}
286287

Diff for: compiler/rustc_lint/messages.ftl

+7
Original file line numberDiff line numberDiff line change
@@ -415,6 +415,13 @@ lint_improper_ctypes_union_layout_help = consider adding a `#[repr(C)]` or `#[re
415415
lint_improper_ctypes_union_layout_reason = this union has unspecified layout
416416
lint_improper_ctypes_union_non_exhaustive = this union is non-exhaustive
417417

418+
lint_incompatible_target_modifiers =
419+
mixing `{$flag_name_prefixed}` will cause an ABI mismatch
420+
.note1 = `{$flag_name_prefixed}={$flag_local_value}` in this crate is incompatible with `{$flag_name_prefixed}={$flag_extern_value}` in dependency `{$extern_crate}`
421+
.help = `{$flag_name_prefixed}` modifies the ABI and Rust crates compiled with different values of this flag cannot be used together safely
422+
.suggestion = set `{$flag_name_prefixed}=${flag_extern_value}` in this crate or `{$flag_name_prefixed}=${flag_local_value}` in `{$extern_crate}`
423+
.note2 = alternatively, use `-Cunsafe-allow-abi-mismatch={$flag_name}` to silence this error
424+
418425
lint_incomplete_include =
419426
include macro expected single expression in source
420427

Diff for: compiler/rustc_lint/src/context/diagnostics.rs

+16
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,22 @@ pub(super) fn decorate_lint(sess: &Session, diagnostic: BuiltinLintDiag, diag: &
422422
lints::UnusedCrateDependency { extern_crate, local_crate }.decorate_lint(diag)
423423
}
424424
BuiltinLintDiag::WasmCAbi => lints::WasmCAbi.decorate_lint(diag),
425+
BuiltinLintDiag::IncompatibleTargetModifiers {
426+
extern_crate,
427+
local_crate,
428+
flag_name,
429+
flag_name_prefixed,
430+
flag_local_value,
431+
flag_extern_value,
432+
} => lints::IncompatibleTargetModifiers {
433+
extern_crate,
434+
local_crate,
435+
flag_name,
436+
flag_name_prefixed,
437+
flag_local_value,
438+
flag_extern_value,
439+
}
440+
.decorate_lint(diag),
425441
BuiltinLintDiag::IllFormedAttributeInput { suggestions } => {
426442
lints::IllFormedAttributeInput {
427443
num_suggestions: suggestions.len(),

Diff for: compiler/rustc_lint/src/lints.rs

+14
Original file line numberDiff line numberDiff line change
@@ -2470,6 +2470,20 @@ pub(crate) struct UnusedCrateDependency {
24702470
pub local_crate: Symbol,
24712471
}
24722472

2473+
#[derive(LintDiagnostic)]
2474+
#[diag(lint_incompatible_target_modifiers)]
2475+
#[help]
2476+
#[note(lint_note1)]
2477+
#[note(lint_note2)]
2478+
pub(crate) struct IncompatibleTargetModifiers {
2479+
pub extern_crate: Symbol,
2480+
pub local_crate: Symbol,
2481+
pub flag_name: String,
2482+
pub flag_name_prefixed: String,
2483+
pub flag_local_value: String,
2484+
pub flag_extern_value: String,
2485+
}
2486+
24732487
#[derive(LintDiagnostic)]
24742488
#[diag(lint_wasm_c_abi)]
24752489
pub(crate) struct WasmCAbi;

Diff for: compiler/rustc_lint_defs/src/builtin.rs

+41
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ declare_lint_pass! {
4949
FUZZY_PROVENANCE_CASTS,
5050
HIDDEN_GLOB_REEXPORTS,
5151
ILL_FORMED_ATTRIBUTE_INPUT,
52+
INCOMPATIBLE_TARGET_MODIFIERS,
5253
INCOMPLETE_INCLUDE,
5354
INEFFECTIVE_UNSTABLE_TRAIT_IMPL,
5455
INLINE_NO_SANITIZE,
@@ -578,6 +579,46 @@ declare_lint! {
578579
crate_level_only
579580
}
580581

582+
declare_lint! {
583+
/// The `incompatible_target_modifiers` lint detects crates with incompatible target modifiers
584+
/// (abi-changing or vulnerability-affecting flags).
585+
///
586+
/// ### Example
587+
///
588+
/// ```rust,ignore (needs extern crate)
589+
/// #![deny(incompatible_target_modifiers)]
590+
/// ```
591+
///
592+
/// When main and dependency crates are compiled with `-Zregparm=1` and `-Zregparm=2` correspondingly.
593+
///
594+
/// This will produce:
595+
///
596+
/// ```text
597+
/// error: mixing `-Zregparm` will cause an ABI mismatch
598+
/// --> $DIR/incompatible_regparm.rs:12:1
599+
/// |
600+
/// LL | #![crate_type = "lib"]
601+
/// | ^
602+
/// |
603+
/// = help: `-Zregparm` modifies the ABI and Rust crates compiled with different values of this flag cannot be used together safely
604+
/// = note: `-Zregparm=1` in this crate is incompatible with `-Zregparm=2` in dependency `wrong_regparm`
605+
/// = note: alternatively, use `-Cunsafe-allow-abi-mismatch=regparm` to silence this error
606+
/// = note: `#[deny(incompatible_target_modifiers)]` on by default
607+
/// ```
608+
///
609+
/// ### Explanation
610+
///
611+
/// `Target modifiers` are compilation flags that affects abi or vulnerability resistance.
612+
/// Linking together crates with incompatible target modifiers would produce incorrect code
613+
/// or degradation of vulnerability resistance.
614+
/// So this lint should find such inconsistency.
615+
///
616+
pub INCOMPATIBLE_TARGET_MODIFIERS,
617+
Deny,
618+
"Incompatible target modifiers",
619+
crate_level_only
620+
}
621+
581622
declare_lint! {
582623
/// The `unused_qualifications` lint detects unnecessarily qualified
583624
/// names.

Diff for: compiler/rustc_lint_defs/src/lib.rs

+8
Original file line numberDiff line numberDiff line change
@@ -719,6 +719,14 @@ pub enum BuiltinLintDiag {
719719
AvoidUsingIntelSyntax,
720720
AvoidUsingAttSyntax,
721721
IncompleteInclude,
722+
IncompatibleTargetModifiers {
723+
extern_crate: Symbol,
724+
local_crate: Symbol,
725+
flag_name: String,
726+
flag_name_prefixed: String,
727+
flag_local_value: String,
728+
flag_extern_value: String,
729+
},
722730
UnnameableTestItems,
723731
DuplicateMacroAttribute,
724732
CfgAttrNoAttributes,

Diff for: compiler/rustc_metadata/src/creader.rs

+118-3
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,9 @@ use rustc_hir::definitions::Definitions;
2222
use rustc_index::IndexVec;
2323
use rustc_middle::bug;
2424
use rustc_middle::ty::{TyCtxt, TyCtxtFeed};
25-
use rustc_session::config::{self, CrateType, ExternLocation};
25+
use rustc_session::config::{self, CrateType, ExternLocation, TargetModifier};
2626
use rustc_session::cstore::{CrateDepKind, CrateSource, ExternCrate, ExternCrateSource};
27-
use rustc_session::lint::{self, BuiltinLintDiag};
27+
use rustc_session::lint::{self, BuiltinLintDiag, LintBuffer};
2828
use rustc_session::output::validate_crate_name;
2929
use rustc_session::search_paths::PathKind;
3030
use rustc_span::edition::Edition;
@@ -35,7 +35,9 @@ use tracing::{debug, info, trace};
3535

3636
use crate::errors;
3737
use crate::locator::{CrateError, CrateLocator, CratePaths};
38-
use crate::rmeta::{CrateDep, CrateMetadata, CrateNumMap, CrateRoot, MetadataBlob};
38+
use crate::rmeta::{
39+
CrateDep, CrateMetadata, CrateNumMap, CrateRoot, MetadataBlob, TargetModifiers,
40+
};
3941

4042
/// The backend's way to give the crate store access to the metadata in a library.
4143
/// Note that it returns the raw metadata bytes stored in the library file, whether
@@ -290,6 +292,98 @@ impl CStore {
290292
}
291293
}
292294

295+
pub fn report_incompatible_target_modifiers(
296+
&self,
297+
tcx: TyCtxt<'_>,
298+
krate: &Crate,
299+
lints: &mut LintBuffer,
300+
) {
301+
if tcx.crate_types().contains(&CrateType::ProcMacro) {
302+
return;
303+
}
304+
let sess = tcx.sess;
305+
let empty_vec = Vec::<String>::new();
306+
let allowed_flag_mismatches = match sess.opts.cg.unsafe_allow_abi_mismatch.as_ref() {
307+
Some(vec) => {
308+
if vec.is_empty() {
309+
// Setting `-Zunsafe-allow-abi-mismatch=` to an empty
310+
// value allows all target modifier mismatches.
311+
return;
312+
}
313+
vec
314+
}
315+
None => &empty_vec,
316+
};
317+
let span = krate.spans.inner_span.shrink_to_lo();
318+
319+
let name = tcx.crate_name(LOCAL_CRATE);
320+
let mods = sess.opts.gather_target_modifiers();
321+
for (_cnum, data) in self.iter_crate_data() {
322+
if data.is_proc_macro_crate() {
323+
continue;
324+
}
325+
let mut report_diff = |opt_name_hash: u64,
326+
flag_local_value: &String,
327+
flag_extern_value: &String| {
328+
let name_info = sess.opts.target_modifier_info_by_hash(opt_name_hash);
329+
let (prefix, opt_name) = name_info.expect("Target modifier not found by name hash");
330+
if allowed_flag_mismatches.contains(&opt_name) {
331+
return;
332+
}
333+
lints.buffer_lint(
334+
lint::builtin::INCOMPATIBLE_TARGET_MODIFIERS,
335+
ast::CRATE_NODE_ID,
336+
span,
337+
BuiltinLintDiag::IncompatibleTargetModifiers {
338+
extern_crate: data.name(),
339+
local_crate: name,
340+
flag_name: opt_name.clone(),
341+
flag_name_prefixed: format!("-{}{}", prefix, opt_name),
342+
flag_local_value: flag_local_value.to_string(),
343+
flag_extern_value: flag_extern_value.to_string(),
344+
},
345+
);
346+
};
347+
let mut it1 = mods.iter();
348+
let mut it2 = data.target_modifiers();
349+
let mut left_name_val: Option<TargetModifier> = None;
350+
let mut right_name_val: Option<TargetModifier> = None;
351+
let no_val = "*".to_string();
352+
loop {
353+
left_name_val = left_name_val.or_else(|| it1.next().cloned());
354+
right_name_val = right_name_val.or_else(|| it2.next().cloned());
355+
match (&left_name_val, &right_name_val) {
356+
(Some(l), Some(r)) => match l.name_hash.cmp(&r.name_hash) {
357+
cmp::Ordering::Equal => {
358+
if l.value_code != r.value_code {
359+
report_diff(l.name_hash, &l.value_name, &r.value_name);
360+
}
361+
left_name_val = None;
362+
right_name_val = None;
363+
}
364+
cmp::Ordering::Greater => {
365+
report_diff(r.name_hash, &no_val, &r.value_name);
366+
right_name_val = None;
367+
}
368+
cmp::Ordering::Less => {
369+
report_diff(l.name_hash, &l.value_name, &no_val);
370+
left_name_val = None;
371+
}
372+
},
373+
(Some(l), None) => {
374+
report_diff(l.name_hash, &l.value_name, &no_val);
375+
left_name_val = None;
376+
}
377+
(None, Some(r)) => {
378+
report_diff(r.name_hash, &no_val, &r.value_name);
379+
right_name_val = None;
380+
}
381+
(None, None) => break,
382+
}
383+
}
384+
}
385+
}
386+
293387
pub fn new(metadata_loader: Box<MetadataLoaderDyn>) -> CStore {
294388
CStore {
295389
metadata_loader,
@@ -432,6 +526,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
432526
};
433527

434528
let cnum_map = self.resolve_crate_deps(root, &crate_root, &metadata, cnum, dep_kind)?;
529+
let target_modifiers = self.resolve_target_modifiers(&crate_root, &metadata, cnum)?;
435530

436531
let raw_proc_macros = if crate_root.is_proc_macro_crate() {
437532
let temp_root;
@@ -456,6 +551,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
456551
raw_proc_macros,
457552
cnum,
458553
cnum_map,
554+
target_modifiers,
459555
dep_kind,
460556
source,
461557
private_dep,
@@ -689,6 +785,25 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
689785
Ok(crate_num_map)
690786
}
691787

788+
fn resolve_target_modifiers(
789+
&mut self,
790+
crate_root: &CrateRoot,
791+
metadata: &MetadataBlob,
792+
krate: CrateNum,
793+
) -> Result<TargetModifiers, CrateError> {
794+
debug!("resolving target modifiers of external crate");
795+
if crate_root.is_proc_macro_crate() {
796+
return Ok(TargetModifiers::new());
797+
}
798+
let mods = crate_root.decode_target_modifiers(metadata);
799+
let mut target_modifiers = TargetModifiers::with_capacity(mods.len());
800+
for modifier in mods {
801+
target_modifiers.push(modifier);
802+
}
803+
debug!("resolve_target_modifiers: target mods for {:?} is {:?}", krate, target_modifiers);
804+
Ok(target_modifiers)
805+
}
806+
692807
fn dlsym_proc_macros(
693808
&self,
694809
path: &Path,

Diff for: compiler/rustc_metadata/src/rmeta/decoder.rs

+19
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ use rustc_middle::{bug, implement_ty_decoder};
2828
use rustc_serialize::opaque::MemDecoder;
2929
use rustc_serialize::{Decodable, Decoder};
3030
use rustc_session::Session;
31+
use rustc_session::config::TargetModifier;
3132
use rustc_session::cstore::{CrateSource, ExternCrate};
3233
use rustc_span::hygiene::HygieneDecodeContext;
3334
use rustc_span::symbol::kw;
@@ -73,6 +74,9 @@ impl MetadataBlob {
7374
/// own crate numbers.
7475
pub(crate) type CrateNumMap = IndexVec<CrateNum, CrateNum>;
7576

77+
/// Target modifiers - abi / vulnerability-resist affecting flags
78+
pub(crate) type TargetModifiers = Vec<TargetModifier>;
79+
7680
pub(crate) struct CrateMetadata {
7781
/// The primary crate data - binary metadata blob.
7882
blob: MetadataBlob,
@@ -110,6 +114,8 @@ pub(crate) struct CrateMetadata {
110114
cnum_map: CrateNumMap,
111115
/// Same ID set as `cnum_map` plus maybe some injected crates like panic runtime.
112116
dependencies: Vec<CrateNum>,
117+
/// Target modifiers - abi and vulnerability-resist affecting flags the crate was compiled with
118+
target_modifiers: TargetModifiers,
113119
/// How to link (or not link) this crate to the currently compiled crate.
114120
dep_kind: CrateDepKind,
115121
/// Filesystem location of this crate.
@@ -960,6 +966,13 @@ impl CrateRoot {
960966
) -> impl ExactSizeIterator<Item = CrateDep> + Captures<'a> {
961967
self.crate_deps.decode(metadata)
962968
}
969+
970+
pub(crate) fn decode_target_modifiers<'a>(
971+
&self,
972+
metadata: &'a MetadataBlob,
973+
) -> impl ExactSizeIterator<Item = TargetModifier> + Captures<'a> {
974+
self.target_modifiers.decode(metadata)
975+
}
963976
}
964977

965978
impl<'a> CrateMetadataRef<'a> {
@@ -1815,6 +1828,7 @@ impl CrateMetadata {
18151828
raw_proc_macros: Option<&'static [ProcMacro]>,
18161829
cnum: CrateNum,
18171830
cnum_map: CrateNumMap,
1831+
target_modifiers: TargetModifiers,
18181832
dep_kind: CrateDepKind,
18191833
source: CrateSource,
18201834
private_dep: bool,
@@ -1846,6 +1860,7 @@ impl CrateMetadata {
18461860
cnum,
18471861
cnum_map,
18481862
dependencies,
1863+
target_modifiers,
18491864
dep_kind,
18501865
source: Lrc::new(source),
18511866
private_dep,
@@ -1875,6 +1890,10 @@ impl CrateMetadata {
18751890
self.dependencies.push(cnum);
18761891
}
18771892

1893+
pub(crate) fn target_modifiers(&self) -> impl Iterator<Item = &TargetModifier> + '_ {
1894+
self.target_modifiers.iter()
1895+
}
1896+
18781897
pub(crate) fn update_extern_crate(&mut self, new_extern_crate: ExternCrate) -> bool {
18791898
let update =
18801899
Some(new_extern_crate.rank()) > self.extern_crate.as_ref().map(ExternCrate::rank);

0 commit comments

Comments
 (0)