Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

sanitizers: Stabilize AddressSanitizer and LeakSanitizer for the Tier 1 targets #123617

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions compiler/rustc_codegen_llvm/src/abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ pub(crate) use rustc_middle::ty::layout::{WIDE_PTR_ADDR, WIDE_PTR_EXTRA};
use rustc_middle::{bug, ty};
use rustc_session::config;
pub(crate) use rustc_target::callconv::*;
use rustc_target::spec::SanitizerSet;
use smallvec::SmallVec;

use crate::attributes::llfn_attrs_from_instance;
Expand Down Expand Up @@ -84,7 +83,7 @@ fn get_attrs<'ll>(this: &ArgAttributes, cx: &CodegenCx<'ll, '_>) -> SmallVec<[&'
attrs.push(llattr.create_attr(cx.llcx));
}
}
} else if cx.tcx.sess.opts.unstable_opts.sanitizer.contains(SanitizerSet::MEMORY) {
} else if cx.tcx.sess.is_sanitizer_memory_enabled() {
// If we're not optimising, *but* memory sanitizer is on, emit noundef, since it affects
// memory sanitizer's behavior.

Expand Down
10 changes: 2 additions & 8 deletions compiler/rustc_codegen_llvm/src/attributes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ pub(crate) fn sanitize_attrs<'ll>(
no_sanitize: SanitizerSet,
) -> SmallVec<[&'ll Attribute; 4]> {
let mut attrs = SmallVec::new();
let enabled = cx.tcx.sess.opts.unstable_opts.sanitizer - no_sanitize;
let enabled = cx.tcx.sess.opts.cg.sanitize - no_sanitize;
if enabled.contains(SanitizerSet::ADDRESS) || enabled.contains(SanitizerSet::KERNELADDRESS) {
attrs.push(llvm::AttributeKind::SanitizeAddress.create_attr(cx.llcx));
}
Expand Down Expand Up @@ -217,13 +217,7 @@ fn probestack_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&'ll Attribute> {
// Currently stack probes seem somewhat incompatible with the address
// sanitizer and thread sanitizer. With asan we're already protected from
// stack overflow anyway so we don't really need stack probes regardless.
if cx
.sess()
.opts
.unstable_opts
.sanitizer
.intersects(SanitizerSet::ADDRESS | SanitizerSet::THREAD)
{
if cx.sess().is_sanitizer_address_enabled() || cx.sess().is_sanitizer_thread_enabled() {
return None;
}

Expand Down
8 changes: 2 additions & 6 deletions compiler/rustc_codegen_ssa/src/back/link.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1315,7 +1315,7 @@ fn add_sanitizer_libraries(
return;
}

let sanitizer = sess.opts.unstable_opts.sanitizer;
let sanitizer = sess.opts.cg.sanitize;
if sanitizer.contains(SanitizerSet::ADDRESS) {
link_sanitizer_runtime(sess, flavor, linker, "asan");
}
Expand Down Expand Up @@ -2447,11 +2447,7 @@ fn add_order_independent_options(
&& crate_type == CrateType::Executable
&& !matches!(flavor, LinkerFlavor::Gnu(Cc::Yes, _))
{
let prefix = if sess.opts.unstable_opts.sanitizer.contains(SanitizerSet::ADDRESS) {
"asan/"
} else {
""
};
let prefix = if sess.is_sanitizer_address_enabled() { "asan/" } else { "" };
cmd.link_arg(format!("--dynamic-linker={prefix}ld.so.1"));
}

Expand Down
8 changes: 4 additions & 4 deletions compiler/rustc_codegen_ssa/src/back/symbol_export.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use rustc_middle::query::LocalCrate;
use rustc_middle::ty::{self, GenericArgKind, GenericArgsRef, Instance, SymbolName, TyCtxt};
use rustc_middle::util::Providers;
use rustc_session::config::{CrateType, OomStrategy};
use rustc_target::spec::{SanitizerSet, TlsModel};
use rustc_target::spec::TlsModel;
use tracing::debug;

use crate::base::allocator_kind_for_codegen;
Expand Down Expand Up @@ -247,15 +247,15 @@ fn exported_symbols_provider_local(
}));
}

if tcx.sess.opts.unstable_opts.sanitizer.contains(SanitizerSet::MEMORY) {
if tcx.sess.is_sanitizer_memory_enabled() {
let mut msan_weak_symbols = Vec::new();

// Similar to profiling, preserve weak msan symbol during LTO.
if tcx.sess.opts.unstable_opts.sanitizer_recover.contains(SanitizerSet::MEMORY) {
if tcx.sess.is_sanitizer_memory_recover_enabled() {
msan_weak_symbols.push("__msan_keep_going");
}

if tcx.sess.opts.unstable_opts.sanitizer_memory_track_origins != 0 {
if tcx.sess.is_sanitizer_memory_track_origins_enabled() {
msan_weak_symbols.push("__msan_track_origins");
}

Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_codegen_ssa/src/back/write.rs
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ impl ModuleConfig {
debug_info_for_profiling: sess.opts.unstable_opts.debug_info_for_profiling,
instrument_coverage: if_regular!(sess.instrument_coverage(), false),

sanitizer: if_regular!(sess.opts.unstable_opts.sanitizer, SanitizerSet::empty()),
sanitizer: if_regular!(sess.opts.cg.sanitize, SanitizerSet::empty()),
sanitizer_dataflow_abilist: if_regular!(
sess.opts.unstable_opts.sanitizer_dataflow_abilist.clone(),
Vec::new()
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_feature/src/accepted.rs
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,8 @@ declare_features! (
(accepted, native_link_modifiers_whole_archive, "1.61.0", Some(81490)),
/// Allows using non lexical lifetimes (RFC 2094).
(accepted, nll, "1.63.0", Some(43234)),
/// Allows the use of `no_sanitize` attribute.
(accepted, no_sanitize, "CURRENT_RUSTC_VERSION", Some(39699)),
/// Allows using `#![no_std]`.
(accepted, no_std, "1.6.0", None),
/// Allows defining identifiers beyond ASCII.
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_feature/src/builtin_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -475,10 +475,10 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
),
ungated!(track_caller, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::Yes),
ungated!(instruction_set, Normal, template!(List: "set"), ErrorPreceding, EncodeCrossCrate::No),
gated!(
ungated!(
no_sanitize, Normal,
template!(List: "address, kcfi, memory, thread"), DuplicatesOk,
EncodeCrossCrate::No, experimental!(no_sanitize)
EncodeCrossCrate::No
),
ungated!(
coverage, Normal, template!(OneOf: &[sym::off, sym::on]),
Expand Down
2 changes: 0 additions & 2 deletions compiler/rustc_feature/src/unstable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -563,8 +563,6 @@ declare_features! (
(unstable, never_type_fallback, "1.41.0", Some(65992)),
/// Allows `#![no_core]`.
(unstable, no_core, "1.3.0", Some(29639)),
/// Allows the use of `no_sanitize` attribute.
(unstable, no_sanitize, "1.42.0", Some(39699)),
/// Allows using the `non_exhaustive_omitted_patterns` lint.
(unstable, non_exhaustive_omitted_patterns_lint, "1.57.0", Some(89554)),
/// Allows `for<T>` binders in where-clauses
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_interface/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -633,6 +633,7 @@ fn test_codegen_options_tracking_hash() {
tracked!(profile_use, Some(PathBuf::from("abc")));
tracked!(relocation_model, Some(RelocModel::Pic));
tracked!(relro_level, Some(RelroLevel::Full));
tracked!(sanitize, SanitizerSet::ADDRESS);
tracked!(soft_float, true);
tracked!(split_debuginfo, Some(SplitDebuginfo::Packed));
tracked!(symbol_mangling_version, Some(SymbolManglingVersion::V0));
Expand Down Expand Up @@ -839,7 +840,6 @@ fn test_unstable_options_tracking_hash() {
tracked!(regparm, Some(3));
tracked!(relax_elf_relocations, Some(true));
tracked!(remap_cwd_prefix, Some(PathBuf::from("abc")));
tracked!(sanitizer, SanitizerSet::ADDRESS);
tracked!(sanitizer_cfi_canonical_jump_tables, None);
tracked!(sanitizer_cfi_generalize_pointers, Some(true));
tracked!(sanitizer_cfi_normalize_integers, Some(true));
Expand Down
2 changes: 0 additions & 2 deletions compiler/rustc_lint_defs/src/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2440,8 +2440,6 @@ declare_lint! {
/// ### Example
///
/// ```rust
/// #![feature(no_sanitize)]
///
/// #[inline(always)]
/// #[no_sanitize(address)]
/// fn x() {}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_metadata/src/native_libs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ pub fn walk_native_lib_search_dirs<R>(
|| sess.target.os == "linux"
|| sess.target.os == "fuchsia"
|| sess.target.is_like_aix
|| sess.target.is_like_osx && !sess.opts.unstable_opts.sanitizer.is_empty()
|| sess.target.is_like_osx && !sess.opts.cg.sanitize.is_empty()
{
f(&sess.target_tlib_path.dir, false)?;
}
Expand Down
12 changes: 6 additions & 6 deletions compiler/rustc_session/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ session_branch_protection_requires_aarch64 = `-Zbranch-protection` is only suppo

session_cannot_enable_crt_static_linux = sanitizer is incompatible with statically linked libc, disable it using `-C target-feature=-crt-static`

session_cannot_mix_and_match_sanitizers = `-Zsanitizer={$first}` is incompatible with `-Zsanitizer={$second}`
session_cannot_mix_and_match_sanitizers = `-Csanitize={$first}` is incompatible with `-Csanitize={$second}`

session_cli_feature_diagnostic_help =
add `-Zcrate-attr="feature({$feature})"` to the command-line options to enable
Expand Down Expand Up @@ -88,15 +88,15 @@ session_profile_sample_use_file_does_not_exist = file `{$path}` passed to `-C pr

session_profile_use_file_does_not_exist = file `{$path}` passed to `-C profile-use` does not exist

session_sanitizer_cfi_canonical_jump_tables_requires_cfi = `-Zsanitizer-cfi-canonical-jump-tables` requires `-Zsanitizer=cfi`
session_sanitizer_cfi_canonical_jump_tables_requires_cfi = `-Zsanitizer-cfi-canonical-jump-tables` requires `-Csanitize=cfi`

session_sanitizer_cfi_generalize_pointers_requires_cfi = `-Zsanitizer-cfi-generalize-pointers` requires `-Zsanitizer=cfi` or `-Zsanitizer=kcfi`
session_sanitizer_cfi_generalize_pointers_requires_cfi = `-Zsanitizer-cfi-generalize-pointers` requires `-Csanitize=cfi` or `-Csanitize=kcfi`

session_sanitizer_cfi_normalize_integers_requires_cfi = `-Zsanitizer-cfi-normalize-integers` requires `-Zsanitizer=cfi` or `-Zsanitizer=kcfi`
session_sanitizer_cfi_normalize_integers_requires_cfi = `-Zsanitizer-cfi-normalize-integers` requires `-Csanitize=cfi` or `-Csanitize=kcfi`

session_sanitizer_cfi_requires_lto = `-Zsanitizer=cfi` requires `-Clto` or `-Clinker-plugin-lto`
session_sanitizer_cfi_requires_lto = `-Csanitize=cfi` requires `-Clto` or `-Clinker-plugin-lto`

session_sanitizer_cfi_requires_single_codegen_unit = `-Zsanitizer=cfi` with `-Clto` requires `-Ccodegen-units=1`
session_sanitizer_cfi_requires_single_codegen_unit = `-Csanitize=cfi` with `-Clto` requires `-Ccodegen-units=1`

session_sanitizer_kcfi_requires_panic_abort = `-Z sanitizer=kcfi` requires `-C panic=abort`

Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_session/src/config/cfg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ pub(crate) fn default_configuration(sess: &Session) -> Cfg {
ins_sym!(sym::relocation_model, sess.target.relocation_model.desc_symbol());
}

for mut s in sess.opts.unstable_opts.sanitizer {
for mut s in sess.opts.cg.sanitize {
// KASAN is still ASAN under the hood, so it uses the same attribute.
if s == SanitizerSet::KERNELADDRESS {
s = SanitizerSet::ADDRESS;
Expand Down
29 changes: 9 additions & 20 deletions compiler/rustc_session/src/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -813,25 +813,14 @@ pub mod parse {
}

pub(crate) fn parse_sanitizers(slot: &mut SanitizerSet, v: Option<&str>) -> bool {
if let Some(v) = v {
for s in v.split(',') {
*slot |= match s {
"address" => SanitizerSet::ADDRESS,
"cfi" => SanitizerSet::CFI,
"dataflow" => SanitizerSet::DATAFLOW,
"kcfi" => SanitizerSet::KCFI,
"kernel-address" => SanitizerSet::KERNELADDRESS,
"leak" => SanitizerSet::LEAK,
"memory" => SanitizerSet::MEMORY,
"memtag" => SanitizerSet::MEMTAG,
"shadow-call-stack" => SanitizerSet::SHADOWCALLSTACK,
"thread" => SanitizerSet::THREAD,
"hwaddress" => SanitizerSet::HWADDRESS,
"safestack" => SanitizerSet::SAFESTACK,
_ => return false,
}
if let Some(s) = v {
let sanitizer_set = SanitizerSet::from_comma_list(s);
if sanitizer_set.is_ok() {
*slot |= sanitizer_set.unwrap();
true
} else {
false
}
true
} else {
false
}
Expand Down Expand Up @@ -1648,6 +1637,8 @@ options! {
"output remarks for these optimization passes (space separated, or \"all\")"),
rpath: bool = (false, parse_bool, [UNTRACKED],
"set rpath values in libs/exes (default: no)"),
sanitize: SanitizerSet = (SanitizerSet::empty(), parse_sanitizers, [TRACKED],
"use one or multiple sanitizers"),
save_temps: bool = (false, parse_bool, [UNTRACKED],
"save all temporary output files during compilation (default: no)"),
soft_float: bool = (false, parse_bool, [TRACKED],
Expand Down Expand Up @@ -2018,8 +2009,6 @@ options! {
remark_dir: Option<PathBuf> = (None, parse_opt_pathbuf, [UNTRACKED],
"directory into which to write optimization remarks (if not specified, they will be \
written to standard error output)"),
sanitizer: SanitizerSet = (SanitizerSet::empty(), parse_sanitizers, [TRACKED],
"use a sanitizer"),
sanitizer_cfi_canonical_jump_tables: Option<bool> = (Some(true), parse_opt_bool, [TRACKED],
"enable canonical jump tables (default: yes)"),
sanitizer_cfi_generalize_pointers: Option<bool> = (None, parse_opt_bool, [TRACKED],
Expand Down
57 changes: 45 additions & 12 deletions compiler/rustc_session/src/session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -357,8 +357,12 @@ impl Session {
self.opts.unstable_opts.coverage_options.discard_all_spans_in_codegen
}

pub fn is_sanitizer_address_enabled(&self) -> bool {
wesleywiser marked this conversation as resolved.
Show resolved Hide resolved
self.opts.cg.sanitize.contains(SanitizerSet::ADDRESS)
}

pub fn is_sanitizer_cfi_enabled(&self) -> bool {
self.opts.unstable_opts.sanitizer.contains(SanitizerSet::CFI)
self.opts.cg.sanitize.contains(SanitizerSet::CFI)
}

pub fn is_sanitizer_cfi_canonical_jump_tables_disabled(&self) -> bool {
Expand All @@ -377,8 +381,32 @@ impl Session {
self.opts.unstable_opts.sanitizer_cfi_normalize_integers == Some(true)
}

pub fn is_sanitizer_hwaddress_enabled(&self) -> bool {
self.opts.cg.sanitize.contains(SanitizerSet::HWADDRESS)
}

pub fn is_sanitizer_kcfi_enabled(&self) -> bool {
self.opts.unstable_opts.sanitizer.contains(SanitizerSet::KCFI)
self.opts.cg.sanitize.contains(SanitizerSet::KCFI)
}

pub fn is_sanitizer_kernel_address_enabled(&self) -> bool {
self.opts.cg.sanitize.contains(SanitizerSet::KERNELADDRESS)
}

pub fn is_sanitizer_memory_enabled(&self) -> bool {
self.opts.cg.sanitize.contains(SanitizerSet::MEMORY)
}

pub fn is_sanitizer_memory_recover_enabled(&self) -> bool {
self.opts.unstable_opts.sanitizer_recover.contains(SanitizerSet::MEMORY)
}

pub fn is_sanitizer_memory_track_origins_enabled(&self) -> bool {
self.opts.unstable_opts.sanitizer_memory_track_origins != 0
}

pub fn is_sanitizer_thread_enabled(&self) -> bool {
self.opts.cg.sanitize.contains(SanitizerSet::THREAD)
}

pub fn is_split_lto_unit_enabled(&self) -> bool {
Expand Down Expand Up @@ -560,7 +588,10 @@ impl Session {
// AddressSanitizer and KernelAddressSanitizer uses lifetimes to detect use after scope bugs.
// MemorySanitizer uses lifetimes to detect use of uninitialized stack variables.
// HWAddressSanitizer will use lifetimes to detect use after scope bugs in the future.
|| self.opts.unstable_opts.sanitizer.intersects(SanitizerSet::ADDRESS | SanitizerSet::KERNELADDRESS | SanitizerSet::MEMORY | SanitizerSet::HWADDRESS)
|| self.is_sanitizer_address_enabled()
|| self.is_sanitizer_kernel_address_enabled()
|| self.is_sanitizer_memory_enabled()
|| self.is_sanitizer_hwaddress_enabled()
}

pub fn diagnostic_width(&self) -> usize {
Expand Down Expand Up @@ -688,7 +719,7 @@ impl Session {
let more_names = self.opts.output_types.contains_key(&OutputType::LlvmAssembly)
|| self.opts.output_types.contains_key(&OutputType::Bitcode)
// AddressSanitizer and MemorySanitizer use alloca name when reporting an issue.
|| self.opts.unstable_opts.sanitizer.intersects(SanitizerSet::ADDRESS | SanitizerSet::MEMORY);
|| self.is_sanitizer_address_enabled() || self.is_sanitizer_memory_enabled();
!more_names
}
}
Expand Down Expand Up @@ -1131,14 +1162,19 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
}
}

// Sanitizers can only be used on platforms that we know have working sanitizer codegen.
let supported_sanitizers = sess.target.options.supported_sanitizers;
let mut unsupported_sanitizers = sess.opts.unstable_opts.sanitizer - supported_sanitizers;
let supported_sanitizers = if sess.unstable_options() {
sess.target.options.supported_sanitizers | sess.target.options.stable_sanitizers
} else {
sess.target.options.stable_sanitizers
};
let mut unsupported_sanitizers = sess.opts.cg.sanitize - supported_sanitizers;

// Niche: if `fixed-x18`, or effectively switching on `reserved-x18` flag, is enabled
// we should allow Shadow Call Stack sanitizer.
if sess.opts.unstable_opts.fixed_x18 && sess.target.arch == "aarch64" {
unsupported_sanitizers -= SanitizerSet::SHADOWCALLSTACK;
}

match unsupported_sanitizers.into_iter().count() {
0 => {}
1 => {
Expand All @@ -1153,18 +1189,15 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
}

// Cannot mix and match mutually-exclusive sanitizers.
if let Some((first, second)) = sess.opts.unstable_opts.sanitizer.mutually_exclusive() {
if let Some((first, second)) = sess.opts.cg.sanitize.mutually_exclusive() {
sess.dcx().emit_err(errors::CannotMixAndMatchSanitizers {
first: first.to_string(),
second: second.to_string(),
});
}

// Cannot enable crt-static with sanitizers on Linux
if sess.crt_static(None)
&& !sess.opts.unstable_opts.sanitizer.is_empty()
&& !sess.target.is_like_msvc
{
if sess.crt_static(None) && !sess.opts.cg.sanitize.is_empty() && !sess.target.is_like_msvc {
sess.dcx().emit_err(errors::CannotEnableCrtStaticLinux);
}

Expand Down
Loading
Loading