Skip to content

Commit

Permalink
Target modifiers (special marked options) are recorded in metainfo an…
Browse files Browse the repository at this point in the history
…d compared to be equal in different crates
  • Loading branch information
azhogin committed Nov 26, 2024
1 parent bca5fde commit 9cd86c3
Show file tree
Hide file tree
Showing 18 changed files with 478 additions and 21 deletions.
7 changes: 4 additions & 3 deletions compiler/rustc_driver_impl/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1160,11 +1160,12 @@ fn describe_codegen_flags() {

fn print_flag_list<T>(
cmdline_opt: &str,
flag_list: &[(&'static str, T, &'static str, &'static str)],
flag_list: &[(&'static str, T, &'static str, &'static str, bool)],
) {
let max_len = flag_list.iter().map(|&(name, _, _, _)| name.chars().count()).max().unwrap_or(0);
let max_len =
flag_list.iter().map(|&(name, _, _, _, _)| name.chars().count()).max().unwrap_or(0);

for &(name, _, _, desc) in flag_list {
for &(name, _, _, desc, _) in flag_list {
safe_println!(
" {} {:>width$}=val -- {}",
cmdline_opt,
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_interface/src/passes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,7 @@ fn configure_and_expand(

resolver.resolve_crate(&krate);

CStore::from_tcx(tcx).report_incompatible_target_modifiers(tcx, &krate, resolver.lint_buffer());
krate
}

Expand Down
7 changes: 7 additions & 0 deletions compiler/rustc_lint/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -415,6 +415,13 @@ lint_improper_ctypes_union_layout_help = consider adding a `#[repr(C)]` or `#[re
lint_improper_ctypes_union_layout_reason = this union has unspecified layout
lint_improper_ctypes_union_non_exhaustive = this union is non-exhaustive

lint_incompatible_target_modifiers =
mixing `{$flag_name_prefixed}` will cause an ABI mismatch
.note1 = `{$flag_name_prefixed}={$flag_local_value}` in this crate is incompatible with `{$flag_name_prefixed}={$flag_extern_value}` in dependency `{$extern_crate}`
.help = `{$flag_name_prefixed}` modifies the ABI and Rust crates compiled with different values of this flag cannot be used together safely
.suggestion = set `{$flag_name_prefixed}=${flag_extern_value}` in this crate or `{$flag_name_prefixed}=${flag_local_value}` in `{$extern_crate}`
.note2 = alternatively, use `-Cunsafe-allow-abi-mismatch={$flag_name}` to silence this error

lint_incomplete_include =
include macro expected single expression in source

Expand Down
16 changes: 16 additions & 0 deletions compiler/rustc_lint/src/context/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,22 @@ pub(super) fn decorate_lint(sess: &Session, diagnostic: BuiltinLintDiag, diag: &
lints::UnusedCrateDependency { extern_crate, local_crate }.decorate_lint(diag)
}
BuiltinLintDiag::WasmCAbi => lints::WasmCAbi.decorate_lint(diag),
BuiltinLintDiag::IncompatibleTargetModifiers {
extern_crate,
local_crate,
flag_name,
flag_name_prefixed,
flag_local_value,
flag_extern_value,
} => lints::IncompatibleTargetModifiers {
extern_crate,
local_crate,
flag_name,
flag_name_prefixed,
flag_local_value,
flag_extern_value,
}
.decorate_lint(diag),
BuiltinLintDiag::IllFormedAttributeInput { suggestions } => {
lints::IllFormedAttributeInput {
num_suggestions: suggestions.len(),
Expand Down
14 changes: 14 additions & 0 deletions compiler/rustc_lint/src/lints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2470,6 +2470,20 @@ pub(crate) struct UnusedCrateDependency {
pub local_crate: Symbol,
}

#[derive(LintDiagnostic)]
#[diag(lint_incompatible_target_modifiers)]
#[help]
#[note(lint_note1)]
#[note(lint_note2)]
pub(crate) struct IncompatibleTargetModifiers {
pub extern_crate: Symbol,
pub local_crate: Symbol,
pub flag_name: String,
pub flag_name_prefixed: String,
pub flag_local_value: String,
pub flag_extern_value: String,
}

#[derive(LintDiagnostic)]
#[diag(lint_wasm_c_abi)]
pub(crate) struct WasmCAbi;
Expand Down
41 changes: 41 additions & 0 deletions compiler/rustc_lint_defs/src/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ declare_lint_pass! {
FUZZY_PROVENANCE_CASTS,
HIDDEN_GLOB_REEXPORTS,
ILL_FORMED_ATTRIBUTE_INPUT,
INCOMPATIBLE_TARGET_MODIFIERS,
INCOMPLETE_INCLUDE,
INEFFECTIVE_UNSTABLE_TRAIT_IMPL,
INLINE_NO_SANITIZE,
Expand Down Expand Up @@ -578,6 +579,46 @@ declare_lint! {
crate_level_only
}

declare_lint! {
/// The `incompatible_target_modifiers` lint detects crates with incompatible target modifiers
/// (abi-changing or vulnerability-affecting flags).
///
/// ### Example
///
/// ```rust,ignore (needs extern crate)
/// #![deny(incompatible_target_modifiers)]
/// ```
///
/// When main and dependency crates are compiled with `-Zregparm=1` and `-Zregparm=2` correspondingly.
///
/// This will produce:
///
/// ```text
/// error: mixing `-Zregparm` will cause an ABI mismatch
/// --> $DIR/incompatible_regparm.rs:12:1
/// |
/// LL | #![crate_type = "lib"]
/// | ^
/// |
/// = help: `-Zregparm` modifies the ABI and Rust crates compiled with different values of this flag cannot be used together safely
/// = note: `-Zregparm=1` in this crate is incompatible with `-Zregparm=2` in dependency `wrong_regparm`
/// = note: alternatively, use `-Cunsafe-allow-abi-mismatch=regparm` to silence this error
/// = note: `#[deny(incompatible_target_modifiers)]` on by default
/// ```
///
/// ### Explanation
///
/// `Target modifiers` are compilation flags that affects abi or vulnerability resistance.
/// Linking together crates with incompatible target modifiers would produce incorrect code
/// or degradation of vulnerability resistance.
/// So this lint should find such inconsistency.
///
pub INCOMPATIBLE_TARGET_MODIFIERS,
Deny,
"Incompatible target modifiers",
crate_level_only
}

declare_lint! {
/// The `unused_qualifications` lint detects unnecessarily qualified
/// names.
Expand Down
8 changes: 8 additions & 0 deletions compiler/rustc_lint_defs/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -719,6 +719,14 @@ pub enum BuiltinLintDiag {
AvoidUsingIntelSyntax,
AvoidUsingAttSyntax,
IncompleteInclude,
IncompatibleTargetModifiers {
extern_crate: Symbol,
local_crate: Symbol,
flag_name: String,
flag_name_prefixed: String,
flag_local_value: String,
flag_extern_value: String,
},
UnnameableTestItems,
DuplicateMacroAttribute,
CfgAttrNoAttributes,
Expand Down
121 changes: 118 additions & 3 deletions compiler/rustc_metadata/src/creader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ use rustc_hir::definitions::Definitions;
use rustc_index::IndexVec;
use rustc_middle::bug;
use rustc_middle::ty::{TyCtxt, TyCtxtFeed};
use rustc_session::config::{self, CrateType, ExternLocation};
use rustc_session::config::{self, CrateType, ExternLocation, TargetModifier};
use rustc_session::cstore::{CrateDepKind, CrateSource, ExternCrate, ExternCrateSource};
use rustc_session::lint::{self, BuiltinLintDiag};
use rustc_session::lint::{self, BuiltinLintDiag, LintBuffer};
use rustc_session::output::validate_crate_name;
use rustc_session::search_paths::PathKind;
use rustc_span::edition::Edition;
Expand All @@ -35,7 +35,9 @@ use tracing::{debug, info, trace};

use crate::errors;
use crate::locator::{CrateError, CrateLocator, CratePaths};
use crate::rmeta::{CrateDep, CrateMetadata, CrateNumMap, CrateRoot, MetadataBlob};
use crate::rmeta::{
CrateDep, CrateMetadata, CrateNumMap, CrateRoot, MetadataBlob, TargetModifiers,
};

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

pub fn report_incompatible_target_modifiers(
&self,
tcx: TyCtxt<'_>,
krate: &Crate,
lints: &mut LintBuffer,
) {
if tcx.crate_types().contains(&CrateType::ProcMacro) {
return;
}
let sess = tcx.sess;
let empty_vec = Vec::<String>::new();
let allowed_flag_mismatches = match sess.opts.cg.unsafe_allow_abi_mismatch.as_ref() {
Some(vec) => {
if vec.is_empty() {
// Setting `-Zunsafe-allow-abi-mismatch=` to an empty
// value allows all target modifier mismatches.
return;
}
vec
}
None => &empty_vec,
};
let span = krate.spans.inner_span.shrink_to_lo();

let name = tcx.crate_name(LOCAL_CRATE);
let mods = sess.opts.gather_target_modifiers();
for (_cnum, data) in self.iter_crate_data() {
if data.is_proc_macro_crate() {
continue;
}
let mut report_diff = |opt_name_hash: u64,
flag_local_value: &String,
flag_extern_value: &String| {
let name_info = sess.opts.target_modifier_info_by_hash(opt_name_hash);
let (prefix, opt_name) = name_info.expect("Target modifier not found by name hash");
if allowed_flag_mismatches.contains(&opt_name) {
return;
}
lints.buffer_lint(
lint::builtin::INCOMPATIBLE_TARGET_MODIFIERS,
ast::CRATE_NODE_ID,
span,
BuiltinLintDiag::IncompatibleTargetModifiers {
extern_crate: data.name(),
local_crate: name,
flag_name: opt_name.clone(),
flag_name_prefixed: format!("-{}{}", prefix, opt_name),
flag_local_value: flag_local_value.to_string(),
flag_extern_value: flag_extern_value.to_string(),
},
);
};
let mut it1 = mods.iter();
let mut it2 = data.target_modifiers();
let mut left_name_val: Option<TargetModifier> = None;
let mut right_name_val: Option<TargetModifier> = None;
let no_val = "*".to_string();
loop {
left_name_val = left_name_val.or_else(|| it1.next().cloned());
right_name_val = right_name_val.or_else(|| it2.next().cloned());
match (&left_name_val, &right_name_val) {
(Some(l), Some(r)) => match l.name_hash.cmp(&r.name_hash) {
cmp::Ordering::Equal => {
if l.value_code != r.value_code {
report_diff(l.name_hash, &l.value_name, &r.value_name);
}
left_name_val = None;
right_name_val = None;
}
cmp::Ordering::Greater => {
report_diff(r.name_hash, &no_val, &r.value_name);
right_name_val = None;
}
cmp::Ordering::Less => {
report_diff(l.name_hash, &l.value_name, &no_val);
left_name_val = None;
}
},
(Some(l), None) => {
report_diff(l.name_hash, &l.value_name, &no_val);
left_name_val = None;
}
(None, Some(r)) => {
report_diff(r.name_hash, &no_val, &r.value_name);
right_name_val = None;
}
(None, None) => break,
}
}
}
}

pub fn new(metadata_loader: Box<MetadataLoaderDyn>) -> CStore {
CStore {
metadata_loader,
Expand Down Expand Up @@ -432,6 +526,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
};

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

let raw_proc_macros = if crate_root.is_proc_macro_crate() {
let temp_root;
Expand All @@ -456,6 +551,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
raw_proc_macros,
cnum,
cnum_map,
target_modifiers,
dep_kind,
source,
private_dep,
Expand Down Expand Up @@ -689,6 +785,25 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
Ok(crate_num_map)
}

fn resolve_target_modifiers(
&mut self,
crate_root: &CrateRoot,
metadata: &MetadataBlob,
krate: CrateNum,
) -> Result<TargetModifiers, CrateError> {
debug!("resolving target modifiers of external crate");
if crate_root.is_proc_macro_crate() {
return Ok(TargetModifiers::new());
}
let mods = crate_root.decode_target_modifiers(metadata);
let mut target_modifiers = TargetModifiers::with_capacity(mods.len());
for modifier in mods {
target_modifiers.push(modifier);
}
debug!("resolve_target_modifiers: target mods for {:?} is {:?}", krate, target_modifiers);
Ok(target_modifiers)
}

fn dlsym_proc_macros(
&self,
path: &Path,
Expand Down
19 changes: 19 additions & 0 deletions compiler/rustc_metadata/src/rmeta/decoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ use rustc_middle::{bug, implement_ty_decoder};
use rustc_serialize::opaque::MemDecoder;
use rustc_serialize::{Decodable, Decoder};
use rustc_session::Session;
use rustc_session::config::TargetModifier;
use rustc_session::cstore::{CrateSource, ExternCrate};
use rustc_span::hygiene::HygieneDecodeContext;
use rustc_span::symbol::kw;
Expand Down Expand Up @@ -73,6 +74,9 @@ impl MetadataBlob {
/// own crate numbers.
pub(crate) type CrateNumMap = IndexVec<CrateNum, CrateNum>;

/// Target modifiers - abi / vulnerability-resist affecting flags
pub(crate) type TargetModifiers = Vec<TargetModifier>;

pub(crate) struct CrateMetadata {
/// The primary crate data - binary metadata blob.
blob: MetadataBlob,
Expand Down Expand Up @@ -110,6 +114,8 @@ pub(crate) struct CrateMetadata {
cnum_map: CrateNumMap,
/// Same ID set as `cnum_map` plus maybe some injected crates like panic runtime.
dependencies: Vec<CrateNum>,
/// Target modifiers - abi and vulnerability-resist affecting flags the crate was compiled with
target_modifiers: TargetModifiers,
/// How to link (or not link) this crate to the currently compiled crate.
dep_kind: CrateDepKind,
/// Filesystem location of this crate.
Expand Down Expand Up @@ -960,6 +966,13 @@ impl CrateRoot {
) -> impl ExactSizeIterator<Item = CrateDep> + Captures<'a> {
self.crate_deps.decode(metadata)
}

pub(crate) fn decode_target_modifiers<'a>(
&self,
metadata: &'a MetadataBlob,
) -> impl ExactSizeIterator<Item = TargetModifier> + Captures<'a> {
self.target_modifiers.decode(metadata)
}
}

impl<'a> CrateMetadataRef<'a> {
Expand Down Expand Up @@ -1815,6 +1828,7 @@ impl CrateMetadata {
raw_proc_macros: Option<&'static [ProcMacro]>,
cnum: CrateNum,
cnum_map: CrateNumMap,
target_modifiers: TargetModifiers,
dep_kind: CrateDepKind,
source: CrateSource,
private_dep: bool,
Expand Down Expand Up @@ -1846,6 +1860,7 @@ impl CrateMetadata {
cnum,
cnum_map,
dependencies,
target_modifiers,
dep_kind,
source: Lrc::new(source),
private_dep,
Expand Down Expand Up @@ -1875,6 +1890,10 @@ impl CrateMetadata {
self.dependencies.push(cnum);
}

pub(crate) fn target_modifiers(&self) -> impl Iterator<Item = &TargetModifier> + '_ {
self.target_modifiers.iter()
}

pub(crate) fn update_extern_crate(&mut self, new_extern_crate: ExternCrate) -> bool {
let update =
Some(new_extern_crate.rank()) > self.extern_crate.as_ref().map(ExternCrate::rank);
Expand Down
Loading

0 comments on commit 9cd86c3

Please sign in to comment.