rustc_sanitizers/ignorelist/
mod.rs1pub use ffi::Blame;
2use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
3use rustc_target::spec::SanitizerSet;
4
5pub(crate) mod ffi;
6
7#[inline]
8pub fn is_blame_ignored(no_san: Blame, san: Blame) -> bool {
9 no_san.is_some() && (san.is_none() || no_san > san)
10}
11
12pub struct SanitizerIgnoreList {
13 inner: *mut ffi::Opaque,
14}
15
16#[derive(#[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for InstanceSanitizers { }
#[automatically_derived]
impl ::core::clone::Clone for InstanceSanitizers {
#[inline]
fn clone(&self) -> InstanceSanitizers {
let _: ::core::clone::AssertParamIsClone<SanitizerSet>;
let _: ::core::clone::AssertParamIsClone<bool>;
*self
}
}Clone, #[automatically_derived]
impl ::core::marker::Copy for InstanceSanitizers { }Copy, #[automatically_derived]
impl ::core::fmt::Debug for InstanceSanitizers {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field3_finish(f,
"InstanceSanitizers", "enabled", &self.enabled, "ignore_cfi",
&self.ignore_cfi, "ignore_kcfi", &&self.ignore_kcfi)
}
}Debug)]
17pub struct InstanceSanitizers {
18 pub enabled: SanitizerSet,
19 pub ignore_cfi: bool,
20 pub ignore_kcfi: bool,
21}
22
23impl SanitizerIgnoreList {
24 pub fn new(paths: &[String]) -> Result<Self, String> {
25 use std::ffi::CString;
26 let c_paths: Vec<CString> =
27 paths.iter().map(|p| CString::new(p.as_str()).unwrap()).collect();
28 let c_ptrs: Vec<*const libc::c_char> = c_paths.iter().map(|c| c.as_ptr()).collect();
29
30 let mut inner = std::ptr::null_mut();
31 let err = ffi::build_string(|err| unsafe {
32 inner = ffi::LLVMRustSpecialCaseListCreate(c_ptrs.as_ptr(), c_ptrs.len(), err);
33 });
34
35 let err = err.unwrap_or_else(|e| ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("utf8 error: {0}", e))
})format!("utf8 error: {}", e));
36 if inner.is_null() { Err(err) } else { Ok(Self { inner }) }
37 }
38
39 pub fn in_section_blame(
40 &self,
41 section: &std::ffi::CStr,
42 prefix: &std::ffi::CStr,
43 query: &str,
44 ) -> (Blame, Blame) {
45 let mask = section_to_sanitizer_set(section);
46 let mut no_san = Blame::NONE;
47 let mut san = Blame::NONE;
48 let Ok(query) = std::ffi::CString::new(query) else {
49 return (Blame::NONE, Blame::NONE);
50 };
51 unsafe {
52 ffi::LLVMRustSpecialCaseListInSectionBlame(
53 self.inner,
54 mask.map(|s| s.bits() as u32).unwrap_or(0),
55 section.as_ptr(),
56 prefix.as_ptr(),
57 query.as_ptr(),
58 &mut no_san,
59 &mut san,
60 );
61 }
62 (no_san, san)
63 }
64
65 pub fn instance_blame<'tcx>(
66 &self,
67 tcx: TyCtxt<'tcx>,
68 instance: Instance<'tcx>,
69 section: &std::ffi::CStr,
70 ) -> (Blame, Blame) {
71 let sym_name = tcx.symbol_name(instance).name;
72 let span = tcx.def_span(instance.def_id());
73 let filename =
74 tcx.sess.source_map().span_to_filename(span).prefer_local_unconditionally().to_string();
75 let mainfile = tcx
76 .sess
77 .local_crate_source_file()
78 .and_then(|path| path.local_path().map(|p| p.display().to_string()))
79 .unwrap_or_default();
80 let demangled =
81 { let _guard = NoTrimmedGuard::new(); tcx.def_path_str(instance.def_id()) }rustc_middle::ty::print::with_no_trimmed_paths!(tcx.def_path_str(instance.def_id()));
82
83 let mut no_san = Blame::NONE;
84 let mut san = Blame::NONE;
85 let mut update = |prefix: &std::ffi::CStr, query: &str| {
86 let (ns, s) = self.in_section_blame(section, prefix, query);
87 no_san = no_san.max(ns);
88 san = san.max(s);
89 };
90
91 update(c"fun", sym_name);
92 update(c"fun", &demangled);
93 update(c"src", &filename);
94 if !mainfile.is_empty() {
95 update(c"mainfile", &mainfile);
96 }
97
98 (no_san, san)
99 }
100
101 pub fn is_instance_ignored<'tcx>(
102 &self,
103 tcx: TyCtxt<'tcx>,
104 instance: Instance<'tcx>,
105 section: &std::ffi::CStr,
106 ) -> bool {
107 let (no_san, san) = self.instance_blame(tcx, instance, section);
108 is_blame_ignored(no_san, san)
109 }
110
111 pub fn filter_instance_sanitizers<'tcx>(
112 &self,
113 tcx: TyCtxt<'tcx>,
114 instance: Instance<'tcx>,
115 mut enabled: SanitizerSet,
116 ) -> InstanceSanitizers {
117 let (address_nosan, address_san) = self.instance_blame(tcx, instance, c"address");
118 let (kaddress_nosan, kaddress_san) = self.instance_blame(tcx, instance, c"kernel-address");
119 let (hwaddress_nosan, hwaddress_san) = self.instance_blame(tcx, instance, c"hwaddress");
120 let (khwaddress_nosan, khwaddress_san) =
121 self.instance_blame(tcx, instance, c"kernel-hwaddress");
122
123 let ignore_address = is_blame_ignored(address_nosan, address_san);
124 let ignore_kernel_address = is_blame_ignored(kaddress_nosan, kaddress_san);
125
126 let ignore_hwaddress = is_blame_ignored(hwaddress_nosan, hwaddress_san);
127 let ignore_kernel_hwaddress = is_blame_ignored(khwaddress_nosan, khwaddress_san);
128
129 if enabled.contains(SanitizerSet::ADDRESS) && ignore_address {
130 enabled.remove(SanitizerSet::ADDRESS);
131 }
132 if enabled.contains(SanitizerSet::KERNELADDRESS) && ignore_kernel_address {
133 enabled.remove(SanitizerSet::KERNELADDRESS);
134 }
135 if enabled.contains(SanitizerSet::MEMORY)
136 && self.is_instance_ignored(tcx, instance, c"memory")
137 {
138 enabled.remove(SanitizerSet::MEMORY);
139 }
140 if enabled.contains(SanitizerSet::THREAD)
141 && self.is_instance_ignored(tcx, instance, c"thread")
142 {
143 enabled.remove(SanitizerSet::THREAD);
144 }
145 if enabled.contains(SanitizerSet::HWADDRESS) && ignore_hwaddress {
146 enabled.remove(SanitizerSet::HWADDRESS);
147 }
148 if enabled.contains(SanitizerSet::KERNELHWADDRESS) && ignore_kernel_hwaddress {
149 enabled.remove(SanitizerSet::KERNELHWADDRESS);
150 }
151 let ignore_cfi = self.is_instance_ignored(tcx, instance, c"cfi");
156 let ignore_kcfi = self.is_instance_ignored(tcx, instance, c"kcfi");
157
158 InstanceSanitizers { enabled, ignore_cfi, ignore_kcfi }
159 }
160
161 pub fn contains_prefix(
162 &self,
163 section: &std::ffi::CStr,
164 prefix: &std::ffi::CStr,
165 query: &str,
166 ) -> bool {
167 let (no_san, san) = self.in_section_blame(section, prefix, query);
168 is_blame_ignored(no_san, san)
169 }
170}
171
172impl Drop for SanitizerIgnoreList {
173 fn drop(&mut self) {
174 unsafe {
175 ffi::LLVMRustSpecialCaseListDestroy(self.inner);
176 }
177 }
178}
179
180pub fn typename_for_ignore_list<'tcx>(
181 tcx: TyCtxt<'tcx>,
182 fn_abi: &rustc_target::callconv::FnAbi<'tcx, Ty<'tcx>>,
183) -> String {
184 let inputs: Vec<_> = fn_abi.args.iter().map(|arg| arg.layout.ty).collect();
185 let output = fn_abi.ret.layout.ty;
186 let mut fn_sig_kind = ty::FnSigKind::default();
187 fn_sig_kind = fn_sig_kind.set_safety(rustc_hir::Safety::Safe);
188 fn_sig_kind = fn_sig_kind.set_c_variadic(fn_abi.c_variadic);
189 let fn_sig = tcx.mk_fn_sig(inputs, output, fn_sig_kind);
190 let fn_ptr = Ty::new_fn_ptr(tcx, ty::Binder::dummy(fn_sig));
191 { let _guard = NoTrimmedGuard::new(); fn_ptr.to_string() }ty::print::with_no_trimmed_paths!(fn_ptr.to_string())
192}
193
194fn section_to_sanitizer_set(section: &std::ffi::CStr) -> Option<SanitizerSet> {
195 match section.to_bytes() {
196 b"address" => Some(SanitizerSet::ADDRESS),
197 b"kernel-address" | b"kasan" => Some(SanitizerSet::KERNELADDRESS),
198 b"memory" => Some(SanitizerSet::MEMORY),
199 b"thread" => Some(SanitizerSet::THREAD),
200 b"hwaddress" => Some(SanitizerSet::HWADDRESS),
201 b"kernel-hwaddress" | b"khwasan" => Some(SanitizerSet::KERNELHWADDRESS),
202 b"safestack" | b"safe-stack" => Some(SanitizerSet::SAFESTACK),
203 b"shadow-call-stack" | b"shadowcallstack" => Some(SanitizerSet::SHADOWCALLSTACK),
204 b"cfi" | b"cfi-icall" => Some(SanitizerSet::CFI),
205 b"kcfi" => Some(SanitizerSet::KCFI),
206 b"memtag" => Some(SanitizerSet::MEMTAG),
207 b"realtime" => Some(SanitizerSet::REALTIME),
208 b"leak" => Some(SanitizerSet::LEAK),
209 b"dataflow" => Some(SanitizerSet::DATAFLOW),
210 _ => None,
211 }
212}