Make meta-item API compatible with LocalInternedString::get soundness fix

This commit is contained in:
Vadim Petrochenkov 2019-03-17 14:17:47 +03:00
parent 7cf074a1e6
commit db74efce69
17 changed files with 84 additions and 97 deletions

View file

@ -177,16 +177,8 @@ impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> {
let mut is_transparent = false; let mut is_transparent = false;
for hint in &hints { for hint in &hints {
let name = if let Some(name) = hint.ident_str() { let (article, allowed_targets) = match hint.name_or_empty().get() {
name name @ "C" | name @ "align" => {
} else {
// Invalid repr hint like repr(42). We don't check for unrecognized hints here
// (libsyntax does that), so just ignore it.
continue;
};
let (article, allowed_targets) = match name {
"C" | "align" => {
is_c |= name == "C"; is_c |= name == "C";
if target != Target::Struct && if target != Target::Struct &&
target != Target::Union && target != Target::Union &&

View file

@ -194,7 +194,7 @@ impl<'a> LintLevelsBuilder<'a> {
struct_span_err!(sess, span, E0452, "malformed lint attribute") struct_span_err!(sess, span, E0452, "malformed lint attribute")
}; };
for attr in attrs { for attr in attrs {
let level = match attr.ident_str().and_then(|name| Level::from_str(name)) { let level = match Level::from_str(&attr.name_or_empty()) {
None => continue, None => continue,
Some(lvl) => lvl, Some(lvl) => lvl,
}; };

View file

@ -723,12 +723,7 @@ pub fn struct_lint_level<'a>(sess: &'a Session,
pub fn maybe_lint_level_root(tcx: TyCtxt<'_, '_, '_>, id: hir::HirId) -> bool { pub fn maybe_lint_level_root(tcx: TyCtxt<'_, '_, '_>, id: hir::HirId) -> bool {
let attrs = tcx.hir().attrs_by_hir_id(id); let attrs = tcx.hir().attrs_by_hir_id(id);
for attr in attrs { attrs.iter().any(|attr| Level::from_str(&attr.name_or_empty()).is_some())
if attr.ident_str().and_then(Level::from_str).is_some() {
return true;
}
}
false
} }
fn lint_levels<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, cnum: CrateNum) fn lint_levels<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, cnum: CrateNum)

View file

@ -65,9 +65,9 @@ impl<'a, 'tcx> LibFeatureCollector<'a, 'tcx> {
for meta in metas { for meta in metas {
if let Some(mi) = meta.meta_item() { if let Some(mi) = meta.meta_item() {
// Find the `feature = ".."` meta-item. // Find the `feature = ".."` meta-item.
match (mi.ident_str(), mi.value_str()) { match (mi.name_or_empty().get(), mi.value_str()) {
(Some("feature"), val) => feature = val, ("feature", val) => feature = val,
(Some("since"), val) => since = val, ("since", val) => since = val,
_ => {} _ => {}
} }
} }

View file

@ -194,12 +194,11 @@ impl<'a, 'tcx: 'a> Annotator<'a, 'tcx> {
} else { } else {
// Emit errors for non-staged-api crates. // Emit errors for non-staged-api crates.
for attr in attrs { for attr in attrs {
if let Some(tag) = attr.ident_str() { let name = attr.name_or_empty();
if tag == "unstable" || tag == "stable" || tag == "rustc_deprecated" { if ["unstable", "stable", "rustc_deprecated"].contains(&name.get()) {
attr::mark_used(attr); attr::mark_used(attr);
self.tcx.sess.span_err(attr.span, "stability attributes may not be used \ self.tcx.sess.span_err(attr.span, "stability attributes may not be used \
outside of the standard library"); outside of the standard library");
}
} }
} }

View file

@ -177,9 +177,9 @@ impl<'a, 'gcx, 'tcx> OnUnimplementedDirective {
for command in self.subcommands.iter().chain(Some(self)).rev() { for command in self.subcommands.iter().chain(Some(self)).rev() {
if let Some(ref condition) = command.condition { if let Some(ref condition) = command.condition {
if !attr::eval_condition(condition, &tcx.sess.parse_sess, &mut |c| { if !attr::eval_condition(condition, &tcx.sess.parse_sess, &mut |c| {
c.ident_str().map_or(false, |name| { c.ident().map_or(false, |ident| {
options.contains(&( options.contains(&(
name.to_string(), ident.to_string(),
c.value_str().map(|s| s.as_str().to_string()) c.value_str().map(|s| s.as_str().to_string())
)) ))
}) })

View file

@ -576,8 +576,8 @@ fn expect_associated_value(tcx: TyCtxt<'_, '_, '_>, item: &NestedMetaItem) -> as
if let Some(value) = item.value_str() { if let Some(value) = item.value_str() {
value value
} else { } else {
let msg = if let Some(name) = item.ident_str() { let msg = if let Some(ident) = item.ident() {
format!("associated value expected for `{}`", name) format!("associated value expected for `{}`", ident)
} else { } else {
"expected an associated value".to_string() "expected an associated value".to_string()
}; };

View file

@ -759,8 +759,9 @@ impl LintPass for DeprecatedAttr {
impl EarlyLintPass for DeprecatedAttr { impl EarlyLintPass for DeprecatedAttr {
fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &ast::Attribute) { fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &ast::Attribute) {
let name = attr.name_or_empty();
for &&(n, _, _, ref g) in &self.depr_attrs { for &&(n, _, _, ref g) in &self.depr_attrs {
if attr.ident_str() == Some(n) { if name == n {
if let &AttributeGate::Gated(Stability::Deprecated(link, suggestion), if let &AttributeGate::Gated(Stability::Deprecated(link, suggestion),
ref name, ref name,
ref reason, ref reason,

View file

@ -267,21 +267,21 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedAttributes {
} }
} }
let name = attr.ident_str(); let name = attr.name_or_empty();
if !attr::is_used(attr) { if !attr::is_used(attr) {
debug!("Emitting warning for: {:?}", attr); debug!("Emitting warning for: {:?}", attr);
cx.span_lint(UNUSED_ATTRIBUTES, attr.span, "unused attribute"); cx.span_lint(UNUSED_ATTRIBUTES, attr.span, "unused attribute");
// Is it a builtin attribute that must be used at the crate level? // Is it a builtin attribute that must be used at the crate level?
let known_crate = BUILTIN_ATTRIBUTES.iter() let known_crate = BUILTIN_ATTRIBUTES.iter()
.find(|&&(builtin, ty, ..)| { .find(|&&(builtin, ty, ..)| {
name == Some(builtin) && ty == AttributeType::CrateLevel name == builtin && ty == AttributeType::CrateLevel
}) })
.is_some(); .is_some();
// Has a plugin registered this attribute as one that must be used at // Has a plugin registered this attribute as one that must be used at
// the crate level? // the crate level?
let plugin_crate = plugin_attributes.iter() let plugin_crate = plugin_attributes.iter()
.find(|&&(ref x, t)| name == Some(x) && AttributeType::CrateLevel == t) .find(|&&(ref x, t)| name == x.as_str() && AttributeType::CrateLevel == t)
.is_some(); .is_some();
if known_crate || plugin_crate { if known_crate || plugin_crate {
let msg = match attr.style { let msg = match attr.style {

View file

@ -53,8 +53,7 @@ impl<'a, 'tcx> VarianceTest<'a, 'tcx> {
// The `..` are the names of fields to dump. // The `..` are the names of fields to dump.
let meta_items = attr.meta_item_list().unwrap_or_default(); let meta_items = attr.meta_item_list().unwrap_or_default();
for meta_item in meta_items { for meta_item in meta_items {
let name = meta_item.ident_str().unwrap_or(""); match meta_item.name_or_empty().get() {
match name {
"abi" => { "abi" => {
self.tcx self.tcx
.sess .sess
@ -84,7 +83,7 @@ impl<'a, 'tcx> VarianceTest<'a, 'tcx> {
); );
} }
_ => { name => {
self.tcx.sess.span_err( self.tcx.sess.span_err(
meta_item.span(), meta_item.span(),
&format!("unrecognized field name `{}`", name), &format!("unrecognized field name `{}`", name),

View file

@ -56,12 +56,12 @@ pub fn load_plugins(sess: &Session,
for plugin in plugins { for plugin in plugins {
// plugins must have a name and can't be key = value // plugins must have a name and can't be key = value
match plugin.ident_str() { let name = plugin.name_or_empty();
Some(name) if !plugin.is_value_str() => { if !name.is_empty() && !plugin.is_value_str() {
let args = plugin.meta_item_list().map(ToOwned::to_owned); let args = plugin.meta_item_list().map(ToOwned::to_owned);
loader.load_plugin(plugin.span(), name, args.unwrap_or_default()); loader.load_plugin(plugin.span(), &name, args.unwrap_or_default());
}, } else {
_ => call_malformed_plugin_attribute(sess, attr.span), call_malformed_plugin_attribute(sess, attr.span);
} }
} }
} }

View file

@ -521,21 +521,21 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt
for attr in krate.module.as_ref().unwrap().attrs.lists("doc") { for attr in krate.module.as_ref().unwrap().attrs.lists("doc") {
let diag = ctxt.sess().diagnostic(); let diag = ctxt.sess().diagnostic();
let name = attr.ident_str(); let name = attr.name_or_empty();
if attr.is_word() { if attr.is_word() {
if name == Some("no_default_passes") { if name == "no_default_passes" {
report_deprecated_attr("no_default_passes", diag); report_deprecated_attr("no_default_passes", diag);
if default_passes == passes::DefaultPassOption::Default { if default_passes == passes::DefaultPassOption::Default {
default_passes = passes::DefaultPassOption::None; default_passes = passes::DefaultPassOption::None;
} }
} }
} else if let Some(value) = attr.value_str() { } else if let Some(value) = attr.value_str() {
let sink = match name { let sink = match name.get() {
Some("passes") => { "passes" => {
report_deprecated_attr("passes = \"...\"", diag); report_deprecated_attr("passes = \"...\"", diag);
&mut manual_passes &mut manual_passes
}, },
Some("plugins") => { "plugins" => {
report_deprecated_attr("plugins = \"...\"", diag); report_deprecated_attr("plugins = \"...\"", diag);
eprintln!("WARNING: #![doc(plugins = \"...\")] no longer functions; \ eprintln!("WARNING: #![doc(plugins = \"...\")] no longer functions; \
see CVE-2018-1000622"); see CVE-2018-1000622");
@ -548,7 +548,7 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt
} }
} }
if attr.is_word() && name == Some("document_private_items") { if attr.is_word() && name == "document_private_items" {
if default_passes == passes::DefaultPassOption::Default { if default_passes == passes::DefaultPassOption::Default {
default_passes = passes::DefaultPassOption::Private; default_passes = passes::DefaultPassOption::Private;
} }

View file

@ -562,23 +562,23 @@ pub fn run(mut krate: clean::Crate,
// going to emit HTML // going to emit HTML
if let Some(attrs) = krate.module.as_ref().map(|m| &m.attrs) { if let Some(attrs) = krate.module.as_ref().map(|m| &m.attrs) {
for attr in attrs.lists("doc") { for attr in attrs.lists("doc") {
match (attr.ident_str(), attr.value_str()) { match (attr.name_or_empty().get(), attr.value_str()) {
(Some("html_favicon_url"), Some(s)) => { ("html_favicon_url", Some(s)) => {
scx.layout.favicon = s.to_string(); scx.layout.favicon = s.to_string();
} }
(Some("html_logo_url"), Some(s)) => { ("html_logo_url", Some(s)) => {
scx.layout.logo = s.to_string(); scx.layout.logo = s.to_string();
} }
(Some("html_playground_url"), Some(s)) => { ("html_playground_url", Some(s)) => {
markdown::PLAYGROUND.with(|slot| { markdown::PLAYGROUND.with(|slot| {
let name = krate.name.clone(); let name = krate.name.clone();
*slot.borrow_mut() = Some((Some(name), s.to_string())); *slot.borrow_mut() = Some((Some(name), s.to_string()));
}); });
} }
(Some("issue_tracker_base_url"), Some(s)) => { ("issue_tracker_base_url", Some(s)) => {
scx.issue_tracker_base_url = Some(s.to_string()); scx.issue_tracker_base_url = Some(s.to_string());
} }
(Some("html_no_source"), None) if attr.is_word() => { ("html_no_source", None) if attr.is_word() => {
scx.include_sources = false; scx.include_sources = false;
} }
_ => {} _ => {}
@ -3749,7 +3749,7 @@ fn render_attributes(w: &mut fmt::Formatter<'_>, it: &clean::Item) -> fmt::Resul
let mut attrs = String::new(); let mut attrs = String::new();
for attr in &it.attrs.other_attrs { for attr in &it.attrs.other_attrs {
if !attr.ident_str().map_or(false, |name| ATTRIBUTE_WHITELIST.contains(&name)) { if !ATTRIBUTE_WHITELIST.contains(&attr.name_or_empty().get()) {
continue; continue;
} }
if let Some(s) = render_attribute(&attr.meta().unwrap()) { if let Some(s) = render_attribute(&attr.meta().unwrap()) {

View file

@ -222,9 +222,9 @@ fn find_stability_generic<'a, I>(sess: &ParseSess,
)+ )+
for meta in metas { for meta in metas {
if let Some(mi) = meta.meta_item() { if let Some(mi) = meta.meta_item() {
match mi.ident_str() { match mi.name_or_empty().get() {
$( $(
Some(stringify!($name)) stringify!($name)
=> if !get(mi, &mut $name) { continue 'outer }, => if !get(mi, &mut $name) { continue 'outer },
)+ )+
_ => { _ => {
@ -252,7 +252,7 @@ fn find_stability_generic<'a, I>(sess: &ParseSess,
} }
} }
match meta.ident_str().expect("not a stability level") { match meta.name_or_empty().get() {
"rustc_deprecated" => { "rustc_deprecated" => {
if rustc_depr.is_some() { if rustc_depr.is_some() {
span_err!(diagnostic, item_sp, E0540, span_err!(diagnostic, item_sp, E0540,
@ -306,10 +306,10 @@ fn find_stability_generic<'a, I>(sess: &ParseSess,
let mut issue = None; let mut issue = None;
for meta in metas { for meta in metas {
if let Some(mi) = meta.meta_item() { if let Some(mi) = meta.meta_item() {
match mi.ident_str() { match mi.name_or_empty().get() {
Some("feature") => if !get(mi, &mut feature) { continue 'outer }, "feature" => if !get(mi, &mut feature) { continue 'outer },
Some("reason") => if !get(mi, &mut reason) { continue 'outer }, "reason" => if !get(mi, &mut reason) { continue 'outer },
Some("issue") => if !get(mi, &mut issue) { continue 'outer }, "issue" => if !get(mi, &mut issue) { continue 'outer },
_ => { _ => {
handle_errors( handle_errors(
sess, sess,
@ -377,10 +377,10 @@ fn find_stability_generic<'a, I>(sess: &ParseSess,
for meta in metas { for meta in metas {
match meta { match meta {
NestedMetaItem::MetaItem(mi) => { NestedMetaItem::MetaItem(mi) => {
match mi.ident_str() { match mi.name_or_empty().get() {
Some("feature") => "feature" =>
if !get(mi, &mut feature) { continue 'outer }, if !get(mi, &mut feature) { continue 'outer },
Some("since") => "since" =>
if !get(mi, &mut since) { continue 'outer }, if !get(mi, &mut since) { continue 'outer },
_ => { _ => {
handle_errors( handle_errors(
@ -532,14 +532,14 @@ pub fn eval_condition<F>(cfg: &ast::MetaItem, sess: &ParseSess, eval: &mut F)
// The unwraps below may look dangerous, but we've already asserted // The unwraps below may look dangerous, but we've already asserted
// that they won't fail with the loop above. // that they won't fail with the loop above.
match cfg.ident_str() { match cfg.name_or_empty().get() {
Some("any") => mis.iter().any(|mi| { "any" => mis.iter().any(|mi| {
eval_condition(mi.meta_item().unwrap(), sess, eval) eval_condition(mi.meta_item().unwrap(), sess, eval)
}), }),
Some("all") => mis.iter().all(|mi| { "all" => mis.iter().all(|mi| {
eval_condition(mi.meta_item().unwrap(), sess, eval) eval_condition(mi.meta_item().unwrap(), sess, eval)
}), }),
Some("not") => { "not" => {
if mis.len() != 1 { if mis.len() != 1 {
span_err!(sess.span_diagnostic, cfg.span, E0536, "expected 1 cfg-pattern"); span_err!(sess.span_diagnostic, cfg.span, E0536, "expected 1 cfg-pattern");
return false; return false;
@ -635,9 +635,9 @@ fn find_deprecation_generic<'a, I>(sess: &ParseSess,
for meta in list { for meta in list {
match meta { match meta {
NestedMetaItem::MetaItem(mi) => { NestedMetaItem::MetaItem(mi) => {
match mi.ident_str() { match mi.name_or_empty().get() {
Some("since") => if !get(mi, &mut since) { continue 'outer }, "since" => if !get(mi, &mut since) { continue 'outer },
Some("note") => if !get(mi, &mut note) { continue 'outer }, "note" => if !get(mi, &mut note) { continue 'outer },
_ => { _ => {
handle_errors( handle_errors(
sess, sess,
@ -729,12 +729,12 @@ pub fn find_repr_attrs(sess: &ParseSess, attr: &Attribute) -> Vec<ReprAttr> {
let mut recognised = false; let mut recognised = false;
if item.is_word() { if item.is_word() {
let hint = match item.ident_str() { let hint = match item.name_or_empty().get() {
Some("C") => Some(ReprC), "C" => Some(ReprC),
Some("packed") => Some(ReprPacked(1)), "packed" => Some(ReprPacked(1)),
Some("simd") => Some(ReprSimd), "simd" => Some(ReprSimd),
Some("transparent") => Some(ReprTransparent), "transparent" => Some(ReprTransparent),
name => name.and_then(|name| int_type_of_word(name)).map(ReprInt), name => int_type_of_word(name).map(ReprInt),
}; };
if let Some(h) = hint { if let Some(h) = hint {

View file

@ -22,7 +22,7 @@ use crate::parse::parser::Parser;
use crate::parse::{self, ParseSess, PResult}; use crate::parse::{self, ParseSess, PResult};
use crate::parse::token::{self, Token}; use crate::parse::token::{self, Token};
use crate::ptr::P; use crate::ptr::P;
use crate::symbol::Symbol; use crate::symbol::{keywords, LocalInternedString, Symbol};
use crate::ThinVec; use crate::ThinVec;
use crate::tokenstream::{TokenStream, TokenTree, DelimSpan}; use crate::tokenstream::{TokenStream, TokenTree, DelimSpan};
use crate::GLOBALS; use crate::GLOBALS;
@ -89,8 +89,8 @@ impl NestedMetaItem {
pub fn ident(&self) -> Option<Ident> { pub fn ident(&self) -> Option<Ident> {
self.meta_item().and_then(|meta_item| meta_item.ident()) self.meta_item().and_then(|meta_item| meta_item.ident())
} }
pub fn ident_str(&self) -> Option<&str> { pub fn name_or_empty(&self) -> LocalInternedString {
self.ident().map(|name| name.as_str().get()) self.ident().unwrap_or(keywords::Invalid.ident()).name.as_str()
} }
/// Gets the string value if self is a MetaItem and the MetaItem is a /// Gets the string value if self is a MetaItem and the MetaItem is a
@ -167,8 +167,8 @@ impl Attribute {
None None
} }
} }
pub fn ident_str(&self) -> Option<&str> { pub fn name_or_empty(&self) -> LocalInternedString {
self.ident().map(|name| name.as_str().get()) self.ident().unwrap_or(keywords::Invalid.ident()).name.as_str()
} }
pub fn value_str(&self) -> Option<Symbol> { pub fn value_str(&self) -> Option<Symbol> {
@ -205,8 +205,8 @@ impl MetaItem {
None None
} }
} }
pub fn ident_str(&self) -> Option<&str> { pub fn name_or_empty(&self) -> LocalInternedString {
self.ident().map(|name| name.as_str().get()) self.ident().unwrap_or(keywords::Invalid.ident()).name.as_str()
} }
// #[attribute(name = "value")] // #[attribute(name = "value")]

View file

@ -1341,9 +1341,9 @@ macro_rules! gate_feature {
impl<'a> Context<'a> { impl<'a> Context<'a> {
fn check_attribute(&self, attr: &ast::Attribute, is_macro: bool) { fn check_attribute(&self, attr: &ast::Attribute, is_macro: bool) {
debug!("check_attribute(attr = {:?})", attr); debug!("check_attribute(attr = {:?})", attr);
let name = attr.ident_str(); let name = attr.name_or_empty();
for &(n, ty, _template, ref gateage) in BUILTIN_ATTRIBUTES { for &(n, ty, _template, ref gateage) in BUILTIN_ATTRIBUTES {
if name == Some(n) { if name == n {
if let Gated(_, name, desc, ref has_feature) = *gateage { if let Gated(_, name, desc, ref has_feature) = *gateage {
if !attr.span.allows_unstable(name) { if !attr.span.allows_unstable(name) {
gate_feature_fn!( gate_feature_fn!(
@ -1373,7 +1373,7 @@ impl<'a> Context<'a> {
} }
} }
if !attr::is_known(attr) { if !attr::is_known(attr) {
if name.map_or(false, |name| name.starts_with("rustc_")) { if name.starts_with("rustc_") {
let msg = "unless otherwise specified, attributes with the prefix `rustc_` \ let msg = "unless otherwise specified, attributes with the prefix `rustc_` \
are reserved for internal compiler diagnostics"; are reserved for internal compiler diagnostics";
gate_feature!(self, rustc_attrs, attr.span, msg); gate_feature!(self, rustc_attrs, attr.span, msg);
@ -2054,12 +2054,12 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute],
}; };
for mi in list { for mi in list {
let name = match mi.ident_str() { if !mi.is_word() {
Some(name) if mi.is_word() => name, continue;
_ => continue, }
};
if incomplete_features.iter().any(|f| *f == name) { let name = mi.name_or_empty();
if incomplete_features.iter().any(|f| name == *f) {
span_handler.struct_span_warn( span_handler.struct_span_warn(
mi.span(), mi.span(),
&format!( &format!(

View file

@ -463,9 +463,10 @@ impl<'a> TraitDef<'a> {
let mut attrs = newitem.attrs.clone(); let mut attrs = newitem.attrs.clone();
attrs.extend(item.attrs attrs.extend(item.attrs
.iter() .iter()
.filter(|a| a.ident_str().map_or(false, |name| { .filter(|a| {
["allow", "warn", "deny", "forbid", "stable", "unstable"].contains(&name) ["allow", "warn", "deny", "forbid", "stable", "unstable"]
})) .contains(&a.name_or_empty().get())
})
.cloned()); .cloned());
push(Annotatable::Item(P(ast::Item { attrs: attrs, ..(*newitem).clone() }))) push(Annotatable::Item(P(ast::Item { attrs: attrs, ..(*newitem).clone() })))
} }