From 5e04c39e1b3d0478a0c017a07cf3c23b26cee48e Mon Sep 17 00:00:00 2001 From: AlexanderPortland Date: Fri, 26 Sep 2025 12:17:33 -0400 Subject: [PATCH 01/40] recognizing sniff-test attrs on functions --- Cargo.lock | 3 + crates/sniff-test-attrs/Cargo.toml | 1 + crates/sniff-test-attrs/src/lib.rs | 11 ++- crates/sniff-test/README.md | 6 ++ crates/sniff-test/src/lib.rs | 34 +++++----- crates/sniff-test/src/reachability/entry.rs | 74 +++++++++++++++++++++ crates/sniff-test/src/reachability/mod.rs | 3 + tests/unsafe/pass_simple/Cargo.lock | 27 ++++++++ 8 files changed, 143 insertions(+), 16 deletions(-) create mode 100644 crates/sniff-test/src/reachability/entry.rs create mode 100644 crates/sniff-test/src/reachability/mod.rs diff --git a/Cargo.lock b/Cargo.lock index ea0d159..ce1b55e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -382,6 +382,9 @@ dependencies = [ [[package]] name = "sniff-test-attrs" version = "0.1.0" +dependencies = [ + "quote", +] [[package]] name = "strsim" diff --git a/crates/sniff-test-attrs/Cargo.toml b/crates/sniff-test-attrs/Cargo.toml index 9e5c007..6c43f9a 100644 --- a/crates/sniff-test-attrs/Cargo.toml +++ b/crates/sniff-test-attrs/Cargo.toml @@ -7,3 +7,4 @@ edition = "2024" proc-macro = true [dependencies] +quote = "1.0.40" diff --git a/crates/sniff-test-attrs/src/lib.rs b/crates/sniff-test-attrs/src/lib.rs index 40527a4..45bcf2c 100644 --- a/crates/sniff-test-attrs/src/lib.rs +++ b/crates/sniff-test-attrs/src/lib.rs @@ -1,6 +1,15 @@ +#![feature(proc_macro_quote)] + use proc_macro::TokenStream; +use quote::quote; #[proc_macro_attribute] pub fn check_unsafe(_attr: TokenStream, item: TokenStream) -> TokenStream { - item + let attrs = quote!( + #[sniff_tool::check_unsafe] + ); + let mut t = TokenStream::new(); + t.extend(TokenStream::from(attrs)); + t.extend(item); + t } diff --git a/crates/sniff-test/README.md b/crates/sniff-test/README.md index 401ed15..fad523c 100644 --- a/crates/sniff-test/README.md +++ b/crates/sniff-test/README.md @@ -7,4 +7,10 @@ You should be able to just run this using `cargo build` and then running the res If you encounter an error along the lines of `dyld[43663]: Library not loaded: ...`, run: ```shell export DYLD_LIBRARY_PATH="$DYLD_LIBRARY_PATH:$(rustc +nightly-2025-08-20 --print target-libdir)" +``` + + +you can run the jawn with +```rust +cargo clean && RUSTFLAGS="-Zcrate-attr=feature(register_tool) -Zcrate-attr=register_tool(sniff_tool)" /Users/alexanderportland/Desktop/research/sniff-test/target/debug/cargo-sniff-test ``` \ No newline at end of file diff --git a/crates/sniff-test/src/lib.rs b/crates/sniff-test/src/lib.rs index 5f408e0..06a2a58 100644 --- a/crates/sniff-test/src/lib.rs +++ b/crates/sniff-test/src/lib.rs @@ -1,6 +1,7 @@ //! A Rustc plugin that prints out the name of all items in a crate. #![feature(rustc_private)] +#![feature(box_patterns)] #![cfg_attr(test, feature(assert_matches))] extern crate lazy_static; @@ -14,6 +15,7 @@ extern crate rustc_session; extern crate rustc_span; mod annotations; +mod reachability; use std::{borrow::Cow, collections::HashMap, env, process::Command}; @@ -129,21 +131,23 @@ type RequirementInfo = HashMap>; /// returning the [`Requirement`]s for those that have them. fn requirement_pass(tcx: TyCtxt) -> impl FnOnce() -> Result { move || { - rustc_public::all_local_items() - .into_iter() - // filter by items we should analyze - .filter_map(|crate_def| should_analyze_item(crate_def, tcx)) - // try to analyze all `FnDef`s, but some will return `None` as they have no annotations... - .filter_map(|def| { - let internal_def = rustc_public::rustc_internal::internal(tcx, def.def_id()); - Some( - Requirement::try_parse(tcx, internal_def)? - .map(|reqs| (internal_def, reqs)) - .map_err(|err| err.emit(tcx.dcx())), - ) - }) - // collect into a hash map - .collect::, ErrorGuaranteed>>() + reachability::filter_entry_points(tcx, &rustc_public::all_local_items()); + todo!(); + // rustc_public::all_local_items() + // .into_iter() + // // filter by items we should analyze + // .filter_map(|crate_def| should_analyze_item(crate_def, tcx)) + // // try to analyze all `FnDef`s, but some will return `None` as they have no annotations... + // .filter_map(|def| { + // let internal_def = rustc_public::rustc_internal::internal(tcx, def.def_id()); + // Some( + // Requirement::try_parse(tcx, internal_def)? + // .map(|reqs| (internal_def, reqs)) + // .map_err(|err| err.emit(tcx.dcx())), + // ) + // }) + // // collect into a hash map + // .collect::, ErrorGuaranteed>>() } } diff --git a/crates/sniff-test/src/reachability/entry.rs b/crates/sniff-test/src/reachability/entry.rs new file mode 100644 index 0000000..e1b837f --- /dev/null +++ b/crates/sniff-test/src/reachability/entry.rs @@ -0,0 +1,74 @@ +use rustc_hir::Attribute; +use rustc_middle::ty::TyCtxt; +use rustc_public::{CrateItem, ty::FnDef}; +use rustc_span::symbol::Ident; + +pub fn filter_entry_points(tcx: TyCtxt, items: &[CrateItem]) -> Vec { + items + .iter() + .filter_map(|item| is_entry_point(tcx, item)) + .collect::>() +} + +fn is_entry_point(tcx: TyCtxt, item: &CrateItem) -> Option { + // Is a function definition + let Some((def, _generics)) = item.ty().kind().fn_def() else { + return None; + }; + + println!("looking at fn def {def:?}"); + // Has an annotation + let internal = rustc_public::rustc_internal::internal(tcx, item); + + let b = tcx.get_all_attrs(internal); + let s = get_sniff_tool_attr(b); + println!("s is {s:?}"); + + Some(def) +} + +#[derive(Debug)] +enum SniffToolAttr { + CheckUnsafe, +} + +impl SniffToolAttr { + fn try_from_string(string: &str) -> Option { + match string { + "check_unsafe" => Some(Self::CheckUnsafe), + _ => None, + } + } +} + +fn get_sniff_tool_attr(attrs: &[Attribute]) -> Option { + let sniff_tool = attrs + .iter() + .filter_map(|attr| { + let Attribute::Unparsed(box item) = attr else { + return None; + }; + + // TODO: this might be hacky bc we're comparing strings... + match item + .path + .segments + .iter() + .map(|segment| segment.as_str()) + .collect::>() + { + box ["sniff_tool", b] => Some(b), + _ => None, + } + }) + .collect::>(); + println!("sniff_tool {:?}", sniff_tool); + + match sniff_tool { + box [attr_name] => SniffToolAttr::try_from_string(attr_name), + box [] => None, + box [_first, _second, ..] => { + panic!("multiple sniff test attrs on the same jawn {sniff_tool:?}") + } + } +} diff --git a/crates/sniff-test/src/reachability/mod.rs b/crates/sniff-test/src/reachability/mod.rs new file mode 100644 index 0000000..018a137 --- /dev/null +++ b/crates/sniff-test/src/reachability/mod.rs @@ -0,0 +1,3 @@ +mod entry; + +pub use entry::filter_entry_points; diff --git a/tests/unsafe/pass_simple/Cargo.lock b/tests/unsafe/pass_simple/Cargo.lock index 963424b..9a2d460 100644 --- a/tests/unsafe/pass_simple/Cargo.lock +++ b/tests/unsafe/pass_simple/Cargo.lock @@ -9,6 +9,33 @@ dependencies = [ "sniff-test-attrs", ] +[[package]] +name = "proc-macro2" +version = "1.0.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +dependencies = [ + "proc-macro2", +] + [[package]] name = "sniff-test-attrs" version = "0.1.0" +dependencies = [ + "quote", +] + +[[package]] +name = "unicode-ident" +version = "1.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" From 4231b1535aacddfad5a46259da8021a7162ee6a3 Mon Sep 17 00:00:00 2001 From: AlexanderPortland Date: Fri, 26 Sep 2025 13:35:57 -0400 Subject: [PATCH 02/40] 'bad' function detection --- crates/sniff-test/src/annotations/attr.rs | 10 +-- crates/sniff-test/src/annotations/err.rs | 24 ++----- crates/sniff-test/src/lib.rs | 50 ++++++++------ crates/sniff-test/src/reachability/attr.rs | 53 +++++++++++++++ crates/sniff-test/src/reachability/bad.rs | 61 +++++++++++++++++ crates/sniff-test/src/reachability/entry.rs | 74 +++------------------ crates/sniff-test/src/reachability/mod.rs | 3 + crates/sniff-test/src/utils/err.rs | 50 ++++++++++++++ crates/sniff-test/src/utils/mod.rs | 3 + tests/unsafe/pass_simple/src/main.rs | 6 +- 10 files changed, 224 insertions(+), 110 deletions(-) create mode 100644 crates/sniff-test/src/reachability/attr.rs create mode 100644 crates/sniff-test/src/reachability/bad.rs create mode 100644 crates/sniff-test/src/utils/err.rs create mode 100644 crates/sniff-test/src/utils/mod.rs diff --git a/crates/sniff-test/src/annotations/attr.rs b/crates/sniff-test/src/annotations/attr.rs index 38c5942..14fd383 100644 --- a/crates/sniff-test/src/annotations/attr.rs +++ b/crates/sniff-test/src/annotations/attr.rs @@ -39,15 +39,7 @@ pub trait Attributeable { // Filter for doc comments. let doc_comments = all_attrs .iter() - .filter_map(|attr| { - if let rustc_hir::Attribute::Parsed(kind) = attr - && let rustc_hir::attrs::AttributeKind::DocComment { comment, .. } = kind - { - Some(comment.as_str()) - } else { - None - } - }) + .filter_map(|attr| attr.doc_str().map(|a| a.as_str().to_owned())) .collect::>(); // Return none if no doc comments were found diff --git a/crates/sniff-test/src/annotations/err.rs b/crates/sniff-test/src/annotations/err.rs index dc0ad63..068632c 100644 --- a/crates/sniff-test/src/annotations/err.rs +++ b/crates/sniff-test/src/annotations/err.rs @@ -2,6 +2,7 @@ use crate::annotations::err::span::{span_all_comments, span_some_comments}; use crate::annotations::{Attributeable, types::InvalidConditionNameReason}; +use crate::utils::SniffTestDiagnostic; use rustc_errors::{Diag, DiagCtxtHandle}; use rustc_hir::Attribute; use rustc_middle::ty::TyCtxt; @@ -34,6 +35,7 @@ pub enum ParsingIssue { } /// A full parsing error that has extra debug info (e.g. the offending [`Span`]). +#[derive(Debug)] pub struct ParsingError<'a> { issue: ParsingIssue, loc_name: String, @@ -76,14 +78,8 @@ impl ParsingIssue { } } -impl ParsingError<'_> { - /// Build and emit the [`Diag`] for this [`ParsingError`]. - pub(crate) fn emit<'s, 'a: 's>(&'s self, dcx: DiagCtxtHandle<'a>) -> ErrorGuaranteed { - self.diag(dcx).emit() - } - - /// Build the [`Diag`] for a given error, but do not emit it. - pub(crate) fn diag<'s, 'a: 's>(&'s self, dcx: DiagCtxtHandle<'a>) -> Diag<'a> { +impl SniffTestDiagnostic for ParsingError<'_> { + fn diag<'s, 'a: 's>(&'s self, dcx: DiagCtxtHandle<'a>) -> Diag<'a> { let base_diag = match &self.issue { ParsingIssue::InvalidConditionName { reason, .. } => { self.build_invalid_condition_diag(dcx, reason) @@ -104,7 +100,9 @@ impl ParsingError<'_> { base_diag.with_span_label(self.span, "here") } +} +impl ParsingError<'_> { fn build_invalid_condition_diag<'a>( &self, dcx: DiagCtxtHandle<'a>, @@ -295,15 +293,7 @@ mod span { let doc_comments = doc_comments .iter() - .filter_map(|attr| { - if let rustc_hir::Attribute::Parsed(kind) = attr - && let rustc_hir::attrs::AttributeKind::DocComment { span, comment, .. } = kind - { - Some((*span, comment.as_str())) - } else { - None - } - }) + .filter_map(|attr| Some((attr.span(), attr.doc_str().map(|a| a.as_str().to_owned())?))) .collect::>(); let mut final_spans = vec![]; diff --git a/crates/sniff-test/src/lib.rs b/crates/sniff-test/src/lib.rs index 06a2a58..9e5ae58 100644 --- a/crates/sniff-test/src/lib.rs +++ b/crates/sniff-test/src/lib.rs @@ -14,8 +14,9 @@ extern crate rustc_public; extern crate rustc_session; extern crate rustc_span; -mod annotations; +pub mod annotations; mod reachability; +pub mod utils; use std::{borrow::Cow, collections::HashMap, env, process::Command}; @@ -27,11 +28,13 @@ use rustc_hir::{ }; use rustc_middle::ty::TyCtxt; use rustc_plugin::{CrateFilter, RustcPlugin, RustcPluginArgs, Utf8Path}; -use rustc_public::CrateDef; use rustc_span::ErrorGuaranteed; use serde::{Deserialize, Serialize}; -use crate::annotations::{Annotation, Justification, ParsingError, Requirement}; +use crate::{ + annotations::{Annotation, Justification, ParsingError, Requirement}, + utils::SniffTestDiagnostic, +}; // This struct is the plugin provided to the rustc_plugin framework, // and it must be exported for use by the CLI/driver binaries. @@ -102,21 +105,8 @@ impl rustc_driver::Callbacks for PrintAllItemsCallbacks { _compiler: &rustc_interface::interface::Compiler, tcx: TyCtxt<'_>, ) -> rustc_driver::Compilation { - let Ok(reqs) = rustc_public::rustc_internal::run(tcx, requirement_pass(tcx)) - .expect("rustc public should work i hope...") - else { - return rustc_driver::Compilation::Stop; - }; - - println!("reqs are {reqs:?}"); - - let fns_to_track: &[DefId] = &reqs.keys().copied().collect::>(); - - let Ok(justs) = justification_pass(tcx, fns_to_track)() else { - return rustc_driver::Compilation::Stop; - }; - - println!("justs are {justs:?}"); + rustc_public::rustc_internal::run(tcx, sniff_test_analysis(tcx)) + .expect("rustc public should work please"); // Note that you should generally allow compilation to continue. If // your plugin is being invoked on a dependency, then you need to ensure @@ -126,12 +116,34 @@ impl rustc_driver::Callbacks for PrintAllItemsCallbacks { } } +fn sniff_test_analysis(tcx: TyCtxt) -> impl FnOnce() { + move || { + let all_fn_defs = rustc_public::all_local_items() + .into_iter() + .filter_map(|item| match item.ty().kind().fn_def() { + Some((def, _other)) => Some(def), + _ => None, + }) + .collect::>(); + // 1. Find all 'bad' functions. Make sure they line up + let bad = reachability::filter_bad_functions(tcx, &all_fn_defs); + print!("bad {bad:?}"); + + // 2a. Find entry points + let entry_points = reachability::filter_entry_points(tcx, &all_fn_defs); + println!("have entry points {:?}", entry_points); + + // 2b. Walk from those entry points to ensure proper labels + } +} + type RequirementInfo = HashMap>; /// Parses all functions that pass the given [`should_analyze_item`] predicate, /// returning the [`Requirement`]s for those that have them. fn requirement_pass(tcx: TyCtxt) -> impl FnOnce() -> Result { move || { - reachability::filter_entry_points(tcx, &rustc_public::all_local_items()); + // let entry_points = reachability::filter_entry_points(tcx, &rustc_public::all_local_items()); + // println!("entry points are {:?}", entry_points); todo!(); // rustc_public::all_local_items() // .into_iter() diff --git a/crates/sniff-test/src/reachability/attr.rs b/crates/sniff-test/src/reachability/attr.rs new file mode 100644 index 0000000..b345894 --- /dev/null +++ b/crates/sniff-test/src/reachability/attr.rs @@ -0,0 +1,53 @@ +//! Utilities for parsing our own `sniff_test_attr` annotation attributes. + +use rustc_hir::{Attribute, def_id::DefId}; +use rustc_middle::ty::TyCtxt; + +pub fn attrs_for(def_id: DefId, tcx: TyCtxt) -> Option { + get_sniff_tool_attr(tcx.get_all_attrs(def_id)) +} + +#[derive(Debug)] +pub enum SniffToolAttr { + CheckUnsafe, +} + +impl SniffToolAttr { + fn try_from_string(string: &str) -> Option { + match string { + "check_unsafe" => Some(Self::CheckUnsafe), + _ => None, + } + } +} + +fn get_sniff_tool_attr(attrs: &[Attribute]) -> Option { + let sniff_tool = attrs + .iter() + .filter_map(|attr| { + let Attribute::Unparsed(box item) = attr else { + return None; + }; + + // TODO: this might be hacky bc we're comparing strings... + match item + .path + .segments + .iter() + .map(|segment| segment.as_str()) + .collect::>() + { + box ["sniff_tool", b] => Some(b), + _ => None, + } + }) + .collect::>(); + + match sniff_tool { + box [] => None, + box [attr_name] => SniffToolAttr::try_from_string(attr_name), + box [_first, _second, ..] => { + panic!("multiple sniff test attrs on the same jawn {sniff_tool:?}") + } + } +} diff --git a/crates/sniff-test/src/reachability/bad.rs b/crates/sniff-test/src/reachability/bad.rs new file mode 100644 index 0000000..e774391 --- /dev/null +++ b/crates/sniff-test/src/reachability/bad.rs @@ -0,0 +1,61 @@ +//! Finds the 'bad' functions that should be annotated + +use crate::annotations::{Annotation, Requirement}; +use std::collections::HashMap; + +use crate::utils::MultiEmittable; + +use rustc_middle::ty::TyCtxt; +use rustc_public::mir::Safety; +use rustc_public::{CrateItem, ty::FnDef}; +use rustc_span::ErrorGuaranteed; + +pub fn filter_bad_functions( + tcx: TyCtxt, + items: &[FnDef], +) -> Result>, ErrorGuaranteed> { + let annotated_bad = items + .iter() + .filter_map(|item| { + Some(( + *item, + Requirement::try_parse(tcx, rustc_public::rustc_internal::internal(tcx, item.0))?, + )) + }) + .collect::>() + .emit_all_errors(tcx)?; + + println!("annotated bad is {:?}", annotated_bad.keys()); + + let should_be_bad = items + .iter() + .filter_map(|fn_def| Some((fn_def, should_be_bad(tcx, *fn_def)?))); + + let bad_but_missed = should_be_bad + .filter(|(fn_def, _reason)| !annotated_bad.contains_key(fn_def)) + .collect::>(); + + if !bad_but_missed.is_empty() { + panic!( + "some functions should be annotated for the following reasons, but are not {:?}", + bad_but_missed + ); + } + + Ok(annotated_bad) +} + +#[derive(Debug)] +pub enum ShouldBeBadReason { + MarkedUnsafe, + // SpecifiedInToml? +} + +// TODO: add config from .toml file. +fn should_be_bad(_tcx: TyCtxt, fn_def: FnDef) -> Option { + if fn_def.fn_sig().value.safety == Safety::Unsafe { + return Some(ShouldBeBadReason::MarkedUnsafe); + } + + return None; +} diff --git a/crates/sniff-test/src/reachability/entry.rs b/crates/sniff-test/src/reachability/entry.rs index e1b837f..067555c 100644 --- a/crates/sniff-test/src/reachability/entry.rs +++ b/crates/sniff-test/src/reachability/entry.rs @@ -1,74 +1,20 @@ -use rustc_hir::Attribute; use rustc_middle::ty::TyCtxt; use rustc_public::{CrateItem, ty::FnDef}; -use rustc_span::symbol::Ident; -pub fn filter_entry_points(tcx: TyCtxt, items: &[CrateItem]) -> Vec { +use crate::reachability::attr::{self, SniffToolAttr}; + +pub fn filter_entry_points(tcx: TyCtxt, items: &[FnDef]) -> Vec { items .iter() - .filter_map(|item| is_entry_point(tcx, item)) + .filter(|item| is_entry_point(tcx, item)) + .cloned() .collect::>() } -fn is_entry_point(tcx: TyCtxt, item: &CrateItem) -> Option { - // Is a function definition - let Some((def, _generics)) = item.ty().kind().fn_def() else { - return None; - }; - - println!("looking at fn def {def:?}"); - // Has an annotation - let internal = rustc_public::rustc_internal::internal(tcx, item); - - let b = tcx.get_all_attrs(internal); - let s = get_sniff_tool_attr(b); - println!("s is {s:?}"); - - Some(def) -} - -#[derive(Debug)] -enum SniffToolAttr { - CheckUnsafe, -} - -impl SniffToolAttr { - fn try_from_string(string: &str) -> Option { - match string { - "check_unsafe" => Some(Self::CheckUnsafe), - _ => None, - } - } -} - -fn get_sniff_tool_attr(attrs: &[Attribute]) -> Option { - let sniff_tool = attrs - .iter() - .filter_map(|attr| { - let Attribute::Unparsed(box item) = attr else { - return None; - }; - - // TODO: this might be hacky bc we're comparing strings... - match item - .path - .segments - .iter() - .map(|segment| segment.as_str()) - .collect::>() - { - box ["sniff_tool", b] => Some(b), - _ => None, - } - }) - .collect::>(); - println!("sniff_tool {:?}", sniff_tool); +fn is_entry_point(tcx: TyCtxt, item: &FnDef) -> bool { + let internal = rustc_public::rustc_internal::internal(tcx, item.0); - match sniff_tool { - box [attr_name] => SniffToolAttr::try_from_string(attr_name), - box [] => None, - box [_first, _second, ..] => { - panic!("multiple sniff test attrs on the same jawn {sniff_tool:?}") - } - } + attr::attrs_for(internal, tcx).map_or(false, |attr| match attr { + SniffToolAttr::CheckUnsafe => true, + }) } diff --git a/crates/sniff-test/src/reachability/mod.rs b/crates/sniff-test/src/reachability/mod.rs index 018a137..b1b39a2 100644 --- a/crates/sniff-test/src/reachability/mod.rs +++ b/crates/sniff-test/src/reachability/mod.rs @@ -1,3 +1,6 @@ +pub mod attr; +mod bad; mod entry; +pub use bad::filter_bad_functions; pub use entry::filter_entry_points; diff --git a/crates/sniff-test/src/utils/err.rs b/crates/sniff-test/src/utils/err.rs new file mode 100644 index 0000000..5a357d7 --- /dev/null +++ b/crates/sniff-test/src/utils/err.rs @@ -0,0 +1,50 @@ +use std::collections::HashMap; +use std::fmt::Debug; +use std::hash::Hash; + +use rustc_errors::{Diag, DiagCtxtHandle}; +use rustc_middle::ty::TyCtxt; +use rustc_span::ErrorGuaranteed; + +pub trait SniffTestDiagnostic: Debug { + /// Build the [`Diag`] for a given error, but do not emit it. + fn diag<'s, 'a: 's>(&'s self, dcx: DiagCtxtHandle<'a>) -> Diag<'_>; + + /// Build and emit the [`Diag`] for this [`ParsingError`]. + fn emit<'s, 'a: 's>(&'s self, dcx: DiagCtxtHandle<'a>) -> ErrorGuaranteed { + self.diag(dcx).emit() + } +} + +pub trait MultiEmittable { + type Emitted; + fn emit_all_errors(self, tcx: TyCtxt) -> Self::Emitted; +} + +impl MultiEmittable + for HashMap> +{ + type Emitted = Result, ErrorGuaranteed>; + fn emit_all_errors(self, tcx: TyCtxt) -> Self::Emitted { + let errs = self + .values() + .filter_map(|err| Some(err.as_ref().err()?.diag(tcx.dcx()).emit())) + .collect::>(); + + if let box [first, ..] = errs { + // We have emitted errors, take the first one as a guarantee that they've been emitted + Err(first) + } else { + // No errors to emit, go through everything and get the value + Ok(self + .into_iter() + .map(|(k, v)| { + ( + k, + v.expect("we already checked that none of there are errr"), + ) + }) + .collect::>()) + } + } +} diff --git a/crates/sniff-test/src/utils/mod.rs b/crates/sniff-test/src/utils/mod.rs new file mode 100644 index 0000000..acc052f --- /dev/null +++ b/crates/sniff-test/src/utils/mod.rs @@ -0,0 +1,3 @@ +mod err; + +pub use err::{MultiEmittable, SniffTestDiagnostic}; diff --git a/tests/unsafe/pass_simple/src/main.rs b/tests/unsafe/pass_simple/src/main.rs index 1c2b840..ab0e23b 100644 --- a/tests/unsafe/pass_simple/src/main.rs +++ b/tests/unsafe/pass_simple/src/main.rs @@ -1,11 +1,15 @@ /// # Unsafe -/// - nonnn: non null +/// - nonnn-nm: non null /// - non-null: aligned /// and ready for business unsafe fn foo(ptr: *const i32) -> i32 { unsafe { *ptr } } +/// # Unsafe +/// - nonnnnm: non null +/// - non-null: aligned +/// and ready for business #[sniff_test_attrs::check_unsafe] fn main() { let x = 1; From 115bb48a86867889fd7f55bedb74eb60a3b52f1d Mon Sep 17 00:00:00 2001 From: AlexanderPortland Date: Sun, 28 Sep 2025 12:04:36 -0400 Subject: [PATCH 03/40] small cleanup --- crates/sniff-test/src/lib.rs | 21 ++++++++++++++------- crates/sniff-test/src/reachability/bad.rs | 2 -- crates/sniff-test/src/reachability/mod.rs | 2 ++ crates/sniff-test/src/reachability/walk.rs | 5 +++++ crates/sniff-test/src/utils/err.rs | 2 +- 5 files changed, 22 insertions(+), 10 deletions(-) create mode 100644 crates/sniff-test/src/reachability/walk.rs diff --git a/crates/sniff-test/src/lib.rs b/crates/sniff-test/src/lib.rs index 9e5ae58..6ed6608 100644 --- a/crates/sniff-test/src/lib.rs +++ b/crates/sniff-test/src/lib.rs @@ -28,6 +28,7 @@ use rustc_hir::{ }; use rustc_middle::ty::TyCtxt; use rustc_plugin::{CrateFilter, RustcPlugin, RustcPluginArgs, Utf8Path}; +use rustc_public::ty::FnDef; use rustc_span::ErrorGuaranteed; use serde::{Deserialize, Serialize}; @@ -116,15 +117,20 @@ impl rustc_driver::Callbacks for PrintAllItemsCallbacks { } } +fn all_local_fn_defs() -> Box<[FnDef]> { + rustc_public::all_local_items() + .into_iter() + .filter_map(|item| match item.ty().kind().fn_def() { + Some((def, _other)) => Some(def), + _ => None, + }) + .collect::>() +} + fn sniff_test_analysis(tcx: TyCtxt) -> impl FnOnce() { move || { - let all_fn_defs = rustc_public::all_local_items() - .into_iter() - .filter_map(|item| match item.ty().kind().fn_def() { - Some((def, _other)) => Some(def), - _ => None, - }) - .collect::>(); + let all_fn_defs = all_local_fn_defs(); + // 1. Find all 'bad' functions. Make sure they line up let bad = reachability::filter_bad_functions(tcx, &all_fn_defs); print!("bad {bad:?}"); @@ -134,6 +140,7 @@ fn sniff_test_analysis(tcx: TyCtxt) -> impl FnOnce() { println!("have entry points {:?}", entry_points); // 2b. Walk from those entry points to ensure proper labels + let res = reachability::walk_from_entry_points(&entry_points); } } diff --git a/crates/sniff-test/src/reachability/bad.rs b/crates/sniff-test/src/reachability/bad.rs index e774391..445e0dd 100644 --- a/crates/sniff-test/src/reachability/bad.rs +++ b/crates/sniff-test/src/reachability/bad.rs @@ -25,8 +25,6 @@ pub fn filter_bad_functions( .collect::>() .emit_all_errors(tcx)?; - println!("annotated bad is {:?}", annotated_bad.keys()); - let should_be_bad = items .iter() .filter_map(|fn_def| Some((fn_def, should_be_bad(tcx, *fn_def)?))); diff --git a/crates/sniff-test/src/reachability/mod.rs b/crates/sniff-test/src/reachability/mod.rs index b1b39a2..8776a14 100644 --- a/crates/sniff-test/src/reachability/mod.rs +++ b/crates/sniff-test/src/reachability/mod.rs @@ -1,6 +1,8 @@ pub mod attr; mod bad; mod entry; +mod walk; pub use bad::filter_bad_functions; pub use entry::filter_entry_points; +pub use walk::walk_from_entry_points; diff --git a/crates/sniff-test/src/reachability/walk.rs b/crates/sniff-test/src/reachability/walk.rs new file mode 100644 index 0000000..7abf934 --- /dev/null +++ b/crates/sniff-test/src/reachability/walk.rs @@ -0,0 +1,5 @@ +use rustc_public::ty::FnDef; + +pub fn walk_from_entry_points(entry_points: &[FnDef]) -> FnDef { + todo!() +} diff --git a/crates/sniff-test/src/utils/err.rs b/crates/sniff-test/src/utils/err.rs index 5a357d7..4cdc985 100644 --- a/crates/sniff-test/src/utils/err.rs +++ b/crates/sniff-test/src/utils/err.rs @@ -8,7 +8,7 @@ use rustc_span::ErrorGuaranteed; pub trait SniffTestDiagnostic: Debug { /// Build the [`Diag`] for a given error, but do not emit it. - fn diag<'s, 'a: 's>(&'s self, dcx: DiagCtxtHandle<'a>) -> Diag<'_>; + fn diag<'s, 'a: 's>(&'s self, dcx: DiagCtxtHandle<'a>) -> Diag<'a>; /// Build and emit the [`Diag`] for this [`ParsingError`]. fn emit<'s, 'a: 's>(&'s self, dcx: DiagCtxtHandle<'a>) -> ErrorGuaranteed { From 4589e6943bc6fa752c5390710442ec4e27006c07 Mon Sep 17 00:00:00 2001 From: AlexanderPortland Date: Fri, 3 Oct 2025 11:41:26 -0400 Subject: [PATCH 04/40] snapshot testing --- .gitignore | 3 +- Cargo.lock | 223 ++++++++++++++++++-- Cargo.toml | 17 +- crates/sniff-test/src/annotations/err.rs | 3 +- crates/sniff-test/src/annotations/mod.rs | 1 + crates/sniff-test/src/lib.rs | 2 +- crates/sniff-test/src/reachability/attr.rs | 2 +- crates/sniff-test/src/reachability/bad.rs | 11 +- crates/sniff-test/src/reachability/entry.rs | 6 +- tests/Cargo.toml | 14 ++ tests/lib.rs | 145 +++++++++++++ tests/unsafe/fail_nested/Cargo.lock | 29 ++- tests/unsafe/fail_nested/Cargo.toml | 6 +- tests/unsafe/fail_simple/Cargo.lock | 36 +++- tests/unsafe/fail_simple/Cargo.toml | 6 +- tests/unsafe/pass_nested/Cargo.lock | 33 ++- tests/unsafe/pass_nested/Cargo.toml | 6 +- tests/unsafe/pass_simple/Cargo.toml | 4 +- 18 files changed, 496 insertions(+), 51 deletions(-) create mode 100644 tests/Cargo.toml create mode 100644 tests/lib.rs diff --git a/.gitignore b/.gitignore index 1de5659..2f9dd2c 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -target \ No newline at end of file +target +review.sh \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index ce1b55e..ff743f0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -47,7 +47,7 @@ version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e231f6134f61b71076a3eab506c379d4f36122f2af15a9ff04415ea4c3339e2" dependencies = [ - "windows-sys", + "windows-sys 0.60.2", ] [[package]] @@ -58,14 +58,14 @@ checksum = "3e0633414522a32ffaac8ac6cc8f748e090c5717661fddeea04219e2344f5f2a" dependencies = [ "anstyle", "once_cell_polyfill", - "windows-sys", + "windows-sys 0.60.2", ] [[package]] name = "anyhow" -version = "1.0.99" +version = "1.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0674a1ddeecb70197781e945de4b3b8ffb61fa939a5597bcf48503737663100" +checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" [[package]] name = "camino" @@ -150,6 +150,24 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" +[[package]] +name = "console" +version = "0.15.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "054ccb5b10f9f2cbf51eb355ca1d05c2d279ce1804688d0db74b4733a5aeafd8" +dependencies = [ + "encode_unicode", + "libc", + "once_cell", + "windows-sys 0.59.0", +] + +[[package]] +name = "encode_unicode" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" + [[package]] name = "env_logger" version = "0.10.2" @@ -187,6 +205,20 @@ dependencies = [ "hashbrown", ] +[[package]] +name = "insta" +version = "1.43.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46fdb647ebde000f43b5b53f773c30cf9b0cb4300453208713fa38b2c70935a0" +dependencies = [ + "console", + "once_cell", + "regex", + "serde", + "similar", + "toml 0.5.11", +] + [[package]] name = "intervaltree" version = "0.2.7" @@ -208,6 +240,18 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.176" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58f929b4d672ea937a23a1ab494143d968337a5f47e56d0815df1e0890ddf174" + [[package]] name = "log" version = "0.4.28" @@ -220,6 +264,12 @@ version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + [[package]] name = "once_cell_polyfill" version = "1.70.1" @@ -284,7 +334,7 @@ dependencies = [ "rustc_tools_util", "serde", "serde_json", - "toml", + "toml 0.7.8", ] [[package]] @@ -311,6 +361,15 @@ version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + [[package]] name = "semver" version = "1.0.26" @@ -322,18 +381,28 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.219" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.219" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", @@ -361,6 +430,12 @@ dependencies = [ "serde", ] +[[package]] +name = "similar" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbbb5d9659141646ae647b42fe094daf6c6192d1620870b449d9557f748b2daa" + [[package]] name = "smallvec" version = "1.15.1" @@ -403,6 +478,26 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "tests" +version = "0.1.0" +dependencies = [ + "anyhow", + "insta", + "lazy_static", + "serde", + "walkdir", +] + +[[package]] +name = "toml" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" +dependencies = [ + "serde", +] + [[package]] name = "toml" version = "0.7.8" @@ -449,19 +544,63 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "winapi-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +dependencies = [ + "windows-sys 0.60.2", +] + [[package]] name = "windows-link" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + [[package]] name = "windows-sys" version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" dependencies = [ - "windows-targets", + "windows-targets 0.53.3", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm 0.52.6", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", ] [[package]] @@ -471,58 +610,106 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91" dependencies = [ "windows-link", - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_gnullvm", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.53.0", + "windows_aarch64_msvc 0.53.0", + "windows_i686_gnu 0.53.0", + "windows_i686_gnullvm 0.53.0", + "windows_i686_msvc 0.53.0", + "windows_x86_64_gnu 0.53.0", + "windows_x86_64_gnullvm 0.53.0", + "windows_x86_64_msvc 0.53.0", ] +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + [[package]] name = "windows_aarch64_gnullvm" version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + [[package]] name = "windows_aarch64_msvc" version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + [[package]] name = "windows_i686_gnu" version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + [[package]] name = "windows_i686_gnullvm" version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + [[package]] name = "windows_i686_msvc" version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + [[package]] name = "windows_x86_64_gnu" version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + [[package]] name = "windows_x86_64_gnullvm" version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + [[package]] name = "windows_x86_64_msvc" version = "0.53.0" diff --git a/Cargo.toml b/Cargo.toml index d0c0bc6..257129b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,13 +1,16 @@ [workspace] resolver = "3" -members = ["crates/*"] +members = ["crates/*", "tests"] # TODO: can we glob exclude these? maybe add that functionality to the upstream? # I could also see that not being possible due to glob rule prescedence ambiguity between this # and `members`, so maybe we can just include them? -exclude = [ - "tests/unsafe/fail_simple", - "tests/unsafe/pass_simple", - "tests/unsafe/fail_nested", - "tests/unsafe/pass_nested" -] \ No newline at end of file +# exclude = [ +# "tests/unsafe/fail_simple", +# "tests/unsafe/pass_simple", +# "tests/unsafe/fail_nested", +# "tests/unsafe/pass_nested" +# ] + +# [workspace.metadata.insta] +# snapshot_path = "tests/*" \ No newline at end of file diff --git a/crates/sniff-test/src/annotations/err.rs b/crates/sniff-test/src/annotations/err.rs index 068632c..e1354db 100644 --- a/crates/sniff-test/src/annotations/err.rs +++ b/crates/sniff-test/src/annotations/err.rs @@ -6,8 +6,8 @@ use crate::utils::SniffTestDiagnostic; use rustc_errors::{Diag, DiagCtxtHandle}; use rustc_hir::Attribute; use rustc_middle::ty::TyCtxt; +use rustc_span::Span; use rustc_span::def_id::DefId; -use rustc_span::{ErrorGuaranteed, Span}; use std::ops::Range; #[derive(PartialEq, Eq, Debug)] @@ -44,6 +44,7 @@ pub struct ParsingError<'a> { } impl ParsingError<'_> { + #[allow(clippy::must_use_candidate)] pub fn issue(&self) -> &ParsingIssue { &self.issue } diff --git a/crates/sniff-test/src/annotations/mod.rs b/crates/sniff-test/src/annotations/mod.rs index 981928f..fb1d144 100644 --- a/crates/sniff-test/src/annotations/mod.rs +++ b/crates/sniff-test/src/annotations/mod.rs @@ -26,6 +26,7 @@ pub trait Annotation<'a>: ParseBulletsFromString { type Input: Attributeable; /// Parse the given [`Input`](Annotation::Input). + #[allow(clippy::missing_errors_doc)] fn parse(tcx: TyCtxt, input: impl Borrow) -> Result, ParsingError> { let input: &Self::Input = input.borrow(); let doc_str: Result = diff --git a/crates/sniff-test/src/lib.rs b/crates/sniff-test/src/lib.rs index 6ed6608..c528a55 100644 --- a/crates/sniff-test/src/lib.rs +++ b/crates/sniff-test/src/lib.rs @@ -137,7 +137,7 @@ fn sniff_test_analysis(tcx: TyCtxt) -> impl FnOnce() { // 2a. Find entry points let entry_points = reachability::filter_entry_points(tcx, &all_fn_defs); - println!("have entry points {:?}", entry_points); + println!("have entry points {entry_points:?}"); // 2b. Walk from those entry points to ensure proper labels let res = reachability::walk_from_entry_points(&entry_points); diff --git a/crates/sniff-test/src/reachability/attr.rs b/crates/sniff-test/src/reachability/attr.rs index b345894..161ffe4 100644 --- a/crates/sniff-test/src/reachability/attr.rs +++ b/crates/sniff-test/src/reachability/attr.rs @@ -34,7 +34,7 @@ fn get_sniff_tool_attr(attrs: &[Attribute]) -> Option { .path .segments .iter() - .map(|segment| segment.as_str()) + .map(rustc_span::Ident::as_str) .collect::>() { box ["sniff_tool", b] => Some(b), diff --git a/crates/sniff-test/src/reachability/bad.rs b/crates/sniff-test/src/reachability/bad.rs index 445e0dd..b1ce6a8 100644 --- a/crates/sniff-test/src/reachability/bad.rs +++ b/crates/sniff-test/src/reachability/bad.rs @@ -7,7 +7,7 @@ use crate::utils::MultiEmittable; use rustc_middle::ty::TyCtxt; use rustc_public::mir::Safety; -use rustc_public::{CrateItem, ty::FnDef}; +use rustc_public::ty::FnDef; use rustc_span::ErrorGuaranteed; pub fn filter_bad_functions( @@ -33,12 +33,9 @@ pub fn filter_bad_functions( .filter(|(fn_def, _reason)| !annotated_bad.contains_key(fn_def)) .collect::>(); - if !bad_but_missed.is_empty() { - panic!( - "some functions should be annotated for the following reasons, but are not {:?}", - bad_but_missed + assert!(bad_but_missed.is_empty(), + "some functions should be annotated for the following reasons, but are not {bad_but_missed:?}" ); - } Ok(annotated_bad) } @@ -55,5 +52,5 @@ fn should_be_bad(_tcx: TyCtxt, fn_def: FnDef) -> Option { return Some(ShouldBeBadReason::MarkedUnsafe); } - return None; + None } diff --git a/crates/sniff-test/src/reachability/entry.rs b/crates/sniff-test/src/reachability/entry.rs index 067555c..a09adea 100644 --- a/crates/sniff-test/src/reachability/entry.rs +++ b/crates/sniff-test/src/reachability/entry.rs @@ -1,5 +1,5 @@ use rustc_middle::ty::TyCtxt; -use rustc_public::{CrateItem, ty::FnDef}; +use rustc_public::ty::FnDef; use crate::reachability::attr::{self, SniffToolAttr}; @@ -7,14 +7,14 @@ pub fn filter_entry_points(tcx: TyCtxt, items: &[FnDef]) -> Vec { items .iter() .filter(|item| is_entry_point(tcx, item)) - .cloned() + .copied() .collect::>() } fn is_entry_point(tcx: TyCtxt, item: &FnDef) -> bool { let internal = rustc_public::rustc_internal::internal(tcx, item.0); - attr::attrs_for(internal, tcx).map_or(false, |attr| match attr { + attr::attrs_for(internal, tcx).is_some_and(|attr| match attr { SniffToolAttr::CheckUnsafe => true, }) } diff --git a/tests/Cargo.toml b/tests/Cargo.toml new file mode 100644 index 0000000..5788598 --- /dev/null +++ b/tests/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "tests" +version = "0.1.0" +edition = "2024" + +[lib] +path = "lib.rs" + +[dependencies] +anyhow = "1.0.100" +insta = {version = "1.43.2", features = ["toml", "filters"]} +lazy_static = "1.5.0" +serde = "1.0.228" +walkdir = "2.5.0" diff --git a/tests/lib.rs b/tests/lib.rs new file mode 100644 index 0000000..3f558fa --- /dev/null +++ b/tests/lib.rs @@ -0,0 +1,145 @@ +#![allow(dead_code)] + +use serde::Serialize; +use std::{ + ffi::OsString, + io::Write, + os::unix::fs::PermissionsExt, + path::{Path, PathBuf}, + process::{Command, Output}, + sync::LazyLock, +}; +use walkdir::WalkDir; + +static CARGO_SNIFF_TEST_PATH: LazyLock = LazyLock::new(|| { + let canon = Path::new("../target/debug/cargo-sniff-test").canonicalize(); + canon + .expect("issue with cargo sniff-test path") + .into_os_string() +}); + +#[derive(Debug, Serialize)] +pub struct SniffTestOutput { + exit_code: Option, + stdout: String, + stderr: String, +} + +impl TryFrom for SniffTestOutput { + type Error = std::string::FromUtf8Error; + fn try_from(value: Output) -> Result { + Ok(SniffTestOutput { + exit_code: value.status.code(), + stdout: String::from_utf8(value.stdout)?, + stderr: String::from_utf8(value.stderr)?, + }) + } +} + +#[test] +fn snapshots() -> anyhow::Result<()> { + let root = Path::new(".").canonicalize()?; + + println!("root is {root:?}"); + + let cargo_dirs = subdirectories(root) + .filter(|dir_path| is_cargo_project(dir_path)) + .map(|path| { + snapshot_cargo_dir(&path)?; + Ok(path) + }) + .collect::>>()?; + + write_review_script(&cargo_dirs)?; + + Ok(()) +} + +fn subdirectories(root: PathBuf) -> impl Iterator { + WalkDir::new(root) + .min_depth(1) + .into_iter() + .flatten() + .filter(|e| e.metadata().map(|m| m.is_dir()).unwrap_or(false)) + .map(walkdir::DirEntry::into_path) +} + +fn is_cargo_project(path: &Path) -> bool { + path.join("Cargo.toml").exists() +} + +fn snapshot_cargo_dir(path: &Path) -> anyhow::Result<()> { + println!("snapshotting {}", path.display()); + let name = path + .file_name() + .expect("directory should have name") + .to_str() + .unwrap_or("[unknown name]") + .to_owned(); + + let out_path = path.to_path_buf(); + let out = cargo_sniff(path)?; + + insta::with_settings!({ + snapshot_path => out_path, + filters => vec![ + (r"process didn't exit successfully: `(.*?)`", "process didn't exit successfully: [BINARY PATH ELIDED]") + ], + prepend_module_to_snapshot => false, + omit_expression => true, + }, { + insta::assert_toml_snapshot!(name, &out); + }); + + println!("out is {out:?}"); + Ok(()) +} + +fn cargo_sniff(path: &Path) -> anyhow::Result { + // cargo clean first + Command::new("cargo") + .arg("clean") + .current_dir(path) + .output()?; + + println!("path is {:?}", CARGO_SNIFF_TEST_PATH.clone().into_string()); + let mut cmd = Command::new(&*CARGO_SNIFF_TEST_PATH); + // register the sniff_tool tool + cmd.env( + "RUSTFLAGS", + "-Zcrate-attr=feature(register_tool) -Zcrate-attr=register_tool(sniff_tool)", + ); + cmd.current_dir(path); + + Ok(cmd.output()?.try_into()?) +} + +const REVIEW_SCRIPT_PATH: &str = "../review.sh"; + +fn write_review_script(cargo_dirs: &[PathBuf]) -> anyhow::Result<()> { + let review_commands = cargo_dirs + .iter() + .map(|dir| format!("cargo insta review --workspace-root {};\n", dir.display())); + + let out = std::iter::once("#!/bin/bash\n".to_string()) + .chain(review_commands) + .collect::(); + + let mut file = std::fs::OpenOptions::new() + .create(true) + .truncate(true) + .write(true) + .open(REVIEW_SCRIPT_PATH)?; + + file.write_all(out.as_bytes())?; + + // make executable if we can on unix + #[cfg(unix)] + { + let mut perms = file.metadata()?.permissions(); + perms.set_mode(0o755); + std::fs::set_permissions(REVIEW_SCRIPT_PATH, perms)?; + } + + Ok(()) +} diff --git a/tests/unsafe/fail_nested/Cargo.lock b/tests/unsafe/fail_nested/Cargo.lock index 963424b..9e11c79 100644 --- a/tests/unsafe/fail_nested/Cargo.lock +++ b/tests/unsafe/fail_nested/Cargo.lock @@ -3,12 +3,39 @@ version = 4 [[package]] -name = "invalid_simple" +name = "fail_nested" version = "0.1.0" dependencies = [ "sniff-test-attrs", ] +[[package]] +name = "proc-macro2" +version = "1.0.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1" +dependencies = [ + "proc-macro2", +] + [[package]] name = "sniff-test-attrs" version = "0.1.0" +dependencies = [ + "quote", +] + +[[package]] +name = "unicode-ident" +version = "1.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" diff --git a/tests/unsafe/fail_nested/Cargo.toml b/tests/unsafe/fail_nested/Cargo.toml index cf84d51..9d99bb7 100644 --- a/tests/unsafe/fail_nested/Cargo.toml +++ b/tests/unsafe/fail_nested/Cargo.toml @@ -1,7 +1,9 @@ [package] -name = "invalid_simple" +name = "fail_nested" version = "0.1.0" edition = "2024" [dependencies] -sniff-test-attrs = { path = "../../../crates/sniff-test-attrs" } \ No newline at end of file +sniff-test-attrs = { path = "../../../crates/sniff-test-attrs" } + +[workspace] \ No newline at end of file diff --git a/tests/unsafe/fail_simple/Cargo.lock b/tests/unsafe/fail_simple/Cargo.lock index 513ce2d..ebb8e70 100644 --- a/tests/unsafe/fail_simple/Cargo.lock +++ b/tests/unsafe/fail_simple/Cargo.lock @@ -3,5 +3,39 @@ version = 4 [[package]] -name = "invalid_simple" +name = "fail_simple" version = "0.1.0" +dependencies = [ + "sniff-test-attrs", +] + +[[package]] +name = "proc-macro2" +version = "1.0.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "sniff-test-attrs" +version = "0.1.0" +dependencies = [ + "quote", +] + +[[package]] +name = "unicode-ident" +version = "1.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" diff --git a/tests/unsafe/fail_simple/Cargo.toml b/tests/unsafe/fail_simple/Cargo.toml index cf84d51..b0775dd 100644 --- a/tests/unsafe/fail_simple/Cargo.toml +++ b/tests/unsafe/fail_simple/Cargo.toml @@ -1,7 +1,9 @@ [package] -name = "invalid_simple" +name = "fail_simple" version = "0.1.0" edition = "2024" [dependencies] -sniff-test-attrs = { path = "../../../crates/sniff-test-attrs" } \ No newline at end of file +sniff-test-attrs = { path = "../../../crates/sniff-test-attrs" } + +[workspace] \ No newline at end of file diff --git a/tests/unsafe/pass_nested/Cargo.lock b/tests/unsafe/pass_nested/Cargo.lock index 7e41092..5348ff5 100644 --- a/tests/unsafe/pass_nested/Cargo.lock +++ b/tests/unsafe/pass_nested/Cargo.lock @@ -3,12 +3,39 @@ version = 4 [[package]] -name = "hocklorp-attrs" +name = "pass_nested" version = "0.1.0" +dependencies = [ + "sniff-test-attrs", +] + +[[package]] +name = "proc-macro2" +version = "1.0.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" +dependencies = [ + "unicode-ident", +] [[package]] -name = "invalid_simple" +name = "quote" +version = "1.0.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "sniff-test-attrs" version = "0.1.0" dependencies = [ - "hocklorp-attrs", + "quote", ] + +[[package]] +name = "unicode-ident" +version = "1.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" diff --git a/tests/unsafe/pass_nested/Cargo.toml b/tests/unsafe/pass_nested/Cargo.toml index cf84d51..3d86a2c 100644 --- a/tests/unsafe/pass_nested/Cargo.toml +++ b/tests/unsafe/pass_nested/Cargo.toml @@ -1,7 +1,9 @@ [package] -name = "invalid_simple" +name = "pass_nested" version = "0.1.0" edition = "2024" [dependencies] -sniff-test-attrs = { path = "../../../crates/sniff-test-attrs" } \ No newline at end of file +sniff-test-attrs = { path = "../../../crates/sniff-test-attrs" } + +[workspace] \ No newline at end of file diff --git a/tests/unsafe/pass_simple/Cargo.toml b/tests/unsafe/pass_simple/Cargo.toml index cf84d51..6f3b543 100644 --- a/tests/unsafe/pass_simple/Cargo.toml +++ b/tests/unsafe/pass_simple/Cargo.toml @@ -4,4 +4,6 @@ version = "0.1.0" edition = "2024" [dependencies] -sniff-test-attrs = { path = "../../../crates/sniff-test-attrs" } \ No newline at end of file +sniff-test-attrs = { path = "../../../crates/sniff-test-attrs" } + +[workspace] \ No newline at end of file From ea2ad40b4f71847845eb1f2447556d94d5dc8715 Mon Sep 17 00:00:00 2001 From: AlexanderPortland Date: Tue, 21 Oct 2025 20:25:18 -0400 Subject: [PATCH 05/40] early safety axioms --- Cargo.lock | 1 + crates/sniff-test/Cargo.toml | 1 + crates/sniff-test/src/axioms/mod.rs | 64 +++++++++++++++++++++ crates/sniff-test/src/axioms/safety.rs | 41 ++++++++++++++ crates/sniff-test/src/lib.rs | 24 ++++++-- crates/sniff-test/src/reachability/err.rs | 14 +++++ crates/sniff-test/src/reachability/mod.rs | 1 + crates/sniff-test/src/reachability/walk.rs | 66 +++++++++++++++++++++- tests/approach.md | 13 +++++ tests/unsafe/fail_simple/src/main.rs | 2 +- tests/unsafe/pass_nested/src/main.rs | 24 ++------ 11 files changed, 224 insertions(+), 27 deletions(-) create mode 100644 crates/sniff-test/src/axioms/mod.rs create mode 100644 crates/sniff-test/src/axioms/safety.rs create mode 100644 crates/sniff-test/src/reachability/err.rs create mode 100644 tests/approach.md diff --git a/Cargo.lock b/Cargo.lock index ff743f0..c328ca1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -446,6 +446,7 @@ checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" name = "sniff-test" version = "0.1.0" dependencies = [ + "anyhow", "clap", "env_logger", "regex", diff --git a/crates/sniff-test/Cargo.toml b/crates/sniff-test/Cargo.toml index 83f22b1..a6ed264 100644 --- a/crates/sniff-test/Cargo.toml +++ b/crates/sniff-test/Cargo.toml @@ -13,3 +13,4 @@ env_logger = { version = "0.10", default-features = false } clap = { version = "4.4", features = ["derive"] } serde = { version = "1", features = ["derive"] } regex = "1.11.2" +anyhow = "1.0.100" diff --git a/crates/sniff-test/src/axioms/mod.rs b/crates/sniff-test/src/axioms/mod.rs new file mode 100644 index 0000000..1cd48ae --- /dev/null +++ b/crates/sniff-test/src/axioms/mod.rs @@ -0,0 +1,64 @@ +use rustc_hir::{ + BodyId, + intravisit::{self, Visitor}, +}; +use rustc_middle::{ + hir::nested_filter, + ty::{TyCtxt, TypeckResults}, +}; +use rustc_span::source_map::Spanned; + +mod safety; + +pub use safety::{SafetyAxiom, SafetyFinder}; + +pub trait Axiom {} + +pub trait AxiomFinder { + type Axiom: Axiom; + + fn from_expr( + &mut self, + tcx: TyCtxt, + tyck: &TypeckResults, + expr: &rustc_hir::Expr, + ) -> Vec>; +} + +struct FinderWrapper<'tcx, T: AxiomFinder> { + tcx: TyCtxt<'tcx>, + finder: T, + tychck: &'tcx TypeckResults<'tcx>, + axioms: Vec>, +} + +pub fn find_axioms(finder: T, tcx: TyCtxt, body: BodyId) -> Vec> { + let tychck = tcx.typeck_body(body); + + let mut finder = FinderWrapper { + finder, + tychck, + tcx, + axioms: Vec::new(), + }; + + finder.visit_nested_body(body); + + finder.axioms +} + +impl<'tcx, T: AxiomFinder> Visitor<'tcx> for FinderWrapper<'tcx, T> { + type NestedFilter = nested_filter::OnlyBodies; + type MaybeTyCtxt = TyCtxt<'tcx>; + + fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt { + self.tcx + } + + fn visit_expr(&mut self, ex: &'tcx rustc_hir::Expr<'tcx>) -> Self::Result { + self.axioms + .extend(self.finder.from_expr(self.tcx, self.tychck, ex)); + + intravisit::walk_expr(self, ex) + } +} diff --git a/crates/sniff-test/src/axioms/safety.rs b/crates/sniff-test/src/axioms/safety.rs new file mode 100644 index 0000000..b06d9fe --- /dev/null +++ b/crates/sniff-test/src/axioms/safety.rs @@ -0,0 +1,41 @@ +use rustc_hir::ExprKind; +use rustc_middle::ty::TyCtxt; +use rustc_public::ty::FnDef; +use rustc_span::source_map::{Spanned, respan}; +use rustc_type_ir::TyKind; + +use crate::axioms::AxiomFinder; + +use super::Axiom; + +pub struct SafetyFinder; + +#[derive(Debug, Clone)] +pub enum SafetyAxiom { + RawPtrDeref, +} + +impl Axiom for SafetyAxiom {} + +impl AxiomFinder for SafetyFinder { + type Axiom = SafetyAxiom; + + fn from_expr( + &mut self, + tcx: TyCtxt, + tyck: &rustc_middle::ty::TypeckResults, + expr: &rustc_hir::Expr, + ) -> Vec> { + if let ExprKind::Unary(op, expr) = expr.kind { + let inner_ty = tyck.expr_ty(expr); + + if let TyKind::RawPtr(ty, _mut) = inner_ty.kind() { + let value = respan(expr.span, SafetyAxiom::RawPtrDeref); + return vec![value]; + } + } + + vec![] + // todo!() + } +} diff --git a/crates/sniff-test/src/lib.rs b/crates/sniff-test/src/lib.rs index c528a55..323567d 100644 --- a/crates/sniff-test/src/lib.rs +++ b/crates/sniff-test/src/lib.rs @@ -13,8 +13,10 @@ extern crate rustc_middle; extern crate rustc_public; extern crate rustc_session; extern crate rustc_span; +extern crate rustc_type_ir; pub mod annotations; +mod axioms; mod reachability; pub mod utils; @@ -106,8 +108,19 @@ impl rustc_driver::Callbacks for PrintAllItemsCallbacks { _compiler: &rustc_interface::interface::Compiler, tcx: TyCtxt<'_>, ) -> rustc_driver::Compilation { - rustc_public::rustc_internal::run(tcx, sniff_test_analysis(tcx)) - .expect("rustc public should work please"); + // let res = rustc_public::rustc_internal::run(tcx, sniff_test_analysis(tcx)) + // .expect("rustc public should work please"); + + // res.unwrap(); + + for local_def_id in tcx.hir_body_owners() { + let res = axioms::find_axioms( + axioms::SafetyFinder, + tcx, + tcx.hir_body_owned_by(local_def_id).id(), + ); + println!("res is {res:?}"); + } // Note that you should generally allow compilation to continue. If // your plugin is being invoked on a dependency, then you need to ensure @@ -127,12 +140,12 @@ fn all_local_fn_defs() -> Box<[FnDef]> { .collect::>() } -fn sniff_test_analysis(tcx: TyCtxt) -> impl FnOnce() { +fn sniff_test_analysis(tcx: TyCtxt) -> impl FnOnce() -> anyhow::Result<()> { move || { let all_fn_defs = all_local_fn_defs(); // 1. Find all 'bad' functions. Make sure they line up - let bad = reachability::filter_bad_functions(tcx, &all_fn_defs); + let bad = reachability::filter_bad_functions(tcx, &all_fn_defs).unwrap(); print!("bad {bad:?}"); // 2a. Find entry points @@ -140,7 +153,8 @@ fn sniff_test_analysis(tcx: TyCtxt) -> impl FnOnce() { println!("have entry points {entry_points:?}"); // 2b. Walk from those entry points to ensure proper labels - let res = reachability::walk_from_entry_points(&entry_points); + let res = reachability::walk_from_entry_points(tcx, &entry_points, bad).unwrap(); + Ok(()) } } diff --git a/crates/sniff-test/src/reachability/err.rs b/crates/sniff-test/src/reachability/err.rs new file mode 100644 index 0000000..045c436 --- /dev/null +++ b/crates/sniff-test/src/reachability/err.rs @@ -0,0 +1,14 @@ +use rustc_span::Span; + +use crate::annotations::Justification; + +#[derive(Debug)] +pub enum ConsistencyIssue { + UnsatisfiedJustification(Justification), +} + +#[derive(Debug)] +pub struct ConsistencyError { + call_at: Span, + issue: ConsistencyIssue, +} diff --git a/crates/sniff-test/src/reachability/mod.rs b/crates/sniff-test/src/reachability/mod.rs index 8776a14..0040fc5 100644 --- a/crates/sniff-test/src/reachability/mod.rs +++ b/crates/sniff-test/src/reachability/mod.rs @@ -1,6 +1,7 @@ pub mod attr; mod bad; mod entry; +mod err; mod walk; pub use bad::filter_bad_functions; diff --git a/crates/sniff-test/src/reachability/walk.rs b/crates/sniff-test/src/reachability/walk.rs index 7abf934..bd6d32c 100644 --- a/crates/sniff-test/src/reachability/walk.rs +++ b/crates/sniff-test/src/reachability/walk.rs @@ -1,5 +1,67 @@ +//! walk from entry points +//! for each function call, does it satisfy the requirements? +//! + +use std::collections::HashMap; + +use rustc_hir::def_id as internal; +use rustc_hir::intravisit::Visitor; +use rustc_middle::ty::TyCtxt; use rustc_public::ty::FnDef; -pub fn walk_from_entry_points(entry_points: &[FnDef]) -> FnDef { - todo!() +use crate::{annotations::Requirement, reachability::err::ConsistencyError}; + +pub fn walk_from_entry_points( + tcx: TyCtxt, + entry_points: &[FnDef], + requirements: HashMap>, +) -> Result<(), ConsistencyError> { + let entry_point_defs = entry_points + .iter() + .map(|fn_def| rustc_public::rustc_internal::internal(tcx, fn_def.0)) + .collect::>(); + + CallGraphVisitor::new(tcx, requirements).visit_from_entrypoints(&entry_point_defs) +} + +struct CallGraphVisitor<'tcx> { + tcx: TyCtxt<'tcx>, + requirements: HashMap>, +} + +type CallGraphResult = (); +impl<'tcx> CallGraphVisitor<'tcx> { + pub fn new(tcx: TyCtxt<'tcx>, requirements: HashMap>) -> Self { + Self { tcx, requirements } + } + + pub fn visit_from_entrypoints( + mut self, + entry_points: &[internal::DefId], + ) -> Result { + let to_visit = self + .tcx + .hir_crate_items(()) + .definitions() + .filter(|a| entry_points.contains(&a.to_def_id())) + .collect::>(); + + for i in self.tcx.hir_crate_items(()).free_items() { + if entry_points.contains(&i.owner_id.to_def_id()) { + println!("going to i {i:?}"); + } + } + + Ok(()) + } +} + +impl<'tcx> rustc_hir::intravisit::Visitor<'tcx> for CallGraphVisitor<'tcx> { + type NestedFilter = rustc_middle::hir::nested_filter::OnlyBodies; + + fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt { + self.tcx + } + + fn visit_expr(&mut self, ex: &'tcx rustc_hir::Expr<'tcx>) -> Self::Result {} } diff --git a/tests/approach.md b/tests/approach.md new file mode 100644 index 0000000..5d8838b --- /dev/null +++ b/tests/approach.md @@ -0,0 +1,13 @@ + + + +# Phases +1. Get something out the door + - any function with direct **unsafe axiom**s (e.g. ptr deref) should have an annotation explaining conditions + - calling a function with an annotation requires justification at call site + - for now, trust that dependencies are annotated correctly (changed in 2) + - single level of annotation (changed in 3) +2. Different levels of annotations + - annotations with specific conditions require specific justification +3. Check dependencies too + - allow the checking of dependencies diff --git a/tests/unsafe/fail_simple/src/main.rs b/tests/unsafe/fail_simple/src/main.rs index 90496cb..9b6419f 100644 --- a/tests/unsafe/fail_simple/src/main.rs +++ b/tests/unsafe/fail_simple/src/main.rs @@ -1,10 +1,10 @@ /// # Unsafe /// * nn: ptr should be non null +#[sniff_test_attrs::check_unsafe] fn foo(ptr: *const i32) -> i32 { unsafe { *ptr } } -#[sniff_test_attrs::check_unsafe] fn main() { let x = 1; foo(&raw const x); diff --git a/tests/unsafe/pass_nested/src/main.rs b/tests/unsafe/pass_nested/src/main.rs index 77281ae..ddd1d76 100644 --- a/tests/unsafe/pass_nested/src/main.rs +++ b/tests/unsafe/pass_nested/src/main.rs @@ -2,31 +2,17 @@ /// # Unsafe /// * nn: ptr should be non null -unsafe fn foo(ptr: *const i32) -> i32 { - unsafe { ptr } -} - -unsafe fn foo2(ptr: *const i32) -> i32 { - unsafe { ptr } -} - -/// # Unsafe -/// * nn: ptr should be non null -unsafe fn bar(ptr: *const i32) -> i32 { - /// SAFETY: - /// - nn: this is non-null bc i checked... - unsafe { - foo(ptr) - } +unsafe fn foo(val: *const i32) -> u32 { + unsafe { std::deref_in_std(val) } } #[sniff_test_attrs::check_unsafe] fn main() { let x = 1; - /// Safety: - /// * nn: ptr expr must be on null unsafe { - bar(&raw const x); + /// Safety: + /// * nn: ptr expr must be on null + foo(&raw const x); } } From a435f562a4ad543353dfae6af4ac01b97641ec33 Mon Sep 17 00:00:00 2001 From: AlexanderPortland Date: Tue, 21 Oct 2025 20:28:06 -0400 Subject: [PATCH 06/40] detecting safety axioms & reporting errors --- Cargo.lock | 16 ++++ crates/sniff-test/Cargo.toml | 1 + crates/sniff-test/src/annotations/mod.rs | 2 +- crates/sniff-test/src/annotations/types.rs | 29 ++++++- crates/sniff-test/src/axioms/mod.rs | 9 ++- crates/sniff-test/src/axioms/safety.rs | 31 ++++++-- crates/sniff-test/src/check/mod.rs | 68 ++++++++++++++++ crates/sniff-test/src/lib.rs | 19 ++--- crates/sniff-test/src/reachability/mod.rs | 2 +- crates/sniff-test/src/reachability/walk.rs | 90 +++++++++++----------- tests/unsafe/fail_nested/src/main.rs | 4 +- 11 files changed, 196 insertions(+), 75 deletions(-) create mode 100644 crates/sniff-test/src/check/mod.rs diff --git a/Cargo.lock b/Cargo.lock index c328ca1..d3acd00 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -162,6 +162,12 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + [[package]] name = "encode_unicode" version = "1.0.0" @@ -234,6 +240,15 @@ version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" +[[package]] +name = "itertools" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.15" @@ -449,6 +464,7 @@ dependencies = [ "anyhow", "clap", "env_logger", + "itertools", "regex", "rustc_plugin", "rustc_utils", diff --git a/crates/sniff-test/Cargo.toml b/crates/sniff-test/Cargo.toml index a6ed264..90a7f7e 100644 --- a/crates/sniff-test/Cargo.toml +++ b/crates/sniff-test/Cargo.toml @@ -14,3 +14,4 @@ clap = { version = "4.4", features = ["derive"] } serde = { version = "1", features = ["derive"] } regex = "1.11.2" anyhow = "1.0.100" +itertools = "0.14.0" diff --git a/crates/sniff-test/src/annotations/mod.rs b/crates/sniff-test/src/annotations/mod.rs index fb1d144..48887dd 100644 --- a/crates/sniff-test/src/annotations/mod.rs +++ b/crates/sniff-test/src/annotations/mod.rs @@ -7,7 +7,7 @@ use std::borrow::Borrow; mod attr; mod err; -mod parsing; +pub mod parsing; mod types; pub use err::ParsingError; diff --git a/crates/sniff-test/src/annotations/types.rs b/crates/sniff-test/src/annotations/types.rs index 44b5088..b6770e8 100644 --- a/crates/sniff-test/src/annotations/types.rs +++ b/crates/sniff-test/src/annotations/types.rs @@ -16,6 +16,26 @@ impl Requirement { description: description.borrow().to_string(), } } + + pub fn name(&self) -> &str { + &self.name.0 + } + + pub fn description(&self) -> &str { + &self.description + } + + pub fn construct, B: Borrow>( + iter: impl IntoIterator, + ) -> Vec { + Vec::from_iter(iter.into_iter().map(|(name, desc)| { + Requirement::new( + ConditionName::try_new(name) + .expect("construct should only be called with valid condition names"), + desc, + ) + })) + } } #[derive(PartialEq, Eq, Debug)] @@ -39,9 +59,9 @@ pub struct ConditionName(String); impl ConditionName { /// Construct a new condition name, checking all invariants to ensure it is valid. - pub fn try_new(name: &str) -> Result { + pub fn try_new>(name: T) -> Result { // For now, just check that it's a single word with no extra white space. - Ok(ConditionName(check_single_word(name)?.to_string())) + Ok(ConditionName(check_single_word(name)?)) } } @@ -53,7 +73,8 @@ pub enum InvalidConditionNameReason { pub const INVALID_WHITESPACE: [char; 3] = [' ', '\n', '\t']; -fn check_single_word(name: &str) -> Result<&str, InvalidConditionNameReason> { +fn check_single_word>(name: T) -> Result { + let name = name.borrow(); // Valid requirement names shouldn't contain whitespace. if name.contains(INVALID_WHITESPACE) { if name @@ -68,5 +89,5 @@ fn check_single_word(name: &str) -> Result<&str, InvalidConditionNameReason> { // contains other words return Err(InvalidConditionNameReason::MultipleWords); } - Ok(name) + Ok(name.to_string()) } diff --git a/crates/sniff-test/src/axioms/mod.rs b/crates/sniff-test/src/axioms/mod.rs index 1cd48ae..56d4cb0 100644 --- a/crates/sniff-test/src/axioms/mod.rs +++ b/crates/sniff-test/src/axioms/mod.rs @@ -1,3 +1,5 @@ +use std::fmt::Display; + use rustc_hir::{ BodyId, intravisit::{self, Visitor}, @@ -12,7 +14,11 @@ mod safety; pub use safety::{SafetyAxiom, SafetyFinder}; -pub trait Axiom {} +pub trait Axiom: Display { + fn known_requirements(&self) -> Option> { + None + } +} pub trait AxiomFinder { type Axiom: Axiom; @@ -55,6 +61,7 @@ impl<'tcx, T: AxiomFinder> Visitor<'tcx> for FinderWrapper<'tcx, T> { self.tcx } + #[allow(clippy::semicolon_if_nothing_returned)] fn visit_expr(&mut self, ex: &'tcx rustc_hir::Expr<'tcx>) -> Self::Result { self.axioms .extend(self.finder.from_expr(self.tcx, self.tychck, ex)); diff --git a/crates/sniff-test/src/axioms/safety.rs b/crates/sniff-test/src/axioms/safety.rs index b06d9fe..0260706 100644 --- a/crates/sniff-test/src/axioms/safety.rs +++ b/crates/sniff-test/src/axioms/safety.rs @@ -1,12 +1,13 @@ +use std::fmt::Display; + +use rustc_ast::UnOp; use rustc_hir::ExprKind; use rustc_middle::ty::TyCtxt; -use rustc_public::ty::FnDef; use rustc_span::source_map::{Spanned, respan}; use rustc_type_ir::TyKind; -use crate::axioms::AxiomFinder; - use super::Axiom; +use crate::{annotations, axioms::AxiomFinder}; pub struct SafetyFinder; @@ -15,18 +16,35 @@ pub enum SafetyAxiom { RawPtrDeref, } -impl Axiom for SafetyAxiom {} +impl Axiom for SafetyAxiom { + fn known_requirements(&self) -> Option> { + match self { + Self::RawPtrDeref => Some(annotations::Requirement::construct([ + ("ptr-non-null", "the dereferenced pointer must be non-null"), + ("ptr-aligned", "the dereferenced pointer must be aligned"), + ])), + } + } +} + +impl Display for SafetyAxiom { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::RawPtrDeref => f.write_str("raw pointer derefence"), + } + } +} impl AxiomFinder for SafetyFinder { type Axiom = SafetyAxiom; fn from_expr( &mut self, - tcx: TyCtxt, + _tcx: TyCtxt, tyck: &rustc_middle::ty::TypeckResults, expr: &rustc_hir::Expr, ) -> Vec> { - if let ExprKind::Unary(op, expr) = expr.kind { + if let ExprKind::Unary(UnOp::Deref, expr) = expr.kind { let inner_ty = tyck.expr_ty(expr); if let TyKind::RawPtr(ty, _mut) = inner_ty.kind() { @@ -36,6 +54,5 @@ impl AxiomFinder for SafetyFinder { } vec![] - // todo!() } } diff --git a/crates/sniff-test/src/check/mod.rs b/crates/sniff-test/src/check/mod.rs new file mode 100644 index 0000000..452d331 --- /dev/null +++ b/crates/sniff-test/src/check/mod.rs @@ -0,0 +1,68 @@ +use itertools::Itertools; +use rustc_errors::{DiagCtxt, DiagCtxtHandle}; +use rustc_middle::ty::TyCtxt; +use rustc_span::{ErrorGuaranteed, Span, source_map::Spanned}; + +use crate::{ + annotations::{self, Annotation}, + axioms::{self, Axiom}, +}; + +/// Checks that all local functions in the crate are properly annotated. +pub fn check_properly_annotated(tcx: TyCtxt) -> Result<(), ErrorGuaranteed> { + for local_def_id in tcx.hir_body_owners() { + let name = &tcx.def_path_debug_str(local_def_id.to_def_id()); + let axioms = axioms::find_axioms( + axioms::SafetyFinder, + tcx, + tcx.hir_body_owned_by(local_def_id).id(), + ); + println!("{name}: axioms are {axioms:?}"); + + let annotations = annotations::Requirement::try_parse(tcx, local_def_id.to_def_id()); + println!("{name}: annotations are {annotations:?}"); + + if !axioms.is_empty() && annotations.is_none() { + return Err(needs_annotation( + tcx.dcx(), + name, + tcx.def_span(local_def_id.to_def_id()), + axioms, + )); + } + } + + todo!() +} + +fn needs_annotation( + dcx: DiagCtxtHandle, + fn_name: &str, + def_span: Span, + bc_of_axioms: Vec>, +) -> ErrorGuaranteed { + let mut diag = dcx.struct_span_err( + def_span, + format!("function {fn_name} has unsafe axioms, but is not annotated unsafe"), + ); + + for axiom in bc_of_axioms { + diag = diag.with_span_note(axiom.span, format!("{} here", axiom.node)); + if let Some(known_reqs) = axiom.node.known_requirements() { + let intro_string = format!("this axiom has known requirements:"); + + let known_req_strs = known_reqs + .into_iter() + .enumerate() + .map(|(i, req)| format!("\t{}. {}", i + 1, req.description())); + + diag = diag.with_help( + std::iter::once(intro_string) + .chain(known_req_strs) + .join("\n"), + ); + } + } + + diag.emit() +} diff --git a/crates/sniff-test/src/lib.rs b/crates/sniff-test/src/lib.rs index 323567d..8ca6dfc 100644 --- a/crates/sniff-test/src/lib.rs +++ b/crates/sniff-test/src/lib.rs @@ -5,6 +5,7 @@ #![cfg_attr(test, feature(assert_matches))] extern crate lazy_static; +extern crate rustc_ast; extern crate rustc_driver; extern crate rustc_errors; extern crate rustc_hir; @@ -17,6 +18,7 @@ extern crate rustc_type_ir; pub mod annotations; mod axioms; +mod check; mod reachability; pub mod utils; @@ -36,6 +38,7 @@ use serde::{Deserialize, Serialize}; use crate::{ annotations::{Annotation, Justification, ParsingError, Requirement}, + check::check_properly_annotated, utils::SniffTestDiagnostic, }; @@ -108,19 +111,7 @@ impl rustc_driver::Callbacks for PrintAllItemsCallbacks { _compiler: &rustc_interface::interface::Compiler, tcx: TyCtxt<'_>, ) -> rustc_driver::Compilation { - // let res = rustc_public::rustc_internal::run(tcx, sniff_test_analysis(tcx)) - // .expect("rustc public should work please"); - - // res.unwrap(); - - for local_def_id in tcx.hir_body_owners() { - let res = axioms::find_axioms( - axioms::SafetyFinder, - tcx, - tcx.hir_body_owned_by(local_def_id).id(), - ); - println!("res is {res:?}"); - } + let res = check_properly_annotated(tcx); // Note that you should generally allow compilation to continue. If // your plugin is being invoked on a dependency, then you need to ensure @@ -153,7 +144,7 @@ fn sniff_test_analysis(tcx: TyCtxt) -> impl FnOnce() -> anyhow::Result<()> { println!("have entry points {entry_points:?}"); // 2b. Walk from those entry points to ensure proper labels - let res = reachability::walk_from_entry_points(tcx, &entry_points, bad).unwrap(); + // let res = reachability::walk_from_entry_points(tcx, &entry_points, bad).unwrap(); Ok(()) } } diff --git a/crates/sniff-test/src/reachability/mod.rs b/crates/sniff-test/src/reachability/mod.rs index 0040fc5..aa62e12 100644 --- a/crates/sniff-test/src/reachability/mod.rs +++ b/crates/sniff-test/src/reachability/mod.rs @@ -6,4 +6,4 @@ mod walk; pub use bad::filter_bad_functions; pub use entry::filter_entry_points; -pub use walk::walk_from_entry_points; +// pub use walk::walk_from_entry_points; diff --git a/crates/sniff-test/src/reachability/walk.rs b/crates/sniff-test/src/reachability/walk.rs index bd6d32c..df90775 100644 --- a/crates/sniff-test/src/reachability/walk.rs +++ b/crates/sniff-test/src/reachability/walk.rs @@ -11,57 +11,57 @@ use rustc_public::ty::FnDef; use crate::{annotations::Requirement, reachability::err::ConsistencyError}; -pub fn walk_from_entry_points( - tcx: TyCtxt, - entry_points: &[FnDef], - requirements: HashMap>, -) -> Result<(), ConsistencyError> { - let entry_point_defs = entry_points - .iter() - .map(|fn_def| rustc_public::rustc_internal::internal(tcx, fn_def.0)) - .collect::>(); +// pub fn walk_from_entry_points( +// tcx: TyCtxt, +// entry_points: &[FnDef], +// requirements: HashMap>, +// ) -> Result<(), ConsistencyError> { +// let entry_point_defs = entry_points +// .iter() +// .map(|fn_def| rustc_public::rustc_internal::internal(tcx, fn_def.0)) +// .collect::>(); - CallGraphVisitor::new(tcx, requirements).visit_from_entrypoints(&entry_point_defs) -} +// CallGraphVisitor::new(tcx, requirements).visit_from_entrypoints(&entry_point_defs) +// } -struct CallGraphVisitor<'tcx> { - tcx: TyCtxt<'tcx>, - requirements: HashMap>, -} +// struct CallGraphVisitor<'tcx> { +// tcx: TyCtxt<'tcx>, +// requirements: HashMap>, +// } -type CallGraphResult = (); -impl<'tcx> CallGraphVisitor<'tcx> { - pub fn new(tcx: TyCtxt<'tcx>, requirements: HashMap>) -> Self { - Self { tcx, requirements } - } +// type CallGraphResult = (); +// impl<'tcx> CallGraphVisitor<'tcx> { +// pub fn new(tcx: TyCtxt<'tcx>, requirements: HashMap>) -> Self { +// Self { tcx, requirements } +// } - pub fn visit_from_entrypoints( - mut self, - entry_points: &[internal::DefId], - ) -> Result { - let to_visit = self - .tcx - .hir_crate_items(()) - .definitions() - .filter(|a| entry_points.contains(&a.to_def_id())) - .collect::>(); +// pub fn visit_from_entrypoints( +// mut self, +// entry_points: &[internal::DefId], +// ) -> Result { +// let to_visit = self +// .tcx +// .hir_crate_items(()) +// .definitions() +// .filter(|a| entry_points.contains(&a.to_def_id())) +// .collect::>(); - for i in self.tcx.hir_crate_items(()).free_items() { - if entry_points.contains(&i.owner_id.to_def_id()) { - println!("going to i {i:?}"); - } - } +// for i in self.tcx.hir_crate_items(()).free_items() { +// if entry_points.contains(&i.owner_id.to_def_id()) { +// println!("going to i {i:?}"); +// } +// } - Ok(()) - } -} +// Ok(()) +// } +// } -impl<'tcx> rustc_hir::intravisit::Visitor<'tcx> for CallGraphVisitor<'tcx> { - type NestedFilter = rustc_middle::hir::nested_filter::OnlyBodies; +// impl<'tcx> rustc_hir::intravisit::Visitor<'tcx> for CallGraphVisitor<'tcx> { +// type NestedFilter = rustc_middle::hir::nested_filter::OnlyBodies; - fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt { - self.tcx - } +// fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt { +// self.tcx +// } - fn visit_expr(&mut self, ex: &'tcx rustc_hir::Expr<'tcx>) -> Self::Result {} -} +// fn visit_expr(&mut self, ex: &'tcx rustc_hir::Expr<'tcx>) -> Self::Result {} +// } diff --git a/tests/unsafe/fail_nested/src/main.rs b/tests/unsafe/fail_nested/src/main.rs index c163963..3516df6 100644 --- a/tests/unsafe/fail_nested/src/main.rs +++ b/tests/unsafe/fail_nested/src/main.rs @@ -1,7 +1,7 @@ -/// # Unsafe +// /// # Unsafe /// * nn: ptr should be non null fn foo(ptr: *const i32) -> i32 { - unsafe { *ptr } + unsafe { *ptr + *ptr } } fn bar(ptr: *const i32) -> i32 { From 9ac5ab89c93b262a8fc4e8384abb9bbf8cef30cc Mon Sep 17 00:00:00 2001 From: AlexanderPortland Date: Tue, 21 Oct 2025 22:51:09 -0400 Subject: [PATCH 07/40] add proper readme --- .gitignore | 3 ++- README.md | 41 +++++++++++++++++++++++++++++++++++++ crates/sniff-test/README.md | 16 --------------- 3 files changed, 43 insertions(+), 17 deletions(-) create mode 100644 README.md delete mode 100644 crates/sniff-test/README.md diff --git a/.gitignore b/.gitignore index 2f9dd2c..7bbce1b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ target -review.sh \ No newline at end of file +review.sh +notes.md \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..8e45fa5 --- /dev/null +++ b/README.md @@ -0,0 +1,41 @@ +# Sniff-test + +## Running +You can run `sniff-test` with the following command once it's been built using `cargo build` (just replace `PATH_TO_REPO` with the directory in which you installed this repo). +*[We should add instructions for installing to cargo path later.]* + +```shell +cargo build # in this directory + +cd [PATH_TO_TEST_CRATE] + +cargo clean && RUSTFLAGS="-Zcrate-attr=feature(register_tool) -Zcrate-attr=register_tool(sniff_tool)" [PATH_TO_REPO]/sniff-test/target/debug/cargo-sniff-test +``` + +We need the extra `RUSTFLAGS` to register our `sniff_tool` tool to allow for our custom attributes. + +### Linking error + +If you encounter an error along the lines of `dyld[43663]: Library not loaded: ...`, run: + +```shell +export DYLD_LIBRARY_PATH="$DYLD_LIBRARY_PATH:$(rustc +nightly-2025-08-20 --print target-libdir)" +``` + +## Testing + +As of now, we have the infrastructure to use `cargo-insta` for snapshot testing, but there's not enough functionality for it to be particularly useful yet. + +### Taking snapshots +Using `cargo insta test`, you can snapshot all of our test crates, saving all new snapshots within each of the crates. +This will run the [`cargo-sniff-test`](/crates/sniff-test/src/bin/cargo-sniff-test.rs) binary on every crate within a subdirectory of [`tests`](/tests). + +By default, `cargo insta review` will only look through the current workspace to find new snapshots, but ours test crates have to be in separate workspaces to not all compile together. +Instead, now the testing infrastructure automatically builds a [`review.sh`](/review.sh) script that will review all of the test crates together. + +```shell +cargo insta test # snapshot all tests +./review.sh # review new snapshots + +cargo test # run all tests (no new snapshots) +``` \ No newline at end of file diff --git a/crates/sniff-test/README.md b/crates/sniff-test/README.md deleted file mode 100644 index fad523c..0000000 --- a/crates/sniff-test/README.md +++ /dev/null @@ -1,16 +0,0 @@ -# Usage notes - -You should be able to just run this using `cargo build` and then running the resulting `cargo-sniff-test` binary within the crate you'd like to analyze. [We should add instructions for installing to cargo path later.] - -### Linking error - -If you encounter an error along the lines of `dyld[43663]: Library not loaded: ...`, run: -```shell -export DYLD_LIBRARY_PATH="$DYLD_LIBRARY_PATH:$(rustc +nightly-2025-08-20 --print target-libdir)" -``` - - -you can run the jawn with -```rust -cargo clean && RUSTFLAGS="-Zcrate-attr=feature(register_tool) -Zcrate-attr=register_tool(sniff_tool)" /Users/alexanderportland/Desktop/research/sniff-test/target/debug/cargo-sniff-test -``` \ No newline at end of file From 019f7d6ea9e513f6a362909c8797d7a0b166856f Mon Sep 17 00:00:00 2001 From: AlexanderPortland Date: Wed, 22 Oct 2025 16:41:27 -0400 Subject: [PATCH 08/40] display of axiom issues --- crates/sniff-test/src/annotations/types.rs | 16 +-- crates/sniff-test/src/axioms/mod.rs | 4 +- crates/sniff-test/src/axioms/panic.rs | 53 +++++++++ crates/sniff-test/src/axioms/safety.rs | 4 +- crates/sniff-test/src/check/mod.rs | 62 +++++++--- crates/sniff-test/src/lib.rs | 11 +- crates/sniff-test/src/reachability/entry.rs | 27 +++-- crates/sniff-test/src/reachability/mod.rs | 4 +- crates/sniff-test/src/reachability/walk.rs | 111 +++++++++++++++++- tests/approach.md | 13 -- tests/unsafe/fail_nested/src/main.rs | 5 +- .../Cargo.lock | 2 +- .../Cargo.toml | 2 +- .../fail_not_annotated.snap | 23 ++++ tests/unsafe/fail_not_annotated/src/main.rs | 17 +++ 15 files changed, 290 insertions(+), 64 deletions(-) create mode 100644 crates/sniff-test/src/axioms/panic.rs delete mode 100644 tests/approach.md rename tests/unsafe/{fail_nested => fail_not_annotated}/Cargo.lock (97%) rename tests/unsafe/{fail_nested => fail_not_annotated}/Cargo.toml (83%) create mode 100644 tests/unsafe/fail_not_annotated/fail_not_annotated.snap create mode 100644 tests/unsafe/fail_not_annotated/src/main.rs diff --git a/crates/sniff-test/src/annotations/types.rs b/crates/sniff-test/src/annotations/types.rs index b6770e8..207cf84 100644 --- a/crates/sniff-test/src/annotations/types.rs +++ b/crates/sniff-test/src/annotations/types.rs @@ -28,13 +28,15 @@ impl Requirement { pub fn construct, B: Borrow>( iter: impl IntoIterator, ) -> Vec { - Vec::from_iter(iter.into_iter().map(|(name, desc)| { - Requirement::new( - ConditionName::try_new(name) - .expect("construct should only be called with valid condition names"), - desc, - ) - })) + iter.into_iter() + .map(|(name, desc)| { + Requirement::new( + ConditionName::try_new(name) + .expect("construct should only be called with valid condition names"), + desc, + ) + }) + .collect() } } diff --git a/crates/sniff-test/src/axioms/mod.rs b/crates/sniff-test/src/axioms/mod.rs index 56d4cb0..e47dd23 100644 --- a/crates/sniff-test/src/axioms/mod.rs +++ b/crates/sniff-test/src/axioms/mod.rs @@ -10,9 +10,11 @@ use rustc_middle::{ }; use rustc_span::source_map::Spanned; +mod panic; mod safety; -pub use safety::{SafetyAxiom, SafetyFinder}; +pub use panic::PanicFinder; +pub use safety::SafetyFinder; pub trait Axiom: Display { fn known_requirements(&self) -> Option> { diff --git a/crates/sniff-test/src/axioms/panic.rs b/crates/sniff-test/src/axioms/panic.rs new file mode 100644 index 0000000..919982a --- /dev/null +++ b/crates/sniff-test/src/axioms/panic.rs @@ -0,0 +1,53 @@ +use rustc_hir::ExprKind; +use rustc_middle::ty::TyCtxt; +use rustc_span::source_map::{Spanned, respan}; +use std::fmt::Display; + +use super::Axiom; +use crate::axioms::AxiomFinder; + +pub struct PanicFinder; + +#[derive(Debug, Clone)] +pub enum PanicAxiom { + ExplicitPanic, +} + +impl Axiom for PanicAxiom {} + +impl Display for PanicAxiom { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::ExplicitPanic => f.write_str("explicit panic"), + } + } +} + +impl AxiomFinder for PanicFinder { + type Axiom = PanicAxiom; + + fn from_expr( + &mut self, + tcx: TyCtxt, + tyck: &rustc_middle::ty::TypeckResults, + expr: &rustc_hir::Expr, + ) -> Vec> { + if let ExprKind::Call(func, _) = expr.kind + && let Some(def_id) = tyck.type_dependent_def_id(func.hir_id) + { + let lang_items = tcx.lang_items(); + + // Check against lang items + if Some(def_id) == lang_items.panic_fn() + || Some(def_id) == lang_items.panic_fmt() + || Some(def_id) == lang_items.begin_panic_fn() + || Some(def_id) == lang_items.panic_impl() + { + let value = respan(expr.span, PanicAxiom::ExplicitPanic); + return vec![value]; + } + } + + vec![] + } +} diff --git a/crates/sniff-test/src/axioms/safety.rs b/crates/sniff-test/src/axioms/safety.rs index 0260706..a57842c 100644 --- a/crates/sniff-test/src/axioms/safety.rs +++ b/crates/sniff-test/src/axioms/safety.rs @@ -3,6 +3,7 @@ use std::fmt::Display; use rustc_ast::UnOp; use rustc_hir::ExprKind; use rustc_middle::ty::TyCtxt; +use rustc_query_system::dep_graph::dep_node::DepNodeParams; use rustc_span::source_map::{Spanned, respan}; use rustc_type_ir::TyKind; @@ -44,10 +45,11 @@ impl AxiomFinder for SafetyFinder { tyck: &rustc_middle::ty::TypeckResults, expr: &rustc_hir::Expr, ) -> Vec> { + // println!("looking at {}", expr.to_debug_str(_tcx)); if let ExprKind::Unary(UnOp::Deref, expr) = expr.kind { let inner_ty = tyck.expr_ty(expr); - if let TyKind::RawPtr(ty, _mut) = inner_ty.kind() { + if let TyKind::RawPtr(_ty, _mut) = inner_ty.kind() { let value = respan(expr.span, SafetyAxiom::RawPtrDeref); return vec![value]; } diff --git a/crates/sniff-test/src/check/mod.rs b/crates/sniff-test/src/check/mod.rs index 452d331..ac0cff0 100644 --- a/crates/sniff-test/src/check/mod.rs +++ b/crates/sniff-test/src/check/mod.rs @@ -1,55 +1,81 @@ use itertools::Itertools; -use rustc_errors::{DiagCtxt, DiagCtxtHandle}; +use rustc_errors::DiagCtxtHandle; use rustc_middle::ty::TyCtxt; -use rustc_span::{ErrorGuaranteed, Span, source_map::Spanned}; +use rustc_span::{ErrorGuaranteed, Span, SpanData, source_map::Spanned}; use crate::{ annotations::{self, Annotation}, axioms::{self, Axiom}, + reachability::{self, LocalReachable}, }; /// Checks that all local functions in the crate are properly annotated. pub fn check_properly_annotated(tcx: TyCtxt) -> Result<(), ErrorGuaranteed> { - for local_def_id in tcx.hir_body_owners() { - let name = &tcx.def_path_debug_str(local_def_id.to_def_id()); + let mut res = Ok(()); + + let entry = reachability::annotated_local_entry_points(tcx); + + let entry = entry.collect::>(); + + println!("entry is {entry:?}"); + + let reachable = reachability::local_reachable_from(tcx, entry).collect::>(); + + println!("reachable is {:?}", reachable); + + for reachable in reachable.iter().cloned() { + let name = &tcx.def_path_debug_str(reachable.reach.to_def_id()); let axioms = axioms::find_axioms( axioms::SafetyFinder, tcx, - tcx.hir_body_owned_by(local_def_id).id(), + tcx.hir_body_owned_by(reachable.reach).id(), ); - println!("{name}: axioms are {axioms:?}"); - let annotations = annotations::Requirement::try_parse(tcx, local_def_id.to_def_id()); - println!("{name}: annotations are {annotations:?}"); + let annotations = annotations::Requirement::try_parse(tcx, reachable.reach.to_def_id()); if !axioms.is_empty() && annotations.is_none() { - return Err(needs_annotation( - tcx.dcx(), - name, - tcx.def_span(local_def_id.to_def_id()), - axioms, - )); + res = Err(needs_annotation(tcx.dcx(), tcx, reachable, axioms)); + // println!("err from {name}"); } } - todo!() + res } fn needs_annotation( dcx: DiagCtxtHandle, - fn_name: &str, - def_span: Span, + tcx: TyCtxt, + reachable: LocalReachable, bc_of_axioms: Vec>, ) -> ErrorGuaranteed { + let def_span = tcx.def_span(reachable.reach); + let fn_name = tcx.def_path_str(reachable.reach.to_def_id()); let mut diag = dcx.struct_span_err( def_span, format!("function {fn_name} has unsafe axioms, but is not annotated unsafe"), ); + let reachability_str = reachable + .from + .iter() + .map(|def| { + let name = tcx.def_path_str(def.0); + let s = tcx + .sess + .source_map() + .span_to_string(def.1, rustc_span::FileNameDisplayPreference::Local); + let colon = s.find(": ").expect("should have a colon"); + format!("{name} ({})", &s[..colon]) + }) + .chain(std::iter::once(format!("*{fn_name}*"))) + .join(" -> "); + + diag = diag.with_help(format!("(reachable from [{reachability_str}])")); + for axiom in bc_of_axioms { diag = diag.with_span_note(axiom.span, format!("{} here", axiom.node)); if let Some(known_reqs) = axiom.node.known_requirements() { - let intro_string = format!("this axiom has known requirements:"); + let intro_string = "this axiom has known requirements:".to_string(); let known_req_strs = known_reqs .into_iter() diff --git a/crates/sniff-test/src/lib.rs b/crates/sniff-test/src/lib.rs index 8ca6dfc..d514059 100644 --- a/crates/sniff-test/src/lib.rs +++ b/crates/sniff-test/src/lib.rs @@ -12,6 +12,7 @@ extern crate rustc_hir; extern crate rustc_interface; extern crate rustc_middle; extern crate rustc_public; +extern crate rustc_query_system; extern crate rustc_session; extern crate rustc_span; extern crate rustc_type_ir; @@ -111,7 +112,11 @@ impl rustc_driver::Callbacks for PrintAllItemsCallbacks { _compiler: &rustc_interface::interface::Compiler, tcx: TyCtxt<'_>, ) -> rustc_driver::Compilation { - let res = check_properly_annotated(tcx); + let Ok(()) = check_properly_annotated(tcx) else { + return rustc_driver::Compilation::Stop; + }; + + println!("compilation successful!!"); // Note that you should generally allow compilation to continue. If // your plugin is being invoked on a dependency, then you need to ensure @@ -140,8 +145,8 @@ fn sniff_test_analysis(tcx: TyCtxt) -> impl FnOnce() -> anyhow::Result<()> { print!("bad {bad:?}"); // 2a. Find entry points - let entry_points = reachability::filter_entry_points(tcx, &all_fn_defs); - println!("have entry points {entry_points:?}"); + // let entry_points = reachability::filter_entry_points(tcx, &all_fn_defs); + // println!("have entry points {entry_points:?}"); // 2b. Walk from those entry points to ensure proper labels // let res = reachability::walk_from_entry_points(tcx, &entry_points, bad).unwrap(); diff --git a/crates/sniff-test/src/reachability/entry.rs b/crates/sniff-test/src/reachability/entry.rs index a09adea..7a79367 100644 --- a/crates/sniff-test/src/reachability/entry.rs +++ b/crates/sniff-test/src/reachability/entry.rs @@ -1,20 +1,27 @@ +use std::collections::HashSet; + +use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::ty::TyCtxt; use rustc_public::ty::FnDef; use crate::reachability::attr::{self, SniffToolAttr}; -pub fn filter_entry_points(tcx: TyCtxt, items: &[FnDef]) -> Vec { - items - .iter() - .filter(|item| is_entry_point(tcx, item)) - .copied() - .collect::>() -} +// pub fn filter_entry_points(tcx: TyCtxt, items: &[FnDef]) -> Vec { +// items +// .into_iter() +// .filter(|item| is_entry_point(tcx, **item)) +// .copied() +// .collect::>() +// } -fn is_entry_point(tcx: TyCtxt, item: &FnDef) -> bool { - let internal = rustc_public::rustc_internal::internal(tcx, item.0); +pub fn annotated_local_entry_points(tcx: TyCtxt) -> impl Iterator { + tcx.hir_body_owners() + .filter(move |item| is_entry_point(tcx, item.to_def_id())) + .map(|item| item) +} - attr::attrs_for(internal, tcx).is_some_and(|attr| match attr { +fn is_entry_point(tcx: TyCtxt, item: DefId) -> bool { + attr::attrs_for(item, tcx).is_some_and(|attr| match attr { SniffToolAttr::CheckUnsafe => true, }) } diff --git a/crates/sniff-test/src/reachability/mod.rs b/crates/sniff-test/src/reachability/mod.rs index aa62e12..1ee4dfa 100644 --- a/crates/sniff-test/src/reachability/mod.rs +++ b/crates/sniff-test/src/reachability/mod.rs @@ -5,5 +5,5 @@ mod err; mod walk; pub use bad::filter_bad_functions; -pub use entry::filter_entry_points; -// pub use walk::walk_from_entry_points; +pub use entry::annotated_local_entry_points; +pub use walk::{LocalReachable, local_reachable_from}; diff --git a/crates/sniff-test/src/reachability/walk.rs b/crates/sniff-test/src/reachability/walk.rs index df90775..7c06ee9 100644 --- a/crates/sniff-test/src/reachability/walk.rs +++ b/crates/sniff-test/src/reachability/walk.rs @@ -2,15 +2,116 @@ //! for each function call, does it satisfy the requirements? //! -use std::collections::HashMap; - -use rustc_hir::def_id as internal; -use rustc_hir::intravisit::Visitor; -use rustc_middle::ty::TyCtxt; +use crate::rustc_middle::mir::visit::Visitor; +use rustc_hir::def_id::{self as internal, DefId, LocalDefId}; +use rustc_hir::{ExprKind, Node, intravisit}; +use rustc_middle::mir::{ConstOperand, Operand, TerminatorKind}; +use rustc_middle::ty::{TyCtxt, TyKind}; use rustc_public::ty::FnDef; +use rustc_span::Span; +use rustc_span::sym::c; +use std::collections::{HashMap, HashSet}; use crate::{annotations::Requirement, reachability::err::ConsistencyError}; +#[derive(Debug, Clone)] +pub struct LocalReachable { + pub reach: LocalDefId, + pub from: Vec<(LocalDefId, Span)>, +} + +impl LocalReachable { + fn goes_to(&self, def_id: LocalDefId, span: Span) -> Self { + LocalReachable { + reach: def_id, + from: self + .from + .iter() + .cloned() + .chain(std::iter::once((self.reach, span))) + .collect(), + } + } +} + +pub fn local_reachable_from( + tcx: TyCtxt, + entry_points: impl IntoIterator, +) -> impl Iterator { + CallGraphVisitor::new(tcx, entry_points.into_iter()).all_local_reachable() +} + +struct CallGraphVisitor<'tcx> { + tcx: TyCtxt<'tcx>, + to_visit: Vec, + reachable: HashMap, +} + +impl<'tcx> CallGraphVisitor<'tcx> { + fn new(tcx: TyCtxt<'tcx>, entry_points: impl Iterator) -> Self { + Self { + tcx, + to_visit: entry_points + .map(|reach| LocalReachable { + reach, + from: Vec::new(), + }) + .collect(), + reachable: HashMap::new(), + } + } + + fn all_local_reachable(mut self) -> impl Iterator { + while let Some(d) = self.to_visit.pop() { + if !self.reachable.contains_key(&d.reach) { + let body = self.tcx.optimized_mir(d.reach); + println!("[!] visit body {:?}", d.reach); + let mut visitor = BodyVisitor(self.tcx, &mut self.to_visit, &d); + visitor.visit_body(body); + self.reachable.insert(d.reach, d); + } + } + self.reachable.into_values() + } +} + +struct BodyVisitor<'tcx, 'm>( + TyCtxt<'tcx>, + &'m mut Vec, + &'m LocalReachable, +); + +impl<'tcx> rustc_middle::mir::visit::Visitor<'tcx> for BodyVisitor<'tcx, '_> { + fn visit_terminator( + &mut self, + terminator: &rustc_middle::mir::Terminator<'tcx>, + location: rustc_middle::mir::Location, + ) { + println!("terminator {:?}", terminator); + if let TerminatorKind::Call { + func, + call_source, + fn_span, + .. + } = &terminator.kind + { + if let Operand::Constant(box co) = func { + if let TyKind::FnDef(def_id, _substs) = co.const_.ty().kind() { + println!("call to {def_id:?}"); + + if let Some(local_def) = def_id.as_local() { + println!("and it's local!"); + self.1 + .push(self.2.goes_to(local_def, terminator.source_info.span)); + } + } + } + } + + self.super_terminator(terminator, location); + } +} + // pub fn walk_from_entry_points( // tcx: TyCtxt, // entry_points: &[FnDef], diff --git a/tests/approach.md b/tests/approach.md deleted file mode 100644 index 5d8838b..0000000 --- a/tests/approach.md +++ /dev/null @@ -1,13 +0,0 @@ - - - -# Phases -1. Get something out the door - - any function with direct **unsafe axiom**s (e.g. ptr deref) should have an annotation explaining conditions - - calling a function with an annotation requires justification at call site - - for now, trust that dependencies are annotated correctly (changed in 2) - - single level of annotation (changed in 3) -2. Different levels of annotations - - annotations with specific conditions require specific justification -3. Check dependencies too - - allow the checking of dependencies diff --git a/tests/unsafe/fail_nested/src/main.rs b/tests/unsafe/fail_nested/src/main.rs index 3516df6..fab4e25 100644 --- a/tests/unsafe/fail_nested/src/main.rs +++ b/tests/unsafe/fail_nested/src/main.rs @@ -1,7 +1,8 @@ -// /// # Unsafe +/// # Unsafe /// * nn: ptr should be non null fn foo(ptr: *const i32) -> i32 { - unsafe { *ptr + *ptr } + let a = unsafe { *ptr }; + a + 2 } fn bar(ptr: *const i32) -> i32 { diff --git a/tests/unsafe/fail_nested/Cargo.lock b/tests/unsafe/fail_not_annotated/Cargo.lock similarity index 97% rename from tests/unsafe/fail_nested/Cargo.lock rename to tests/unsafe/fail_not_annotated/Cargo.lock index 9e11c79..4727049 100644 --- a/tests/unsafe/fail_nested/Cargo.lock +++ b/tests/unsafe/fail_not_annotated/Cargo.lock @@ -3,7 +3,7 @@ version = 4 [[package]] -name = "fail_nested" +name = "fail_not_annotated" version = "0.1.0" dependencies = [ "sniff-test-attrs", diff --git a/tests/unsafe/fail_nested/Cargo.toml b/tests/unsafe/fail_not_annotated/Cargo.toml similarity index 83% rename from tests/unsafe/fail_nested/Cargo.toml rename to tests/unsafe/fail_not_annotated/Cargo.toml index 9d99bb7..b0fdcf7 100644 --- a/tests/unsafe/fail_nested/Cargo.toml +++ b/tests/unsafe/fail_not_annotated/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "fail_nested" +name = "fail_not_annotated" version = "0.1.0" edition = "2024" diff --git a/tests/unsafe/fail_not_annotated/fail_not_annotated.snap b/tests/unsafe/fail_not_annotated/fail_not_annotated.snap new file mode 100644 index 0000000..b1ec081 --- /dev/null +++ b/tests/unsafe/fail_not_annotated/fail_not_annotated.snap @@ -0,0 +1,23 @@ +--- +source: tests/lib.rs +--- +exit_code = 101 +stdout = '' +stderr = ''' +error: function fail_not_annotated[801a]::foo has unsafe axioms, but is not annotated unsafe + --> src/main.rs:1:1 + | +1 | fn foo(ptr: *const i32) -> i32 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: raw pointer derefence here + --> src/main.rs:2:23 + | +2 | let a = unsafe { *ptr }; + | ^^^ + = help: this axiom has known requirements: + 1. the dereferenced pointer must be non-null + 2. the dereferenced pointer must be aligned + +error: could not compile `fail_not_annotated` (bin "fail_not_annotated") due to 1 previous error +''' diff --git a/tests/unsafe/fail_not_annotated/src/main.rs b/tests/unsafe/fail_not_annotated/src/main.rs new file mode 100644 index 0000000..603dcde --- /dev/null +++ b/tests/unsafe/fail_not_annotated/src/main.rs @@ -0,0 +1,17 @@ +fn foo(ptr: *const i32) -> i32 { + let a = unsafe { *ptr }; + a + 2 +} + +fn bar(ptr: *const i32) -> i32 { + foo(ptr) + unsafe { *ptr } +} + +#[sniff_test_attrs::check_unsafe] +fn main() { + let x = 1; + bar(&raw const x); +} + +// - instance safety for some traits +// - when it cant be done alwyas deny and just allow specific instances From 2b4a81d492f63e6e90c09db35dd12688d5070e5d Mon Sep 17 00:00:00 2001 From: AlexanderPortland Date: Thu, 23 Oct 2025 15:05:57 -0400 Subject: [PATCH 09/40] fix sniff-test macro expansion when building normally --- Cargo.lock | 1 + crates/sniff-test-attrs/src/lib.rs | 25 +++++++++++++++++++++---- crates/sniff-test/Cargo.toml | 1 + 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d3acd00..26d362f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -469,6 +469,7 @@ dependencies = [ "rustc_plugin", "rustc_utils", "serde", + "sniff-test-attrs", ] [[package]] diff --git a/crates/sniff-test-attrs/src/lib.rs b/crates/sniff-test-attrs/src/lib.rs index 45bcf2c..99238b6 100644 --- a/crates/sniff-test-attrs/src/lib.rs +++ b/crates/sniff-test-attrs/src/lib.rs @@ -3,13 +3,30 @@ use proc_macro::TokenStream; use quote::quote; +const TOOL_ENV_VAR: &str = "USING_SNIFF_TOOL"; + +#[proc_macro] +pub fn tool_env_var(_item: TokenStream) -> TokenStream { + format!("\"{TOOL_ENV_VAR}\"",).parse().unwrap() +} + #[proc_macro_attribute] pub fn check_unsafe(_attr: TokenStream, item: TokenStream) -> TokenStream { - let attrs = quote!( - #[sniff_tool::check_unsafe] - ); let mut t = TokenStream::new(); - t.extend(TokenStream::from(attrs)); + + // println!("expanding check unsafe!!"); + // let env_vars = ; + + // println!("vars are {env_vars:?}"); + + if let Ok(rust_flags) = std::env::var("RUSTFLAGS") { + if rust_flags.contains("-Zcrate-attr=register_tool(sniff_tool)") { + t.extend(TokenStream::from(quote!( + #[sniff_tool::check_unsafe] + ))); + } + } + t.extend(item); t } diff --git a/crates/sniff-test/Cargo.toml b/crates/sniff-test/Cargo.toml index 90a7f7e..38a5561 100644 --- a/crates/sniff-test/Cargo.toml +++ b/crates/sniff-test/Cargo.toml @@ -9,6 +9,7 @@ rustc_private = true [dependencies] rustc_plugin = "=0.14.0-nightly-2025-08-20" rustc_utils = "=0.14.0-nightly-2025-08-20" +sniff-test-attrs ={ path = "../sniff-test-attrs" } env_logger = { version = "0.10", default-features = false } clap = { version = "4.4", features = ["derive"] } serde = { version = "1", features = ["derive"] } From ea89266005f8dd223649d41cb3d0230d7e41a02a Mon Sep 17 00:00:00 2001 From: AlexanderPortland Date: Thu, 23 Oct 2025 16:24:56 -0400 Subject: [PATCH 10/40] rework annotation logic to use macros --- crates/sniff-test-attrs/src/lib.rs | 45 +++++++++++++----------------- 1 file changed, 20 insertions(+), 25 deletions(-) diff --git a/crates/sniff-test-attrs/src/lib.rs b/crates/sniff-test-attrs/src/lib.rs index 99238b6..2c3d054 100644 --- a/crates/sniff-test-attrs/src/lib.rs +++ b/crates/sniff-test-attrs/src/lib.rs @@ -3,30 +3,25 @@ use proc_macro::TokenStream; use quote::quote; -const TOOL_ENV_VAR: &str = "USING_SNIFF_TOOL"; - -#[proc_macro] -pub fn tool_env_var(_item: TokenStream) -> TokenStream { - format!("\"{TOOL_ENV_VAR}\"",).parse().unwrap() -} - -#[proc_macro_attribute] -pub fn check_unsafe(_attr: TokenStream, item: TokenStream) -> TokenStream { - let mut t = TokenStream::new(); - - // println!("expanding check unsafe!!"); - // let env_vars = ; - - // println!("vars are {env_vars:?}"); - - if let Ok(rust_flags) = std::env::var("RUSTFLAGS") { - if rust_flags.contains("-Zcrate-attr=register_tool(sniff_tool)") { - t.extend(TokenStream::from(quote!( - #[sniff_tool::check_unsafe] - ))); +macro_rules! define_sniff_tool_annotation { + ($name: ident) => { + #[proc_macro_attribute] + pub fn $name(_attr: TokenStream, item: TokenStream) -> TokenStream { + let mut t = TokenStream::new(); + + // If we're registering the sniff-test tool, add the actual attribute to check unsafe. + if let Ok(rust_flags) = std::env::var("RUSTFLAGS") + && rust_flags.contains("-Zcrate-attr=register_tool(sniff_tool)") + { + t.extend(TokenStream::from(quote!( + #[sniff_tool::$name] + ))); + } + + t.extend(item); + t } - } - - t.extend(item); - t + }; } + +define_sniff_tool_annotation!(check_unsafe); From 29f5c3a9a35b8d6878964ae51eeb661358139b90 Mon Sep 17 00:00:00 2001 From: AlexanderPortland Date: Thu, 23 Oct 2025 16:25:34 -0400 Subject: [PATCH 11/40] also detect calls to bad functions --- crates/sniff-test/src/axioms/mod.rs | 22 +- crates/sniff-test/src/axioms/panic.rs | 14 +- crates/sniff-test/src/axioms/safety.rs | 25 ++- crates/sniff-test/src/check/mod.rs | 170 ++++++++++++---- crates/sniff-test/src/lib.rs | 221 --------------------- crates/sniff-test/src/reachability/bad.rs | 49 ++++- crates/sniff-test/src/reachability/mod.rs | 4 +- crates/sniff-test/src/reachability/walk.rs | 122 ++++-------- 8 files changed, 262 insertions(+), 365 deletions(-) diff --git a/crates/sniff-test/src/axioms/mod.rs b/crates/sniff-test/src/axioms/mod.rs index e47dd23..50e8753 100644 --- a/crates/sniff-test/src/axioms/mod.rs +++ b/crates/sniff-test/src/axioms/mod.rs @@ -1,5 +1,6 @@ -use std::fmt::Display; +//! A module for detecting axiomatic program patterns +use crate::{annotations, reachability::LocallyReachable}; use rustc_hir::{ BodyId, intravisit::{self, Visitor}, @@ -9,6 +10,7 @@ use rustc_middle::{ ty::{TyCtxt, TypeckResults}, }; use rustc_span::source_map::Spanned; +use std::fmt::Display; mod panic; mod safety; @@ -16,8 +18,17 @@ mod safety; pub use panic::PanicFinder; pub use safety::SafetyFinder; +pub enum AxiomaticBadness { + Unconditional, + Conditional(Vec), +} + pub trait Axiom: Display { - fn known_requirements(&self) -> Option> { + /// The name for this kind of axiom (e.g. `I found a {name} axiom in your code`) + fn axiom_kind_name() -> &'static str; + + /// The requirements that this axiom has, if known. + fn known_requirements(&self) -> Option { None } } @@ -40,7 +51,12 @@ struct FinderWrapper<'tcx, T: AxiomFinder> { axioms: Vec>, } -pub fn find_axioms(finder: T, tcx: TyCtxt, body: BodyId) -> Vec> { +pub fn find_axioms( + finder: T, + tcx: TyCtxt, + locally_reachable: &LocallyReachable, +) -> Vec> { + let body = tcx.hir_body_owned_by(locally_reachable.reach).id(); let tychck = tcx.typeck_body(body); let mut finder = FinderWrapper { diff --git a/crates/sniff-test/src/axioms/panic.rs b/crates/sniff-test/src/axioms/panic.rs index 919982a..6d24a3d 100644 --- a/crates/sniff-test/src/axioms/panic.rs +++ b/crates/sniff-test/src/axioms/panic.rs @@ -4,7 +4,7 @@ use rustc_span::source_map::{Spanned, respan}; use std::fmt::Display; use super::Axiom; -use crate::axioms::AxiomFinder; +use crate::axioms::{AxiomFinder, AxiomaticBadness}; pub struct PanicFinder; @@ -13,7 +13,17 @@ pub enum PanicAxiom { ExplicitPanic, } -impl Axiom for PanicAxiom {} +impl Axiom for PanicAxiom { + fn axiom_kind_name() -> &'static str { + "panicking" + } + + fn known_requirements(&self) -> Option { + match self { + Self::ExplicitPanic => Some(AxiomaticBadness::Unconditional), + } + } +} impl Display for PanicAxiom { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { diff --git a/crates/sniff-test/src/axioms/safety.rs b/crates/sniff-test/src/axioms/safety.rs index a57842c..aa4bc69 100644 --- a/crates/sniff-test/src/axioms/safety.rs +++ b/crates/sniff-test/src/axioms/safety.rs @@ -3,13 +3,18 @@ use std::fmt::Display; use rustc_ast::UnOp; use rustc_hir::ExprKind; use rustc_middle::ty::TyCtxt; -use rustc_query_system::dep_graph::dep_node::DepNodeParams; use rustc_span::source_map::{Spanned, respan}; use rustc_type_ir::TyKind; use super::Axiom; -use crate::{annotations, axioms::AxiomFinder}; +use crate::{ + annotations, + axioms::{AxiomFinder, AxiomaticBadness}, +}; +/// A finder that looks for axioms that **could cause UB**. +/// +/// Currently just looks for raw pointer dereferences. pub struct SafetyFinder; #[derive(Debug, Clone)] @@ -18,12 +23,18 @@ pub enum SafetyAxiom { } impl Axiom for SafetyAxiom { - fn known_requirements(&self) -> Option> { + fn axiom_kind_name() -> &'static str { + "unsafe" + } + + fn known_requirements(&self) -> Option { match self { - Self::RawPtrDeref => Some(annotations::Requirement::construct([ - ("ptr-non-null", "the dereferenced pointer must be non-null"), - ("ptr-aligned", "the dereferenced pointer must be aligned"), - ])), + Self::RawPtrDeref => Some(AxiomaticBadness::Conditional( + annotations::Requirement::construct([ + ("ptr-non-null", "the dereferenced pointer must be non-null"), + ("ptr-aligned", "the dereferenced pointer must be aligned"), + ]), + )), } } } diff --git a/crates/sniff-test/src/check/mod.rs b/crates/sniff-test/src/check/mod.rs index ac0cff0..8f0f6af 100644 --- a/crates/sniff-test/src/check/mod.rs +++ b/crates/sniff-test/src/check/mod.rs @@ -1,62 +1,131 @@ use itertools::Itertools; -use rustc_errors::DiagCtxtHandle; +use rustc_errors::{Diag, DiagCtxtHandle}; +use rustc_hir::def_id::DefId; use rustc_middle::ty::TyCtxt; -use rustc_span::{ErrorGuaranteed, Span, SpanData, source_map::Spanned}; +use rustc_span::{ErrorGuaranteed, source_map::Spanned}; use crate::{ annotations::{self, Annotation}, - axioms::{self, Axiom}, - reachability::{self, LocalReachable}, + axioms::{self, Axiom, AxiomFinder, AxiomaticBadness}, + reachability::{self, CallsToBad, LocallyReachable}, + utils::SniffTestDiagnostic, }; /// Checks that all local functions in the crate are properly annotated. pub fn check_properly_annotated(tcx: TyCtxt) -> Result<(), ErrorGuaranteed> { let mut res = Ok(()); - let entry = reachability::annotated_local_entry_points(tcx); - - let entry = entry.collect::>(); + let entry = reachability::annotated_local_entry_points(tcx).collect::>(); println!("entry is {entry:?}"); - let reachable = reachability::local_reachable_from(tcx, entry).collect::>(); + let reachable = reachability::locally_reachable_from(tcx, entry).collect::>(); println!("reachable is {:?}", reachable); + // For all reachable local function definitions, ensure their axioms align with their annotations. for reachable in reachable.iter().cloned() { - let name = &tcx.def_path_debug_str(reachable.reach.to_def_id()); - let axioms = axioms::find_axioms( - axioms::SafetyFinder, - tcx, - tcx.hir_body_owned_by(reachable.reach).id(), - ); + let axioms = axioms::find_axioms(axioms::SafetyFinder, tcx, &reachable); + + let bad_calls = reachability::find_bad_calls(tcx, &reachable) + .map_err(|parsing_error| parsing_error.diag(tcx.dcx()).emit())?; let annotations = annotations::Requirement::try_parse(tcx, reachable.reach.to_def_id()); - if !axioms.is_empty() && annotations.is_none() { - res = Err(needs_annotation(tcx.dcx(), tcx, reachable, axioms)); - // println!("err from {name}"); + // For now, just check that all functions with axioms have some annotations. + if annotations.is_none() && (!axioms.is_empty() || !bad_calls.is_empty()) { + res = Err(needs_annotation( + tcx.dcx(), + tcx, + reachable, + FunctionIssues(axioms, bad_calls), + )); } } res } +struct FunctionIssues(Vec>, Vec); + +pub fn check_function( + tcx: TyCtxt, + fn_def: LocallyReachable, +) -> Result<(), FunctionIssues> { + // Check that this function: + // a) contains no axiomatic bad things. + // b) contains no calls to bad functions. + + todo!() +} + fn needs_annotation( dcx: DiagCtxtHandle, tcx: TyCtxt, - reachable: LocalReachable, - bc_of_axioms: Vec>, + reachable: LocallyReachable, + bc_of_isses: FunctionIssues, ) -> ErrorGuaranteed { let def_span = tcx.def_span(reachable.reach); let fn_name = tcx.def_path_str(reachable.reach.to_def_id()); - let mut diag = dcx.struct_span_err( - def_span, - format!("function {fn_name} has unsafe axioms, but is not annotated unsafe"), + + let mut diag = dcx.struct_span_err(def_span, summary::summary_string(&fn_name, &bc_of_isses)); + + diag = diag.with_note(reachability_str(&fn_name, tcx, reachable)); + + for axiom in bc_of_isses.0 { + diag = diag_handle_axiom(diag, axiom); + } + + for bad_call in bc_of_isses.1 { + diag = diag_handle_bad_call(diag, tcx, bad_call); + } + + diag.emit() +} + +fn diag_handle_bad_call<'d>(mut diag: Diag<'d>, tcx: TyCtxt, bad_call: CallsToBad) -> Diag<'d> { + let (num, s) = if bad_call.from_spans.len() > 1 { + (format!("{} ", bad_call.from_spans.len()), "s") + } else { + ("".to_string(), "") + }; + let call_to = tcx.def_path_str(bad_call.def_id); + diag = diag.with_span_note( + bad_call.from_spans, + format!("{num}call{s} to {call_to} here"), ); + diag +} + +fn diag_handle_axiom(mut diag: Diag<'_>, axiom: Spanned) -> Diag<'_> { + diag = diag.with_span_note(axiom.span, format!("{} here", axiom.node)); + match axiom.node.known_requirements() { + None => (), + Some(AxiomaticBadness::Conditional(known_reqs)) => { + // We know the conditional requirements, so display them + let intro_string = "this axiom has known requirements:".to_string(); + + let known_req_strs = known_reqs + .into_iter() + .enumerate() + .map(|(i, req)| format!("\t{}. {}", i + 1, req.description())); + + diag = diag.with_help( + std::iter::once(intro_string) + .chain(known_req_strs) + .join("\n"), + ); + } + Some(AxiomaticBadness::Unconditional) => todo!(), + } + + diag +} + +fn reachability_str(fn_name: &str, tcx: TyCtxt, reachable: LocallyReachable) -> String { let reachability_str = reachable - .from + .through .iter() .map(|def| { let name = tcx.def_path_str(def.0); @@ -70,25 +139,48 @@ fn needs_annotation( .chain(std::iter::once(format!("*{fn_name}*"))) .join(" -> "); - diag = diag.with_help(format!("(reachable from [{reachability_str}])")); + format!("reachable from [{reachability_str}]") +} - for axiom in bc_of_axioms { - diag = diag.with_span_note(axiom.span, format!("{} here", axiom.node)); - if let Some(known_reqs) = axiom.node.known_requirements() { - let intro_string = "this axiom has known requirements:".to_string(); +mod summary { + use itertools::Itertools; + use rustc_span::source_map::Spanned; - let known_req_strs = known_reqs - .into_iter() - .enumerate() - .map(|(i, req)| format!("\t{}. {}", i + 1, req.description())); + use crate::axioms::Axiom; + use crate::check::FunctionIssues; + use crate::reachability::CallsToBad; - diag = diag.with_help( - std::iter::once(intro_string) - .chain(known_req_strs) - .join("\n"), - ); - } + pub fn summary_string(fn_name: &str, issues: &FunctionIssues) -> String { + let axiom_summary = axiom_summary(&issues.0); + let call_summary = call_summary::(&issues.1); + let issue_summary = [axiom_summary, call_summary] + .into_iter() + .flatten() + .join(" and "); + + let kind = A::axiom_kind_name(); + format!("function {fn_name} directly contains {issue_summary}, but is not annotated {kind}") } - diag.emit() + fn call_summary(calls: &[CallsToBad]) -> Option { + let count: usize = calls.iter().map(|call| call.from_spans.len()).sum(); + let kind = A::axiom_kind_name(); + let s = match count { + 1 => "", + x if x > 1 => "s", + _ => return None, + }; + Some(format!("{count} call{s} to {kind} functions")) + } + + fn axiom_summary(axioms: &[Spanned]) -> Option { + let count = axioms.len(); + let kind = A::axiom_kind_name(); + let s = match count { + 1 => "", + x if x > 1 => "s", + _ => return None, + }; + Some(format!("{count} {kind} axiom{s}")) + } } diff --git a/crates/sniff-test/src/lib.rs b/crates/sniff-test/src/lib.rs index d514059..276328a 100644 --- a/crates/sniff-test/src/lib.rs +++ b/crates/sniff-test/src/lib.rs @@ -125,224 +125,3 @@ impl rustc_driver::Callbacks for PrintAllItemsCallbacks { rustc_driver::Compilation::Continue } } - -fn all_local_fn_defs() -> Box<[FnDef]> { - rustc_public::all_local_items() - .into_iter() - .filter_map(|item| match item.ty().kind().fn_def() { - Some((def, _other)) => Some(def), - _ => None, - }) - .collect::>() -} - -fn sniff_test_analysis(tcx: TyCtxt) -> impl FnOnce() -> anyhow::Result<()> { - move || { - let all_fn_defs = all_local_fn_defs(); - - // 1. Find all 'bad' functions. Make sure they line up - let bad = reachability::filter_bad_functions(tcx, &all_fn_defs).unwrap(); - print!("bad {bad:?}"); - - // 2a. Find entry points - // let entry_points = reachability::filter_entry_points(tcx, &all_fn_defs); - // println!("have entry points {entry_points:?}"); - - // 2b. Walk from those entry points to ensure proper labels - // let res = reachability::walk_from_entry_points(tcx, &entry_points, bad).unwrap(); - Ok(()) - } -} - -type RequirementInfo = HashMap>; -/// Parses all functions that pass the given [`should_analyze_item`] predicate, -/// returning the [`Requirement`]s for those that have them. -fn requirement_pass(tcx: TyCtxt) -> impl FnOnce() -> Result { - move || { - // let entry_points = reachability::filter_entry_points(tcx, &rustc_public::all_local_items()); - // println!("entry points are {:?}", entry_points); - todo!(); - // rustc_public::all_local_items() - // .into_iter() - // // filter by items we should analyze - // .filter_map(|crate_def| should_analyze_item(crate_def, tcx)) - // // try to analyze all `FnDef`s, but some will return `None` as they have no annotations... - // .filter_map(|def| { - // let internal_def = rustc_public::rustc_internal::internal(tcx, def.def_id()); - // Some( - // Requirement::try_parse(tcx, internal_def)? - // .map(|reqs| (internal_def, reqs)) - // .map_err(|err| err.emit(tcx.dcx())), - // ) - // }) - // // collect into a hash map - // .collect::, ErrorGuaranteed>>() - } -} - -type JustificationInfo = HashMap>; - -/// Records the [`Justification`]s given on all function calls to `fns_to_track`. -fn justification_pass( - tcx: TyCtxt, - fns_to_track: &[DefId], -) -> impl FnOnce() -> Result { - move || { - println!("gonna visit... w/ fns to track {fns_to_track:?}"); - let mut visitor = FnCallVisitor::new(tcx, fns_to_track); - tcx.hir_visit_all_item_likes_in_crate(&mut visitor); - visitor.finish() - } -} - -struct FnCallVisitor<'tcx, 'a> { - tcx: TyCtxt<'tcx>, - fns_to_track: &'a [DefId], - results: HashMap, ErrorGuaranteed>>, -} - -impl<'tcx, 'a> FnCallVisitor<'tcx, 'a> { - fn new(tcx: TyCtxt<'tcx>, fns_to_track: &'a [DefId]) -> Self { - Self { - tcx, - fns_to_track, - results: HashMap::default(), - } - } - - /// Checks if we should try to analyze a function call to a given `DefId`. - fn should_analyze_fn_call_to(&self, def_id: rustc_span::def_id::DefId) -> bool { - self.fns_to_track.contains(&def_id) - } - - /// Try to get the annotations from all parent code blocks for a given [`Expr`]. - /// - /// This is used to ensure code like the following will work, even if - /// the annotation isn't on the exact HIR node of the function call: - /// ``` - /// # let foo = |ptr: &i32| *ptr; - /// # let val = 42; - /// # let ptr: &i32 = &val; - /// /// Safety: - /// /// - non-null: the ptr is non null - /// unsafe { foo(ptr); } - /// ``` - fn try_get_from_parent_blocks( - &self, - ex: &'tcx rustc_hir::Expr<'tcx>, - ) -> Option, ParsingError<'_>>> { - // TODO: stop looking once we reach a single code block, to ensure we don't - self.tcx - .hir_parent_iter(ex.hir_id) - .filter_map(|(_id, node)| { - if let Node::Expr(expr) = node - && let ExprKind::Block(..) = expr.kind - { - Some(expr) - } else { - None - } - }) - .find_map(|expr| Justification::try_parse(self.tcx, expr)) - } - - /// Consume this visitor and return the stored mapping between function call sites - /// and the justifications behind them. - fn finish(self) -> Result>, ErrorGuaranteed> { - self.results - .into_iter() - .map(|(id, res)| res.map(|res| (id, res))) - .collect() - } -} - -impl<'tcx> rustc_hir::intravisit::Visitor<'tcx> for FnCallVisitor<'tcx, '_> { - // Have to set this to ensure we visit the expressions INSIDE function bodies. - type NestedFilter = rustc_middle::hir::nested_filter::OnlyBodies; - - fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt { - self.tcx - } - - fn visit_expr(&mut self, ex: &'tcx rustc_hir::Expr<'tcx>) -> Self::Result { - if let rustc_hir::ExprKind::Call(f, _args) = ex.kind - && let rustc_hir::ExprKind::Path(rustc_hir::QPath::Resolved(_self, path)) = f.kind - { - let def_id = path.res.def_id(); - - if self.should_analyze_fn_call_to(def_id) { - let annotation_res = Justification::try_parse(self.tcx, ex).unwrap_or_else(|| { - // try getting from parents - self.try_get_from_parent_blocks(ex).map_or_else( - || { - // if that fails, just return the original issue - Justification::parse(self.tcx, ex) - }, - // update the span if we found it from a parent, - |found| { - found.map_err(|mut err| { - err.update_span(ex.span); - err - }) - }, - ) - }); - - let res = annotation_res.map_err(|err| err.emit(self.tcx.dcx())); - - self.results.insert(ex.hir_id, res); - } - } - - intravisit::walk_expr(self, ex); - } -} - -fn should_analyze_item( - item: rustc_public::CrateItem, - _tcx: TyCtxt, -) -> Option { - if let Some((def, _generics)) = item.ty().kind().fn_def() - // && def.fn_sig().value.safety == Safety::Unsafe - { - Some(def) - } else { - None - } -} - -// The core of our analysis. Right now it just prints out a description of each item. -// I recommend reading the Rustc Development Guide to better understand which compiler APIs -// are relevant to whatever task you have. -#[allow(dead_code)] -fn print_all_items(tcx: TyCtxt, args: PrintAllItemsPluginArgs) { - tcx.hir_visit_all_item_likes_in_crate(&mut PrintVisitor { args, tcx }); -} - -struct PrintVisitor<'tcx> { - args: PrintAllItemsPluginArgs, - tcx: TyCtxt<'tcx>, -} - -impl<'tcx> Visitor<'tcx> for PrintVisitor<'tcx> { - #[allow(clippy::semicolon_if_nothing_returned)] - fn visit_item(&mut self, item: &'tcx Item<'tcx>) -> Self::Result { - let mut msg = match item.kind.ident() { - Some(ident) => format!( - "There is an item \"{}\" of type \"{}\"", - ident, - self.tcx.def_descr(item.owner_id.to_def_id()) - ), - None => format!( - "There is an item of type \"{}\"", - self.tcx.def_descr(item.owner_id.to_def_id()) - ), - }; - if self.args.allcaps { - msg = msg.to_uppercase(); - } - println!("{msg}"); - - intravisit::walk_item(self, item) - } -} diff --git a/crates/sniff-test/src/reachability/bad.rs b/crates/sniff-test/src/reachability/bad.rs index b1ce6a8..8c25487 100644 --- a/crates/sniff-test/src/reachability/bad.rs +++ b/crates/sniff-test/src/reachability/bad.rs @@ -1,14 +1,50 @@ //! Finds the 'bad' functions that should be annotated -use crate::annotations::{Annotation, Requirement}; +use crate::annotations::{self, Annotation, ParsingError, Requirement}; +use crate::reachability::LocallyReachable; use std::collections::HashMap; use crate::utils::MultiEmittable; - +use rustc_hir::def_id::DefId; use rustc_middle::ty::TyCtxt; use rustc_public::mir::Safety; use rustc_public::ty::FnDef; -use rustc_span::ErrorGuaranteed; +use rustc_span::{ErrorGuaranteed, Span}; + +pub struct CallsToBad { + pub def_id: DefId, + pub requirements: Vec, + pub from_spans: Vec, +} + +fn is_call_bad<'tcx>( + tcx: TyCtxt<'tcx>, +) -> impl Fn((&DefId, &Vec)) -> Option>> { + move |(to_def_id, from_spans)| { + let requirements = match Requirement::try_parse(tcx, to_def_id)? { + Err(e) => return Some(Err(e)), + Ok(req) => req, + }; + + // match + Some(Ok(CallsToBad { + def_id: *to_def_id, + requirements, + from_spans: from_spans.to_vec(), + })) + } +} + +pub fn find_bad_calls<'tcx>( + tcx: TyCtxt<'tcx>, + locally_reachable: &LocallyReachable, +) -> Result, ParsingError<'tcx>> { + locally_reachable + .calls_to + .iter() + .filter_map(is_call_bad(tcx)) + .collect::, ParsingError>>() +} pub fn filter_bad_functions( tcx: TyCtxt, @@ -33,9 +69,10 @@ pub fn filter_bad_functions( .filter(|(fn_def, _reason)| !annotated_bad.contains_key(fn_def)) .collect::>(); - assert!(bad_but_missed.is_empty(), - "some functions should be annotated for the following reasons, but are not {bad_but_missed:?}" - ); + assert!( + bad_but_missed.is_empty(), + "some functions should be annotated for the following reasons, but are not {bad_but_missed:?}" + ); Ok(annotated_bad) } diff --git a/crates/sniff-test/src/reachability/mod.rs b/crates/sniff-test/src/reachability/mod.rs index 1ee4dfa..05616f8 100644 --- a/crates/sniff-test/src/reachability/mod.rs +++ b/crates/sniff-test/src/reachability/mod.rs @@ -4,6 +4,6 @@ mod entry; mod err; mod walk; -pub use bad::filter_bad_functions; +pub use bad::{CallsToBad, filter_bad_functions, find_bad_calls}; pub use entry::annotated_local_entry_points; -pub use walk::{LocalReachable, local_reachable_from}; +pub use walk::{LocallyReachable, locally_reachable_from}; diff --git a/crates/sniff-test/src/reachability/walk.rs b/crates/sniff-test/src/reachability/walk.rs index 7c06ee9..7332384 100644 --- a/crates/sniff-test/src/reachability/walk.rs +++ b/crates/sniff-test/src/reachability/walk.rs @@ -4,47 +4,56 @@ use crate::rustc_middle::mir::visit::Visitor; use rustc_hir::def_id::{self as internal, DefId, LocalDefId}; -use rustc_hir::{ExprKind, Node, intravisit}; use rustc_middle::mir::{ConstOperand, Operand, TerminatorKind}; use rustc_middle::ty::{TyCtxt, TyKind}; -use rustc_public::ty::FnDef; use rustc_span::Span; -use rustc_span::sym::c; -use std::collections::{HashMap, HashSet}; - -use crate::{annotations::Requirement, reachability::err::ConsistencyError}; +use std::collections::{HashMap, HashSet, VecDeque}; #[derive(Debug, Clone)] -pub struct LocalReachable { +pub struct LocallyReachable { + /// The item that can be reached. pub reach: LocalDefId, - pub from: Vec<(LocalDefId, Span)>, + /// The path of calls between items through which you can reach this item. + pub through: Vec<(LocalDefId, Span)>, + /// The functions (not necessarily local) that this one calls to. + pub calls_to: HashMap>, } -impl LocalReachable { - fn goes_to(&self, def_id: LocalDefId, span: Span) -> Self { - LocalReachable { +impl LocallyReachable { + /// Say that this locally reachable item can go to another `def_id` through a call at a given `span`. + fn extended_to(&self, def_id: LocalDefId, span: Span) -> Self { + LocallyReachable { reach: def_id, - from: self - .from + through: self + .through .iter() .cloned() .chain(std::iter::once((self.reach, span))) .collect(), + calls_to: HashMap::new(), } } + + fn calls_to(&mut self, def_id: &DefId, span: Span) { + self.calls_to.entry(*def_id).or_default().push(span); + } } -pub fn local_reachable_from( +/// Get an iterator over all locally reachable function definitions from the given `entry_points`. +pub fn locally_reachable_from( tcx: TyCtxt, entry_points: impl IntoIterator, -) -> impl Iterator { +) -> impl Iterator { CallGraphVisitor::new(tcx, entry_points.into_iter()).all_local_reachable() } struct CallGraphVisitor<'tcx> { tcx: TyCtxt<'tcx>, - to_visit: Vec, - reachable: HashMap, + /// Queue of reachable items we want to visit. + /// + /// This lets us to BFS to get the shortest path to each item. + to_visit: VecDeque, + reachable: HashMap, } impl<'tcx> CallGraphVisitor<'tcx> { @@ -52,21 +61,21 @@ impl<'tcx> CallGraphVisitor<'tcx> { Self { tcx, to_visit: entry_points - .map(|reach| LocalReachable { + .map(|reach| LocallyReachable { reach, - from: Vec::new(), + through: Vec::new(), + calls_to: HashMap::new(), }) .collect(), reachable: HashMap::new(), } } - fn all_local_reachable(mut self) -> impl Iterator { - while let Some(d) = self.to_visit.pop() { + fn all_local_reachable(mut self) -> impl Iterator { + while let Some(mut d) = self.to_visit.pop_front() { if !self.reachable.contains_key(&d.reach) { let body = self.tcx.optimized_mir(d.reach); - println!("[!] visit body {:?}", d.reach); - let mut visitor = BodyVisitor(self.tcx, &mut self.to_visit, &d); + let mut visitor = BodyVisitor(self.tcx, &mut self.to_visit, &mut d); visitor.visit_body(body); self.reachable.insert(d.reach, d); } @@ -77,8 +86,8 @@ impl<'tcx> CallGraphVisitor<'tcx> { struct BodyVisitor<'tcx, 'm>( TyCtxt<'tcx>, - &'m mut Vec, - &'m LocalReachable, + &'m mut VecDeque, + &'m mut LocallyReachable, ); impl<'tcx> rustc_middle::mir::visit::Visitor<'tcx> for BodyVisitor<'tcx, '_> { @@ -87,7 +96,6 @@ impl<'tcx> rustc_middle::mir::visit::Visitor<'tcx> for BodyVisitor<'tcx, '_> { terminator: &rustc_middle::mir::Terminator<'tcx>, location: rustc_middle::mir::Location, ) { - println!("terminator {:?}", terminator); if let TerminatorKind::Call { func, call_source, @@ -97,12 +105,11 @@ impl<'tcx> rustc_middle::mir::visit::Visitor<'tcx> for BodyVisitor<'tcx, '_> { { if let Operand::Constant(box co) = func { if let TyKind::FnDef(def_id, _substs) = co.const_.ty().kind() { - println!("call to {def_id:?}"); - + self.2.calls_to(def_id, terminator.source_info.span); if let Some(local_def) = def_id.as_local() { - println!("and it's local!"); + // Doing BFS here to ensure we get the shortest path possible to all reachable items. self.1 - .push(self.2.goes_to(local_def, terminator.source_info.span)); + .push_back(self.2.extended_to(local_def, terminator.source_info.span)); } } } @@ -111,58 +118,3 @@ impl<'tcx> rustc_middle::mir::visit::Visitor<'tcx> for BodyVisitor<'tcx, '_> { self.super_terminator(terminator, location); } } - -// pub fn walk_from_entry_points( -// tcx: TyCtxt, -// entry_points: &[FnDef], -// requirements: HashMap>, -// ) -> Result<(), ConsistencyError> { -// let entry_point_defs = entry_points -// .iter() -// .map(|fn_def| rustc_public::rustc_internal::internal(tcx, fn_def.0)) -// .collect::>(); - -// CallGraphVisitor::new(tcx, requirements).visit_from_entrypoints(&entry_point_defs) -// } - -// struct CallGraphVisitor<'tcx> { -// tcx: TyCtxt<'tcx>, -// requirements: HashMap>, -// } - -// type CallGraphResult = (); -// impl<'tcx> CallGraphVisitor<'tcx> { -// pub fn new(tcx: TyCtxt<'tcx>, requirements: HashMap>) -> Self { -// Self { tcx, requirements } -// } - -// pub fn visit_from_entrypoints( -// mut self, -// entry_points: &[internal::DefId], -// ) -> Result { -// let to_visit = self -// .tcx -// .hir_crate_items(()) -// .definitions() -// .filter(|a| entry_points.contains(&a.to_def_id())) -// .collect::>(); - -// for i in self.tcx.hir_crate_items(()).free_items() { -// if entry_points.contains(&i.owner_id.to_def_id()) { -// println!("going to i {i:?}"); -// } -// } - -// Ok(()) -// } -// } - -// impl<'tcx> rustc_hir::intravisit::Visitor<'tcx> for CallGraphVisitor<'tcx> { -// type NestedFilter = rustc_middle::hir::nested_filter::OnlyBodies; - -// fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt { -// self.tcx -// } - -// fn visit_expr(&mut self, ex: &'tcx rustc_hir::Expr<'tcx>) -> Self::Result {} -// } From 11b9af01ed151beca4c077d1abce0f27be5702f9 Mon Sep 17 00:00:00 2001 From: AlexanderPortland Date: Thu, 23 Oct 2025 16:33:49 -0400 Subject: [PATCH 12/40] make clippy happy --- crates/sniff-test/src/axioms/mod.rs | 10 ++---- crates/sniff-test/src/axioms/panic.rs | 2 +- crates/sniff-test/src/axioms/safety.rs | 2 +- crates/sniff-test/src/check/mod.rs | 30 +++++++++--------- crates/sniff-test/src/lib.rs | 23 ++++++-------- crates/sniff-test/src/reachability/bad.rs | 2 +- crates/sniff-test/src/reachability/entry.rs | 3 -- crates/sniff-test/src/reachability/mod.rs | 2 +- crates/sniff-test/src/reachability/walk.rs | 35 +++++++++------------ crates/sniff-test/src/utils/err.rs | 4 +-- tests/unsafe/fail_not_annotated/src/main.rs | 14 ++++++++- 11 files changed, 61 insertions(+), 66 deletions(-) diff --git a/crates/sniff-test/src/axioms/mod.rs b/crates/sniff-test/src/axioms/mod.rs index 50e8753..ef0f326 100644 --- a/crates/sniff-test/src/axioms/mod.rs +++ b/crates/sniff-test/src/axioms/mod.rs @@ -1,10 +1,7 @@ //! A module for detecting axiomatic program patterns use crate::{annotations, reachability::LocallyReachable}; -use rustc_hir::{ - BodyId, - intravisit::{self, Visitor}, -}; +use rustc_hir::intravisit::{self, Visitor}; use rustc_middle::{ hir::nested_filter, ty::{TyCtxt, TypeckResults}, @@ -15,7 +12,6 @@ use std::fmt::Display; mod panic; mod safety; -pub use panic::PanicFinder; pub use safety::SafetyFinder; pub enum AxiomaticBadness { @@ -36,7 +32,7 @@ pub trait Axiom: Display { pub trait AxiomFinder { type Axiom: Axiom; - fn from_expr( + fn find_in_expr( &mut self, tcx: TyCtxt, tyck: &TypeckResults, @@ -82,7 +78,7 @@ impl<'tcx, T: AxiomFinder> Visitor<'tcx> for FinderWrapper<'tcx, T> { #[allow(clippy::semicolon_if_nothing_returned)] fn visit_expr(&mut self, ex: &'tcx rustc_hir::Expr<'tcx>) -> Self::Result { self.axioms - .extend(self.finder.from_expr(self.tcx, self.tychck, ex)); + .extend(self.finder.find_in_expr(self.tcx, self.tychck, ex)); intravisit::walk_expr(self, ex) } diff --git a/crates/sniff-test/src/axioms/panic.rs b/crates/sniff-test/src/axioms/panic.rs index 6d24a3d..0e635c2 100644 --- a/crates/sniff-test/src/axioms/panic.rs +++ b/crates/sniff-test/src/axioms/panic.rs @@ -36,7 +36,7 @@ impl Display for PanicAxiom { impl AxiomFinder for PanicFinder { type Axiom = PanicAxiom; - fn from_expr( + fn find_in_expr( &mut self, tcx: TyCtxt, tyck: &rustc_middle::ty::TypeckResults, diff --git a/crates/sniff-test/src/axioms/safety.rs b/crates/sniff-test/src/axioms/safety.rs index aa4bc69..8bdcf62 100644 --- a/crates/sniff-test/src/axioms/safety.rs +++ b/crates/sniff-test/src/axioms/safety.rs @@ -50,7 +50,7 @@ impl Display for SafetyAxiom { impl AxiomFinder for SafetyFinder { type Axiom = SafetyAxiom; - fn from_expr( + fn find_in_expr( &mut self, _tcx: TyCtxt, tyck: &rustc_middle::ty::TypeckResults, diff --git a/crates/sniff-test/src/check/mod.rs b/crates/sniff-test/src/check/mod.rs index 8f0f6af..49483d0 100644 --- a/crates/sniff-test/src/check/mod.rs +++ b/crates/sniff-test/src/check/mod.rs @@ -1,6 +1,5 @@ use itertools::Itertools; use rustc_errors::{Diag, DiagCtxtHandle}; -use rustc_hir::def_id::DefId; use rustc_middle::ty::TyCtxt; use rustc_span::{ErrorGuaranteed, source_map::Spanned}; @@ -21,7 +20,7 @@ pub fn check_properly_annotated(tcx: TyCtxt) -> Result<(), ErrorGuaranteed> { let reachable = reachability::locally_reachable_from(tcx, entry).collect::>(); - println!("reachable is {:?}", reachable); + println!("reachable is {reachable:?}"); // For all reachable local function definitions, ensure their axioms align with their annotations. for reachable in reachable.iter().cloned() { @@ -37,7 +36,7 @@ pub fn check_properly_annotated(tcx: TyCtxt) -> Result<(), ErrorGuaranteed> { res = Err(needs_annotation( tcx.dcx(), tcx, - reachable, + &reachable, FunctionIssues(axioms, bad_calls), )); } @@ -48,21 +47,21 @@ pub fn check_properly_annotated(tcx: TyCtxt) -> Result<(), ErrorGuaranteed> { struct FunctionIssues(Vec>, Vec); -pub fn check_function( - tcx: TyCtxt, - fn_def: LocallyReachable, -) -> Result<(), FunctionIssues> { - // Check that this function: - // a) contains no axiomatic bad things. - // b) contains no calls to bad functions. +// pub fn check_function( +// tcx: TyCtxt, +// fn_def: LocallyReachable, +// ) -> Result<(), FunctionIssues> { +// // Check that this function: +// // a) contains no axiomatic bad things. +// // b) contains no calls to bad functions. - todo!() -} +// todo!() +// } fn needs_annotation( dcx: DiagCtxtHandle, tcx: TyCtxt, - reachable: LocallyReachable, + reachable: &LocallyReachable, bc_of_isses: FunctionIssues, ) -> ErrorGuaranteed { let def_span = tcx.def_span(reachable.reach); @@ -87,7 +86,7 @@ fn diag_handle_bad_call<'d>(mut diag: Diag<'d>, tcx: TyCtxt, bad_call: CallsToBa let (num, s) = if bad_call.from_spans.len() > 1 { (format!("{} ", bad_call.from_spans.len()), "s") } else { - ("".to_string(), "") + (String::new(), "") }; let call_to = tcx.def_path_str(bad_call.def_id); diag = diag.with_span_note( @@ -98,6 +97,7 @@ fn diag_handle_bad_call<'d>(mut diag: Diag<'d>, tcx: TyCtxt, bad_call: CallsToBa diag } +#[allow(clippy::needless_pass_by_value)] fn diag_handle_axiom(mut diag: Diag<'_>, axiom: Spanned) -> Diag<'_> { diag = diag.with_span_note(axiom.span, format!("{} here", axiom.node)); match axiom.node.known_requirements() { @@ -123,7 +123,7 @@ fn diag_handle_axiom(mut diag: Diag<'_>, axiom: Spanned) -> Diag<'_ diag } -fn reachability_str(fn_name: &str, tcx: TyCtxt, reachable: LocallyReachable) -> String { +fn reachability_str(fn_name: &str, tcx: TyCtxt, reachable: &LocallyReachable) -> String { let reachability_str = reachable .through .iter() diff --git a/crates/sniff-test/src/lib.rs b/crates/sniff-test/src/lib.rs index 276328a..0d032b0 100644 --- a/crates/sniff-test/src/lib.rs +++ b/crates/sniff-test/src/lib.rs @@ -3,6 +3,14 @@ #![feature(rustc_private)] #![feature(box_patterns)] #![cfg_attr(test, feature(assert_matches))] +#![deny(warnings)] +#![warn(clippy::pedantic)] +#![allow( + unused, + clippy::must_use_candidate, + clippy::missing_panics_doc, // TODO: should remove this, kinda ironic for us to be using it... + clippy::missing_errors_doc +)] extern crate lazy_static; extern crate rustc_ast; @@ -23,25 +31,14 @@ mod check; mod reachability; pub mod utils; -use std::{borrow::Cow, collections::HashMap, env, process::Command}; +use std::{borrow::Cow, env, process::Command}; use clap::Parser; -use rustc_hir::{ - ExprKind, HirId, Item, Node, - def_id::DefId, - intravisit::{self, Visitor}, -}; use rustc_middle::ty::TyCtxt; use rustc_plugin::{CrateFilter, RustcPlugin, RustcPluginArgs, Utf8Path}; -use rustc_public::ty::FnDef; -use rustc_span::ErrorGuaranteed; use serde::{Deserialize, Serialize}; -use crate::{ - annotations::{Annotation, Justification, ParsingError, Requirement}, - check::check_properly_annotated, - utils::SniffTestDiagnostic, -}; +use crate::check::check_properly_annotated; // This struct is the plugin provided to the rustc_plugin framework, // and it must be exported for use by the CLI/driver binaries. diff --git a/crates/sniff-test/src/reachability/bad.rs b/crates/sniff-test/src/reachability/bad.rs index 8c25487..2dc16c5 100644 --- a/crates/sniff-test/src/reachability/bad.rs +++ b/crates/sniff-test/src/reachability/bad.rs @@ -30,7 +30,7 @@ fn is_call_bad<'tcx>( Some(Ok(CallsToBad { def_id: *to_def_id, requirements, - from_spans: from_spans.to_vec(), + from_spans: from_spans.clone(), })) } } diff --git a/crates/sniff-test/src/reachability/entry.rs b/crates/sniff-test/src/reachability/entry.rs index 7a79367..98f7187 100644 --- a/crates/sniff-test/src/reachability/entry.rs +++ b/crates/sniff-test/src/reachability/entry.rs @@ -1,8 +1,6 @@ -use std::collections::HashSet; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::ty::TyCtxt; -use rustc_public::ty::FnDef; use crate::reachability::attr::{self, SniffToolAttr}; @@ -17,7 +15,6 @@ use crate::reachability::attr::{self, SniffToolAttr}; pub fn annotated_local_entry_points(tcx: TyCtxt) -> impl Iterator { tcx.hir_body_owners() .filter(move |item| is_entry_point(tcx, item.to_def_id())) - .map(|item| item) } fn is_entry_point(tcx: TyCtxt, item: DefId) -> bool { diff --git a/crates/sniff-test/src/reachability/mod.rs b/crates/sniff-test/src/reachability/mod.rs index 05616f8..66aa054 100644 --- a/crates/sniff-test/src/reachability/mod.rs +++ b/crates/sniff-test/src/reachability/mod.rs @@ -4,6 +4,6 @@ mod entry; mod err; mod walk; -pub use bad::{CallsToBad, filter_bad_functions, find_bad_calls}; +pub use bad::{CallsToBad, find_bad_calls}; pub use entry::annotated_local_entry_points; pub use walk::{LocallyReachable, locally_reachable_from}; diff --git a/crates/sniff-test/src/reachability/walk.rs b/crates/sniff-test/src/reachability/walk.rs index 7332384..696e822 100644 --- a/crates/sniff-test/src/reachability/walk.rs +++ b/crates/sniff-test/src/reachability/walk.rs @@ -3,11 +3,11 @@ //! use crate::rustc_middle::mir::visit::Visitor; -use rustc_hir::def_id::{self as internal, DefId, LocalDefId}; -use rustc_middle::mir::{ConstOperand, Operand, TerminatorKind}; +use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_middle::mir::{Operand, TerminatorKind}; use rustc_middle::ty::{TyCtxt, TyKind}; use rustc_span::Span; -use std::collections::{HashMap, HashSet, VecDeque}; +use std::collections::{HashMap, VecDeque}; #[derive(Debug, Clone)] pub struct LocallyReachable { @@ -27,15 +27,15 @@ impl LocallyReachable { through: self .through .iter() - .cloned() + .copied() .chain(std::iter::once((self.reach, span))) .collect(), calls_to: HashMap::new(), } } - fn calls_to(&mut self, def_id: &DefId, span: Span) { - self.calls_to.entry(*def_id).or_default().push(span); + fn calls_to(&mut self, def_id: DefId, span: Span) { + self.calls_to.entry(def_id).or_default().push(span); } } @@ -96,22 +96,15 @@ impl<'tcx> rustc_middle::mir::visit::Visitor<'tcx> for BodyVisitor<'tcx, '_> { terminator: &rustc_middle::mir::Terminator<'tcx>, location: rustc_middle::mir::Location, ) { - if let TerminatorKind::Call { - func, - call_source, - fn_span, - .. - } = &terminator.kind + if let TerminatorKind::Call { func, .. } = &terminator.kind + && let Operand::Constant(box co) = func + && let TyKind::FnDef(def_id, _substs) = co.const_.ty().kind() { - if let Operand::Constant(box co) = func { - if let TyKind::FnDef(def_id, _substs) = co.const_.ty().kind() { - self.2.calls_to(def_id, terminator.source_info.span); - if let Some(local_def) = def_id.as_local() { - // Doing BFS here to ensure we get the shortest path possible to all reachable items. - self.1 - .push_back(self.2.extended_to(local_def, terminator.source_info.span)); - } - } + self.2.calls_to(*def_id, terminator.source_info.span); + if let Some(local_def) = def_id.as_local() { + // Doing BFS here to ensure we get the shortest path possible to all reachable items. + self.1 + .push_back(self.2.extended_to(local_def, terminator.source_info.span)); } } diff --git a/crates/sniff-test/src/utils/err.rs b/crates/sniff-test/src/utils/err.rs index 4cdc985..4dd0906 100644 --- a/crates/sniff-test/src/utils/err.rs +++ b/crates/sniff-test/src/utils/err.rs @@ -21,8 +21,8 @@ pub trait MultiEmittable { fn emit_all_errors(self, tcx: TyCtxt) -> Self::Emitted; } -impl MultiEmittable - for HashMap> +impl + MultiEmittable for HashMap, S> { type Emitted = Result, ErrorGuaranteed>; fn emit_all_errors(self, tcx: TyCtxt) -> Self::Emitted { diff --git a/tests/unsafe/fail_not_annotated/src/main.rs b/tests/unsafe/fail_not_annotated/src/main.rs index 603dcde..02408bd 100644 --- a/tests/unsafe/fail_not_annotated/src/main.rs +++ b/tests/unsafe/fail_not_annotated/src/main.rs @@ -1,15 +1,27 @@ +/// # Unsafe +/// - css: css fn foo(ptr: *const i32) -> i32 { + let a = unsafe { *ptr }; + // std::mem::drop(ptr); + a + 2 +} + +/// # Unsafe +/// - css: css +fn foo2(ptr: *const i32) -> i32 { let a = unsafe { *ptr }; a + 2 } fn bar(ptr: *const i32) -> i32 { - foo(ptr) + unsafe { *ptr } + let a = foo(ptr); + foo2(ptr) + unsafe { *ptr } + foo(ptr) + a } #[sniff_test_attrs::check_unsafe] fn main() { let x = 1; + /// Hello bar(&raw const x); } From e37659978e1fe7953e03c613835625b55625a0db Mon Sep 17 00:00:00 2001 From: AlexanderPortland Date: Thu, 23 Oct 2025 19:56:45 -0400 Subject: [PATCH 13/40] annotation consistency working for local crate --- crates/sniff-test/src/annotations/check.rs | 42 + crates/sniff-test/src/annotations/err.rs | 8 +- crates/sniff-test/src/annotations/mod.rs | 24 +- crates/sniff-test/src/annotations/parsing.rs | 1035 +++++++++--------- crates/sniff-test/src/annotations/types.rs | 22 +- crates/sniff-test/src/check/expr.rs | 71 ++ crates/sniff-test/src/check/mod.rs | 73 +- crates/sniff-test/src/reachability/bad.rs | 26 +- tests/unsafe/fail_not_annotated/src/main.rs | 16 +- 9 files changed, 762 insertions(+), 555 deletions(-) create mode 100644 crates/sniff-test/src/annotations/check.rs create mode 100644 crates/sniff-test/src/check/expr.rs diff --git a/crates/sniff-test/src/annotations/check.rs b/crates/sniff-test/src/annotations/check.rs new file mode 100644 index 0000000..646b1b6 --- /dev/null +++ b/crates/sniff-test/src/annotations/check.rs @@ -0,0 +1,42 @@ +use rustc_span::source_map::Spanned; + +use crate::annotations::{Justification, Requirement, types::ConditionName}; + +pub struct ConsistencyIssue<'r> { + missing_cond: &'r Spanned, +} + +pub fn check_consistency<'r>( + justifications: &[Spanned], + for_requirements: &'r [Spanned], +) -> Result<(), ConsistencyIssue<'r>> { + println!("does {justifications:?} satisfy {for_requirements:?}??"); + for req in for_requirements { + let sat = justifications + .iter() + .any(|just| just.node.name().as_str() == req.node.name().as_str()); + if !sat { + return Err(ConsistencyIssue { missing_cond: req }); + } + } + + Ok(()) +} + +mod error { + use rustc_errors::{Diag, DiagCtxtHandle}; + + use crate::annotations::check::ConsistencyIssue; + + impl ConsistencyIssue<'_> { + pub fn diag<'tcx>(&self, dcx: DiagCtxtHandle<'tcx>) -> Diag<'tcx> { + dcx.struct_span_err( + self.missing_cond.span, + format!( + "no justification for requirement {}", + self.missing_cond.node.name().as_str() + ), + ) + } + } +} diff --git a/crates/sniff-test/src/annotations/err.rs b/crates/sniff-test/src/annotations/err.rs index e1354db..c5444ca 100644 --- a/crates/sniff-test/src/annotations/err.rs +++ b/crates/sniff-test/src/annotations/err.rs @@ -6,8 +6,8 @@ use crate::utils::SniffTestDiagnostic; use rustc_errors::{Diag, DiagCtxtHandle}; use rustc_hir::Attribute; use rustc_middle::ty::TyCtxt; -use rustc_span::Span; use rustc_span::def_id::DefId; +use rustc_span::{DUMMY_SP, Span}; use std::ops::Range; #[derive(PartialEq, Eq, Debug)] @@ -59,7 +59,9 @@ impl ParsingIssue { ParsingError { issue: self, loc_name: format!("function definition {}", tcx.def_path_debug_str(def_id)), - span: tcx.hir_span(tcx.local_def_id_to_hir_id(def_id.expect_local())), + span: def_id.as_local().map_or(DUMMY_SP, |local| { + tcx.hir_span(tcx.local_def_id_to_hir_id(local)) + }), doc_comments: def_id.get_attrs(tcx), } } @@ -268,7 +270,7 @@ impl ParsingError<'_> { // Utilities for converting character ranges of a doc string into spans that can be // used to reference specific source code when displaying error messages. -mod span { +pub mod span { use rustc_hir::Attribute; use rustc_span::BytePos; use rustc_span::Span; diff --git a/crates/sniff-test/src/annotations/mod.rs b/crates/sniff-test/src/annotations/mod.rs index 48887dd..55ffc93 100644 --- a/crates/sniff-test/src/annotations/mod.rs +++ b/crates/sniff-test/src/annotations/mod.rs @@ -3,9 +3,11 @@ use crate::annotations::{attr::Attributeable, err::ParsingIssue}; use parsing::ParseBulletsFromString; use rustc_middle::ty::TyCtxt; +use rustc_span::source_map::{Spanned, respan}; use std::borrow::Borrow; mod attr; +pub mod check; mod err; pub mod parsing; mod types; @@ -27,14 +29,28 @@ pub trait Annotation<'a>: ParseBulletsFromString { /// Parse the given [`Input`](Annotation::Input). #[allow(clippy::missing_errors_doc)] - fn parse(tcx: TyCtxt, input: impl Borrow) -> Result, ParsingError> { + fn parse( + tcx: TyCtxt, + input: impl Borrow, + ) -> Result>, ParsingError> { let input: &Self::Input = input.borrow(); + let attrs = input.get_attrs(tcx); let doc_str: Result = input.get_doc_str(tcx).ok_or(ParsingIssue::NoDocString); - doc_str + println!("doc string is {doc_str:?}"); + + Ok(doc_str .and_then(|doc_str| Self::parse_bullets_from_string(&doc_str)) - .map_err(input.convert_err(tcx)) + .map_err(input.convert_err(tcx))? + .into_iter() + .map(|(req, range)| { + respan( + *err::span::span_some_comments(attrs, range).first().unwrap(), + req, + ) + }) + .collect()) } /// Try to parse the given [`Input`](Annotation::Input), returning `None` if @@ -42,7 +58,7 @@ pub trait Annotation<'a>: ParseBulletsFromString { fn try_parse( tcx: TyCtxt, input: impl Borrow, - ) -> Option, ParsingError>> { + ) -> Option>, ParsingError>> { let res = Self::parse(tcx, input); // If the error is recoverable, just return none instead. diff --git a/crates/sniff-test/src/annotations/parsing.rs b/crates/sniff-test/src/annotations/parsing.rs index 354c7fe..c0500b9 100644 --- a/crates/sniff-test/src/annotations/parsing.rs +++ b/crates/sniff-test/src/annotations/parsing.rs @@ -1,6 +1,10 @@ //! Utilities for parsing values from full doc strings. -use crate::annotations::{Justification, Requirement, err::ParsingIssue, types::ConditionName}; +use crate::annotations::{ + Justification, Requirement, + err::{self, ParsingIssue}, + types::ConditionName, +}; use regex::Regex; use std::ops::Range; @@ -38,7 +42,9 @@ pub trait ParseBulletsFromString: Sized { bullet_pre_chars: Range, ) -> Result; - fn parse_bullets_from_string(original_comment_str: &str) -> Result, ParsingIssue> { + fn parse_bullets_from_string( + original_comment_str: &str, + ) -> Result)>, ParsingIssue> { // First, make sure we have the marker and trim everything before that. let comment_str = &original_comment_str[Self::section_marker_regex() .find(original_comment_str) @@ -81,7 +87,10 @@ pub trait ParseBulletsFromString: Sized { offset..(offset + bullet_str.len()), bullet_str.find(' ').unwrap_or(bullet_str.len()), ))?; - Self::parse_bullet(pre, post, offset..(offset + pre.len())) + Ok(( + Self::parse_bullet(pre, post, offset..(offset + pre.len()))?, + offset..(offset + bullet_str.len()), + )) }) .collect::, ParsingIssue>>() } @@ -186,513 +195,513 @@ mod bullet { } } -#[cfg(test)] -mod test { - /// General utility macro for testing that parsing a certain `$type` from a certain `$str` - /// results in the expected result. - macro_rules! test_string_parse { - (($type: ty) $test_name: tt: $str: expr => ok $expected_requirements: expr) => { - #[test] - fn $test_name() { - let doc_str = $str; - let requirements = <$type>::parse_bullets_from_string(doc_str); - assert_eq!(requirements, Ok($expected_requirements)); - } - }; - (($type: ty) $test_name: tt: $str: expr => err $expected_err: pat) => { - #[test] - fn $test_name() { - let doc_str = $str; - let requirements = <$type>::parse_bullets_from_string(doc_str); - std::assert_matches::assert_matches!(requirements, Err($expected_err)); - } - }; - } - - /// General utility macro for making a vector of types that can be - /// constructed with a `try_new` method. - macro_rules! try_new { - ($type: ident, $($name: expr => $desc: expr)*) => { - vec![$(crate::annotations::$type::new(crate::annotations::types::ConditionName::try_new($name).unwrap(), $desc),)*] - }; - } - - #[rustfmt::skip] // Skip formatting because it looks weird for the testing macros. - mod requirements { - use crate::annotations::{parsing::ParseBulletsFromString, Requirement}; - use crate::annotations::types::InvalidConditionNameReason; - - /// Generate a test that ensures expected [`Requirement`] parsing from a given doc string. - macro_rules! test_req_parse { - ($test_name: tt: $str: expr => ok $expected_requirements: expr) => { - test_string_parse!((Requirement) $test_name: $str => ok $expected_requirements); - }; - ($test_name: tt: $str: expr => err $expected_err: pat) => { - test_string_parse!((Requirement) $test_name: $str => err $expected_err); - }; - } - - /// Helper for easily creating vectors of [`Requirement`]s. - macro_rules! reqs { - ($($name: expr => $desc: expr)*) => { - try_new!(Requirement, $($name => $desc)*) - }; - } - - use crate::annotations::err::ParsingIssue; - - test_req_parse!(simple_no_requirements: - r"# Unsafe" - => err ParsingIssue::EmptyMarker); - - test_req_parse!(simple_no_marker: - r"This is a random doc comment" - => err ParsingIssue::NoMarkerPattern); - - test_req_parse!(multi_line_no_marker: - r"This is a random doc comment. - It is multiple lines, but it still has no marker - unfortunately..." - => err ParsingIssue::NoMarkerPattern); - - test_req_parse!(incorrect_markers: - r"# Hi! - # Hello! - # Usage - # Overview" - => err ParsingIssue::NoMarkerPattern); - - test_req_parse!(incorrect_marker_w_desc: - r"# Usage - - nn: the pointer must be non-null - - align: the pointer must be aligned" - => err ParsingIssue::NoMarkerPattern); - - test_req_parse!(multiple_correct_markers: - r"# Unsafe - # Unsafe" - => err ParsingIssue::MultipleMarkerPatterns(..)); - - test_req_parse!(multiple_correct_markers_separeted: - r"# Unsafe - - nn: the pointer must be non-null - - align: the pointer must be aligned - # Unsafe" - => err ParsingIssue::MultipleMarkerPatterns(..)); - - test_req_parse!(bullet_with_no_colon: - r"# Unsafe - - nn the pointer must be non-null" - => err ParsingIssue::NoColon(..)); - - test_req_parse!(multiple_bullets_with_no_colon: - r"# Unsafe - - nn the pointer must be non-null - - align the pointer must be aligned" - => err ParsingIssue::NoColon(..)); - - test_req_parse!(simplest_use: - r"# Unsafe - - nn: the pointer must be non-null" - => ok reqs!( - "nn" => "the pointer must be non-null" - )); - - test_req_parse!(simple_use_many_requirements: - r"# Unsafe - - nn: the pointer must be non-null - - align: the pointer must be aligned - - heap-allocated: the pointer must be heap-allocated" - => ok reqs!( - "nn" => "the pointer must be non-null" - "align" => "the pointer must be aligned" - "heap-allocated" => "the pointer must be heap-allocated" - )); - - test_req_parse!(ignores_text_before: - r"filler text, blah blah blah... - # Unsafe - - nn: the pointer must be non-null - - align: the pointer must be aligned" - => ok reqs!( - "nn" => "the pointer must be non-null" - "align"=> "the pointer must be aligned" - )); - - test_req_parse!(intro_prose_allowed: - r"# Unsafe - This function must satisfy the following invariants - to avoid UB: - - nn: the pointer must be non-null - - align: the pointer must be aligned" - => ok reqs!( - "nn" => "the pointer must be non-null" - "align"=> "the pointer must be aligned" - )); - - test_req_parse!(ignores_other_markers_before: - r"# Usage - - Use this struct however you'd like, I don't mind. - # Unsafe - - nn: the pointer must be non-null - - align: the pointer must be aligned" - => ok reqs!( - "nn" => "the pointer must be non-null" - "align"=> "the pointer must be aligned" - )); - - test_req_parse!(ignores_other_markers_after: - r"# Unsafe - - nn: the pointer must be non-null - - align: the pointer must be aligned - # Usage - - Use this struct however you'd like, I don't mind." - => ok reqs!( - "nn" => "the pointer must be non-null" - "align"=> "the pointer must be aligned" - )); - - test_req_parse!(ignores_sandwiched_other_markers: - r"# Overview - - this is a function of some kind - # Unsafe - - nn: the pointer must be non-null - - align: the pointer must be aligned - # Usage - - Use this struct however you'd like, I don't mind." - => ok reqs!( - "nn" => "the pointer must be non-null" - "align"=> "the pointer must be aligned" - )); - - test_req_parse!(section_ends_with_empty_line: - r"# Unsafe - - nn: the pointer must be non-null - - align: the pointer must be aligned - - - Use this struct however you'd like, I don't mind." - => ok reqs!( - "nn" => "the pointer must be non-null" - "align"=> "the pointer must be aligned" - )); - - test_req_parse!(section_ends_with_whitespace_only_line: - r"# Unsafe - - nn: the pointer must be non-null - - align: the pointer must be aligned - - - Use this struct however you'd like, I don't mind." - => ok reqs!( - "nn" => "the pointer must be non-null" - "align"=> "the pointer must be aligned" - )); - - test_req_parse!(markers_arent_case_sensitive: - r"# UNSAFE - - nn: the pointer must be non-null - - align: the pointer must be aligned" - => ok reqs!( - "nn" => "the pointer must be non-null" - "align"=> "the pointer must be aligned" - )); - test_req_parse!(markers_allow_any_markdown_header: - r"### UNSAFE - - nn: the pointer must be non-null - - align: the pointer must be aligned" - => ok reqs!( - "nn" => "the pointer must be non-null" - "align"=> "the pointer must be aligned" - )); - - test_req_parse!(asterisk_bullets_allowed: - r"# Unsafe - * nn: the pointer must be non-null - * align: the pointer must be aligned" - => ok reqs!( - "nn" => "the pointer must be non-null" - "align"=> "the pointer must be aligned" - )); - - test_req_parse!(bullet_types_must_match: - r"# Unsafe - * nn: the pointer must be non-null - - align: the pointer must be aligned" - => err ParsingIssue::NonMatchingBullets(_)); - - test_req_parse!(spaces_after_bullet_ignored: - r"# Unsafe - - nn: the pointer must be non-null - - align: the pointer must be aligned" - => ok reqs!( - "nn" => "the pointer must be non-null" - "align"=> "the pointer must be aligned" - )); - - test_req_parse!(spaces_before_colon_disallowed: - r"# Unsafe - - nn : the pointer must be non-null - - align : the pointer must be aligned" - => err ParsingIssue::InvalidConditionName {reason: InvalidConditionNameReason::TrailingWhitespace, ..}); - - test_req_parse!(multi_word_names_disallowed: - r"# Unsafe - - non null: the pointer must be non-null - - aligned ptr: the pointer must be aligned" - => err ParsingIssue::InvalidConditionName {reason: InvalidConditionNameReason::MultipleWords, ..}); - - test_req_parse!(kebab_case_names_allowed: - r"# Unsafe - - non-null: the pointer must be non-null - - aligned-ptr: the pointer must be aligned" - => ok reqs!( - "non-null" => "the pointer must be non-null" - "aligned-ptr"=> "the pointer must be aligned" - )); - - test_req_parse!(snake_case_names_allowed: - r"# Unsafe - - non_null: the pointer must be non-null - - aligned_ptr: the pointer must be aligned" - => ok reqs!( - "non_null" => "the pointer must be non-null" - "aligned_ptr"=> "the pointer must be aligned" - )); - } - - #[rustfmt::skip] // Skip formatting because it looks weird for the testing macros. - mod justifications { - use crate::annotations::err::ParsingIssue; - use crate::annotations::types::InvalidConditionNameReason; - use crate::annotations::{parsing::ParseBulletsFromString, Justification}; - - /// Generate a test that ensures expected [`Justification`] parsing from a given doc string. - macro_rules! test_just_parse { - ($test_name: tt: $str: expr => ok $expected_requirements: expr) => { - test_string_parse!((Justification) $test_name: $str => ok $expected_requirements); - }; - ($test_name: tt: $str: expr => err $expected_err: pat) => { - test_string_parse!((Justification) $test_name: $str => err $expected_err); - }; - } - - /// Helper for easily creating vectors of [`Justification`]s. - macro_rules! justs { - ($($name: expr => $desc: expr)*) => { - try_new!(Justification, $($name => $desc)*) - }; - } - - test_just_parse!(simple_no_requirements: - r"SAFETY:" - => err ParsingIssue::EmptyMarker); - - test_just_parse!(simple_no_marker: - r"This is a random doc comment" - => err ParsingIssue::NoMarkerPattern); - - test_just_parse!(multi_line_no_marker: - r"This is a random doc comment. - It is multiple lines, but it still has no marker - unfortunately..." - => err ParsingIssue::NoMarkerPattern); - - test_just_parse!(incorrect_markers: - r"# Hi! - Unsafety: - # Usage - Usage:" - => err ParsingIssue::NoMarkerPattern); - - test_just_parse!(incorrect_marker_w_desc: - r"Usage: - - nn: the pointer must be non-null - - align: the pointer must be aligned" - => err ParsingIssue::NoMarkerPattern); - - test_just_parse!(multiple_correct_markers: - r"Safety: - Safety:" - => err ParsingIssue::MultipleMarkerPatterns(..)); - - test_just_parse!(multiple_correct_markers_separeted: - r"Safety: - - nn: the pointer must be non-null - - align: the pointer must be aligned - Safety:" - => err ParsingIssue::MultipleMarkerPatterns(..)); - - test_just_parse!(bullet_with_no_colon: - r"Safety: - - nn the pointer must be non-null" - => err ParsingIssue::NoColon(..)); - - test_just_parse!(multiple_bullets_with_no_colon: - r"Safety: - - nn the pointer must be non-null - - align the pointer must be aligned" - => err ParsingIssue::NoColon(..)); - - test_just_parse!(simplest_use: - r"SAFETY: - - nn: the pointer must be non-null" - => ok justs!( - "nn" => "the pointer must be non-null" - )); - - test_just_parse!(simple_use_many_requirements: - r"SAFETY: - - nn: the pointer must be non-null - - align: the pointer must be aligned - - heap-allocated: the pointer must be heap-allocated" - => ok justs!( - "nn" => "the pointer must be non-null" - "align" => "the pointer must be aligned" - "heap-allocated" => "the pointer must be heap-allocated" - )); - - test_just_parse!(ignores_text_before: - r"filler text, blah blah blah... - SAFETY: - - nn: the pointer must be non-null - - align: the pointer must be aligned" - => ok justs!( - "nn" => "the pointer must be non-null" - "align"=> "the pointer must be aligned" - )); - - test_just_parse!(intro_prose_allowed: - r"SAFETY: - This function call will avoid UB because we have satisfied - the following conditions: - - nn: the pointer must be non-null - - align: the pointer must be aligned" - => ok justs!( - "nn" => "the pointer must be non-null" - "align"=> "the pointer must be aligned" - )); - - test_just_parse!(ignores_other_markers_before: - r"Usage: - - Use this struct however you'd like, I don't mind. - - Safety: - - nn: the pointer must be non-null - - align: the pointer must be aligned" - => ok justs!( - "nn" => "the pointer must be non-null" - "align"=> "the pointer must be aligned" - )); - - test_just_parse!(ignores_other_markers_after: - r"SAFETY: - - nn: the pointer must be non-null - - align: the pointer must be aligned - - USAGE: - - Use this struct however you'd like, I don't mind." - => ok justs!( - "nn" => "the pointer must be non-null" - "align"=> "the pointer must be aligned" - )); - - test_just_parse!(ignores_sandwiched_other_markers: - r"Overview: - - this is a function of some kind - - SAFETY: - - nn: the pointer must be non-null - - align: the pointer must be aligned - - Usage - - Use this struct however you'd like, I don't mind." - => ok justs!( - "nn" => "the pointer must be non-null" - "align"=> "the pointer must be aligned" - )); - - test_just_parse!(section_ends_with_empty_line: - r"SAFETY: - - nn: the pointer must be non-null - - align: the pointer must be aligned - - - Use this struct however you'd like, I don't mind." - => ok justs!( - "nn" => "the pointer must be non-null" - "align"=> "the pointer must be aligned" - )); - - test_just_parse!(section_ends_with_whitespace_only_line: - r"SAFETY: - - nn: the pointer must be non-null - - align: the pointer must be aligned - - - Use this struct however you'd like, I don't mind." - => ok justs!( - "nn" => "the pointer must be non-null" - "align"=> "the pointer must be aligned" - )); - - test_just_parse!(markers_arent_case_sensitive: - r"Safety: - - nn: the pointer must be non-null - - align: the pointer must be aligned" - => ok justs!( - "nn" => "the pointer must be non-null" - "align"=> "the pointer must be aligned" - )); - - test_just_parse!(asterisk_bullets_allowed: - r"Safety: - * nn: the pointer must be non-null - * align: the pointer must be aligned" - => ok justs!( - "nn" => "the pointer must be non-null" - "align"=> "the pointer must be aligned" - )); - - test_just_parse!(bullet_types_must_match: - r"Safety: - * nn: the pointer must be non-null - - align: the pointer must be aligned" - => err ParsingIssue::NonMatchingBullets(_)); - - test_just_parse!(spaces_after_bullet_ignored: - r"Safety: - - nn: the pointer must be non-null - - align: the pointer must be aligned" - => ok justs!( - "nn" => "the pointer must be non-null" - "align"=> "the pointer must be aligned" - )); - - test_just_parse!(spaces_before_colon_disallowed: - r"Safety: - - nn : the pointer must be non-null - - align : the pointer must be aligned" - => err ParsingIssue::InvalidConditionName {reason: InvalidConditionNameReason::TrailingWhitespace, ..}); - - test_just_parse!(multi_word_names_disallowed: - r"Safety: - - non null: the pointer must be non-null - - aligned ptr: the pointer must be aligned" - => err ParsingIssue::InvalidConditionName {reason: InvalidConditionNameReason::MultipleWords, ..}); - - test_just_parse!(kebab_case_names_allowed: - r"Safety: - - non-null: the pointer must be non-null - - aligned-ptr: the pointer must be aligned" - => ok justs!( - "non-null" => "the pointer must be non-null" - "aligned-ptr"=> "the pointer must be aligned" - )); - - test_just_parse!(snake_case_names_allowed: - r"Safety: - - non_null: the pointer must be non-null - - aligned_ptr: the pointer must be aligned" - => ok justs!( - "non_null" => "the pointer must be non-null" - "aligned_ptr"=> "the pointer must be aligned" - )); - } -} +// #[cfg(test)] +// mod test { +// /// General utility macro for testing that parsing a certain `$type` from a certain `$str` +// /// results in the expected result. +// macro_rules! test_string_parse { +// (($type: ty) $test_name: tt: $str: expr => ok $expected_requirements: expr) => { +// #[test] +// fn $test_name() { +// let doc_str = $str; +// let requirements = <$type>::parse_bullets_from_string(doc_str); +// assert_eq!(requirements, Ok($expected_requirements)); +// } +// }; +// (($type: ty) $test_name: tt: $str: expr => err $expected_err: pat) => { +// #[test] +// fn $test_name() { +// let doc_str = $str; +// let requirements = <$type>::parse_bullets_from_string(doc_str); +// std::assert_matches::assert_matches!(requirements, Err($expected_err)); +// } +// }; +// } + +// /// General utility macro for making a vector of types that can be +// /// constructed with a `try_new` method. +// macro_rules! try_new { +// ($type: ident, $($name: expr => $desc: expr)*) => { +// vec![$(crate::annotations::$type::new(crate::annotations::types::ConditionName::try_new($name).unwrap(), $desc),)*] +// }; +// } + +// #[rustfmt::skip] // Skip formatting because it looks weird for the testing macros. +// mod requirements { +// use crate::annotations::{parsing::ParseBulletsFromString, Requirement}; +// use crate::annotations::types::InvalidConditionNameReason; + +// /// Generate a test that ensures expected [`Requirement`] parsing from a given doc string. +// macro_rules! test_req_parse { +// ($test_name: tt: $str: expr => ok $expected_requirements: expr) => { +// test_string_parse!((Requirement) $test_name: $str => ok $expected_requirements); +// }; +// ($test_name: tt: $str: expr => err $expected_err: pat) => { +// test_string_parse!((Requirement) $test_name: $str => err $expected_err); +// }; +// } + +// /// Helper for easily creating vectors of [`Requirement`]s. +// macro_rules! reqs { +// ($($name: expr => $desc: expr)*) => { +// try_new!(Requirement, $($name => $desc)*) +// }; +// } + +// use crate::annotations::err::ParsingIssue; + +// test_req_parse!(simple_no_requirements: +// r"# Unsafe" +// => err ParsingIssue::EmptyMarker); + +// test_req_parse!(simple_no_marker: +// r"This is a random doc comment" +// => err ParsingIssue::NoMarkerPattern); + +// test_req_parse!(multi_line_no_marker: +// r"This is a random doc comment. +// It is multiple lines, but it still has no marker +// unfortunately..." +// => err ParsingIssue::NoMarkerPattern); + +// test_req_parse!(incorrect_markers: +// r"# Hi! +// # Hello! +// # Usage +// # Overview" +// => err ParsingIssue::NoMarkerPattern); + +// test_req_parse!(incorrect_marker_w_desc: +// r"# Usage +// - nn: the pointer must be non-null +// - align: the pointer must be aligned" +// => err ParsingIssue::NoMarkerPattern); + +// test_req_parse!(multiple_correct_markers: +// r"# Unsafe +// # Unsafe" +// => err ParsingIssue::MultipleMarkerPatterns(..)); + +// test_req_parse!(multiple_correct_markers_separeted: +// r"# Unsafe +// - nn: the pointer must be non-null +// - align: the pointer must be aligned +// # Unsafe" +// => err ParsingIssue::MultipleMarkerPatterns(..)); + +// test_req_parse!(bullet_with_no_colon: +// r"# Unsafe +// - nn the pointer must be non-null" +// => err ParsingIssue::NoColon(..)); + +// test_req_parse!(multiple_bullets_with_no_colon: +// r"# Unsafe +// - nn the pointer must be non-null +// - align the pointer must be aligned" +// => err ParsingIssue::NoColon(..)); + +// test_req_parse!(simplest_use: +// r"# Unsafe +// - nn: the pointer must be non-null" +// => ok reqs!( +// "nn" => "the pointer must be non-null" +// )); + +// test_req_parse!(simple_use_many_requirements: +// r"# Unsafe +// - nn: the pointer must be non-null +// - align: the pointer must be aligned +// - heap-allocated: the pointer must be heap-allocated" +// => ok reqs!( +// "nn" => "the pointer must be non-null" +// "align" => "the pointer must be aligned" +// "heap-allocated" => "the pointer must be heap-allocated" +// )); + +// test_req_parse!(ignores_text_before: +// r"filler text, blah blah blah... +// # Unsafe +// - nn: the pointer must be non-null +// - align: the pointer must be aligned" +// => ok reqs!( +// "nn" => "the pointer must be non-null" +// "align"=> "the pointer must be aligned" +// )); + +// test_req_parse!(intro_prose_allowed: +// r"# Unsafe +// This function must satisfy the following invariants +// to avoid UB: +// - nn: the pointer must be non-null +// - align: the pointer must be aligned" +// => ok reqs!( +// "nn" => "the pointer must be non-null" +// "align"=> "the pointer must be aligned" +// )); + +// test_req_parse!(ignores_other_markers_before: +// r"# Usage +// - Use this struct however you'd like, I don't mind. +// # Unsafe +// - nn: the pointer must be non-null +// - align: the pointer must be aligned" +// => ok reqs!( +// "nn" => "the pointer must be non-null" +// "align"=> "the pointer must be aligned" +// )); + +// test_req_parse!(ignores_other_markers_after: +// r"# Unsafe +// - nn: the pointer must be non-null +// - align: the pointer must be aligned +// # Usage +// - Use this struct however you'd like, I don't mind." +// => ok reqs!( +// "nn" => "the pointer must be non-null" +// "align"=> "the pointer must be aligned" +// )); + +// test_req_parse!(ignores_sandwiched_other_markers: +// r"# Overview +// - this is a function of some kind +// # Unsafe +// - nn: the pointer must be non-null +// - align: the pointer must be aligned +// # Usage +// - Use this struct however you'd like, I don't mind." +// => ok reqs!( +// "nn" => "the pointer must be non-null" +// "align"=> "the pointer must be aligned" +// )); + +// test_req_parse!(section_ends_with_empty_line: +// r"# Unsafe +// - nn: the pointer must be non-null +// - align: the pointer must be aligned + +// - Use this struct however you'd like, I don't mind." +// => ok reqs!( +// "nn" => "the pointer must be non-null" +// "align"=> "the pointer must be aligned" +// )); + +// test_req_parse!(section_ends_with_whitespace_only_line: +// r"# Unsafe +// - nn: the pointer must be non-null +// - align: the pointer must be aligned + +// - Use this struct however you'd like, I don't mind." +// => ok reqs!( +// "nn" => "the pointer must be non-null" +// "align"=> "the pointer must be aligned" +// )); + +// test_req_parse!(markers_arent_case_sensitive: +// r"# UNSAFE +// - nn: the pointer must be non-null +// - align: the pointer must be aligned" +// => ok reqs!( +// "nn" => "the pointer must be non-null" +// "align"=> "the pointer must be aligned" +// )); +// test_req_parse!(markers_allow_any_markdown_header: +// r"### UNSAFE +// - nn: the pointer must be non-null +// - align: the pointer must be aligned" +// => ok reqs!( +// "nn" => "the pointer must be non-null" +// "align"=> "the pointer must be aligned" +// )); + +// test_req_parse!(asterisk_bullets_allowed: +// r"# Unsafe +// * nn: the pointer must be non-null +// * align: the pointer must be aligned" +// => ok reqs!( +// "nn" => "the pointer must be non-null" +// "align"=> "the pointer must be aligned" +// )); + +// test_req_parse!(bullet_types_must_match: +// r"# Unsafe +// * nn: the pointer must be non-null +// - align: the pointer must be aligned" +// => err ParsingIssue::NonMatchingBullets(_)); + +// test_req_parse!(spaces_after_bullet_ignored: +// r"# Unsafe +// - nn: the pointer must be non-null +// - align: the pointer must be aligned" +// => ok reqs!( +// "nn" => "the pointer must be non-null" +// "align"=> "the pointer must be aligned" +// )); + +// test_req_parse!(spaces_before_colon_disallowed: +// r"# Unsafe +// - nn : the pointer must be non-null +// - align : the pointer must be aligned" +// => err ParsingIssue::InvalidConditionName {reason: InvalidConditionNameReason::TrailingWhitespace, ..}); + +// test_req_parse!(multi_word_names_disallowed: +// r"# Unsafe +// - non null: the pointer must be non-null +// - aligned ptr: the pointer must be aligned" +// => err ParsingIssue::InvalidConditionName {reason: InvalidConditionNameReason::MultipleWords, ..}); + +// test_req_parse!(kebab_case_names_allowed: +// r"# Unsafe +// - non-null: the pointer must be non-null +// - aligned-ptr: the pointer must be aligned" +// => ok reqs!( +// "non-null" => "the pointer must be non-null" +// "aligned-ptr"=> "the pointer must be aligned" +// )); + +// test_req_parse!(snake_case_names_allowed: +// r"# Unsafe +// - non_null: the pointer must be non-null +// - aligned_ptr: the pointer must be aligned" +// => ok reqs!( +// "non_null" => "the pointer must be non-null" +// "aligned_ptr"=> "the pointer must be aligned" +// )); +// } + +// #[rustfmt::skip] // Skip formatting because it looks weird for the testing macros. +// mod justifications { +// use crate::annotations::err::ParsingIssue; +// use crate::annotations::types::InvalidConditionNameReason; +// use crate::annotations::{parsing::ParseBulletsFromString, Justification}; + +// /// Generate a test that ensures expected [`Justification`] parsing from a given doc string. +// macro_rules! test_just_parse { +// ($test_name: tt: $str: expr => ok $expected_requirements: expr) => { +// test_string_parse!((Justification) $test_name: $str => ok $expected_requirements); +// }; +// ($test_name: tt: $str: expr => err $expected_err: pat) => { +// test_string_parse!((Justification) $test_name: $str => err $expected_err); +// }; +// } + +// /// Helper for easily creating vectors of [`Justification`]s. +// macro_rules! justs { +// ($($name: expr => $desc: expr)*) => { +// try_new!(Justification, $($name => $desc)*) +// }; +// } + +// test_just_parse!(simple_no_requirements: +// r"SAFETY:" +// => err ParsingIssue::EmptyMarker); + +// test_just_parse!(simple_no_marker: +// r"This is a random doc comment" +// => err ParsingIssue::NoMarkerPattern); + +// test_just_parse!(multi_line_no_marker: +// r"This is a random doc comment. +// It is multiple lines, but it still has no marker +// unfortunately..." +// => err ParsingIssue::NoMarkerPattern); + +// test_just_parse!(incorrect_markers: +// r"# Hi! +// Unsafety: +// # Usage +// Usage:" +// => err ParsingIssue::NoMarkerPattern); + +// test_just_parse!(incorrect_marker_w_desc: +// r"Usage: +// - nn: the pointer must be non-null +// - align: the pointer must be aligned" +// => err ParsingIssue::NoMarkerPattern); + +// test_just_parse!(multiple_correct_markers: +// r"Safety: +// Safety:" +// => err ParsingIssue::MultipleMarkerPatterns(..)); + +// test_just_parse!(multiple_correct_markers_separeted: +// r"Safety: +// - nn: the pointer must be non-null +// - align: the pointer must be aligned +// Safety:" +// => err ParsingIssue::MultipleMarkerPatterns(..)); + +// test_just_parse!(bullet_with_no_colon: +// r"Safety: +// - nn the pointer must be non-null" +// => err ParsingIssue::NoColon(..)); + +// test_just_parse!(multiple_bullets_with_no_colon: +// r"Safety: +// - nn the pointer must be non-null +// - align the pointer must be aligned" +// => err ParsingIssue::NoColon(..)); + +// test_just_parse!(simplest_use: +// r"SAFETY: +// - nn: the pointer must be non-null" +// => ok justs!( +// "nn" => "the pointer must be non-null" +// )); + +// test_just_parse!(simple_use_many_requirements: +// r"SAFETY: +// - nn: the pointer must be non-null +// - align: the pointer must be aligned +// - heap-allocated: the pointer must be heap-allocated" +// => ok justs!( +// "nn" => "the pointer must be non-null" +// "align" => "the pointer must be aligned" +// "heap-allocated" => "the pointer must be heap-allocated" +// )); + +// test_just_parse!(ignores_text_before: +// r"filler text, blah blah blah... +// SAFETY: +// - nn: the pointer must be non-null +// - align: the pointer must be aligned" +// => ok justs!( +// "nn" => "the pointer must be non-null" +// "align"=> "the pointer must be aligned" +// )); + +// test_just_parse!(intro_prose_allowed: +// r"SAFETY: +// This function call will avoid UB because we have satisfied +// the following conditions: +// - nn: the pointer must be non-null +// - align: the pointer must be aligned" +// => ok justs!( +// "nn" => "the pointer must be non-null" +// "align"=> "the pointer must be aligned" +// )); + +// test_just_parse!(ignores_other_markers_before: +// r"Usage: +// - Use this struct however you'd like, I don't mind. + +// Safety: +// - nn: the pointer must be non-null +// - align: the pointer must be aligned" +// => ok justs!( +// "nn" => "the pointer must be non-null" +// "align"=> "the pointer must be aligned" +// )); + +// test_just_parse!(ignores_other_markers_after: +// r"SAFETY: +// - nn: the pointer must be non-null +// - align: the pointer must be aligned + +// USAGE: +// - Use this struct however you'd like, I don't mind." +// => ok justs!( +// "nn" => "the pointer must be non-null" +// "align"=> "the pointer must be aligned" +// )); + +// test_just_parse!(ignores_sandwiched_other_markers: +// r"Overview: +// - this is a function of some kind + +// SAFETY: +// - nn: the pointer must be non-null +// - align: the pointer must be aligned + +// Usage +// - Use this struct however you'd like, I don't mind." +// => ok justs!( +// "nn" => "the pointer must be non-null" +// "align"=> "the pointer must be aligned" +// )); + +// test_just_parse!(section_ends_with_empty_line: +// r"SAFETY: +// - nn: the pointer must be non-null +// - align: the pointer must be aligned + +// - Use this struct however you'd like, I don't mind." +// => ok justs!( +// "nn" => "the pointer must be non-null" +// "align"=> "the pointer must be aligned" +// )); + +// test_just_parse!(section_ends_with_whitespace_only_line: +// r"SAFETY: +// - nn: the pointer must be non-null +// - align: the pointer must be aligned + +// - Use this struct however you'd like, I don't mind." +// => ok justs!( +// "nn" => "the pointer must be non-null" +// "align"=> "the pointer must be aligned" +// )); + +// test_just_parse!(markers_arent_case_sensitive: +// r"Safety: +// - nn: the pointer must be non-null +// - align: the pointer must be aligned" +// => ok justs!( +// "nn" => "the pointer must be non-null" +// "align"=> "the pointer must be aligned" +// )); + +// test_just_parse!(asterisk_bullets_allowed: +// r"Safety: +// * nn: the pointer must be non-null +// * align: the pointer must be aligned" +// => ok justs!( +// "nn" => "the pointer must be non-null" +// "align"=> "the pointer must be aligned" +// )); + +// test_just_parse!(bullet_types_must_match: +// r"Safety: +// * nn: the pointer must be non-null +// - align: the pointer must be aligned" +// => err ParsingIssue::NonMatchingBullets(_)); + +// test_just_parse!(spaces_after_bullet_ignored: +// r"Safety: +// - nn: the pointer must be non-null +// - align: the pointer must be aligned" +// => ok justs!( +// "nn" => "the pointer must be non-null" +// "align"=> "the pointer must be aligned" +// )); + +// test_just_parse!(spaces_before_colon_disallowed: +// r"Safety: +// - nn : the pointer must be non-null +// - align : the pointer must be aligned" +// => err ParsingIssue::InvalidConditionName {reason: InvalidConditionNameReason::TrailingWhitespace, ..}); + +// test_just_parse!(multi_word_names_disallowed: +// r"Safety: +// - non null: the pointer must be non-null +// - aligned ptr: the pointer must be aligned" +// => err ParsingIssue::InvalidConditionName {reason: InvalidConditionNameReason::MultipleWords, ..}); + +// test_just_parse!(kebab_case_names_allowed: +// r"Safety: +// - non-null: the pointer must be non-null +// - aligned-ptr: the pointer must be aligned" +// => ok justs!( +// "non-null" => "the pointer must be non-null" +// "aligned-ptr"=> "the pointer must be aligned" +// )); + +// test_just_parse!(snake_case_names_allowed: +// r"Safety: +// - non_null: the pointer must be non-null +// - aligned_ptr: the pointer must be aligned" +// => ok justs!( +// "non_null" => "the pointer must be non-null" +// "aligned_ptr"=> "the pointer must be aligned" +// )); +// } +// } diff --git a/crates/sniff-test/src/annotations/types.rs b/crates/sniff-test/src/annotations/types.rs index 207cf84..dd646b3 100644 --- a/crates/sniff-test/src/annotations/types.rs +++ b/crates/sniff-test/src/annotations/types.rs @@ -2,7 +2,9 @@ use std::borrow::Borrow; -#[derive(PartialEq, Eq, Debug)] +use serde::{Deserialize, Serialize}; + +#[derive(PartialEq, Eq, Debug, Serialize, Deserialize)] /// A condition that must hold such that a given function call will not cause UB. pub struct Requirement { name: ConditionName, @@ -17,8 +19,8 @@ impl Requirement { } } - pub fn name(&self) -> &str { - &self.name.0 + pub fn name(&self) -> &ConditionName { + &self.name } pub fn description(&self) -> &str { @@ -54,9 +56,17 @@ impl Justification { explanation: explanation.borrow().to_string(), } } + + pub fn name(&self) -> &ConditionName { + &self.name + } + + pub fn description(&self) -> &str { + &self.explanation + } } -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct ConditionName(String); impl ConditionName { @@ -65,6 +75,10 @@ impl ConditionName { // For now, just check that it's a single word with no extra white space. Ok(ConditionName(check_single_word(name)?)) } + + pub fn as_str(&self) -> &str { + &self.0 + } } #[derive(Debug, Clone, PartialEq, Eq)] diff --git a/crates/sniff-test/src/check/expr.rs b/crates/sniff-test/src/check/expr.rs new file mode 100644 index 0000000..14adf02 --- /dev/null +++ b/crates/sniff-test/src/check/expr.rs @@ -0,0 +1,71 @@ +use std::{ + cell::{LazyCell, RefCell}, + collections::HashMap, + sync::{LazyLock, Mutex}, +}; + +use rustc_hir::{ + Expr, ExprKind, HirId, + def_id::{DefId, LocalDefId}, + intravisit::{self, Visitor}, +}; +use rustc_middle::ty::TyCtxt; +use rustc_span::Span; + +// thread_local! { +// static MAPPINGS: RefCell> = Default::default(); +// } + +// fn find_expr_for_call(tcx: TyCtxt, call_to: DefId, call_from: Span) -> Expr { +// // MAPPINGS.with_borrow_mut(move |map| { +// // *map.entry(call_from) +// // .or_insert_with(move || find_expr_for_call_inner(tcx, call_from)) +// // }) +// find_expr_for_call_inner(tcx, call_to, call_from) +// } + +pub fn find_expr_for_call( + tcx: TyCtxt<'_>, + call_to: DefId, + call_from: LocalDefId, + call_from_span: Span, +) -> &Expr<'_> { + let mut f = SpanExprFinder(tcx, call_to, call_from_span, None); + f.visit_body(tcx.hir_body_owned_by(call_from)); + f.3.expect("hello") +} + +struct SpanExprFinder<'tcx>(TyCtxt<'tcx>, DefId, Span, Option<&'tcx Expr<'tcx>>); + +impl<'tcx> intravisit::Visitor<'tcx> for SpanExprFinder<'tcx> { + type MaybeTyCtxt = TyCtxt<'tcx>; + + fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt { + self.0 + } + + fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) -> Self::Result { + if let ExprKind::Call(to, from) = ex.kind + && ex.span == self.2 + { + println!("call and matching spa to {to:?}"); + if let ExprKind::Path(qpath) = &to.kind { + let tychck = self.0.typeck(ex.hir_id.owner.def_id); + + // Resolve the path to get the DefId + if let Some(def_id) = tychck.qpath_res(qpath, to.hir_id).opt_def_id() { + println!("resolve to defid {def_id:?}"); + if def_id == self.1 { + println!("WHICH MATCHES!!"); + self.3 = Some(ex); + return; + } + } + } else { + todo!("should handle more complex resolution here..."); + } + } + + intravisit::walk_expr(self, ex); + } +} diff --git a/crates/sniff-test/src/check/mod.rs b/crates/sniff-test/src/check/mod.rs index 49483d0..aedc6d2 100644 --- a/crates/sniff-test/src/check/mod.rs +++ b/crates/sniff-test/src/check/mod.rs @@ -1,15 +1,18 @@ use itertools::Itertools; use rustc_errors::{Diag, DiagCtxtHandle}; +use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::ty::TyCtxt; -use rustc_span::{ErrorGuaranteed, source_map::Spanned}; +use rustc_span::{ErrorGuaranteed, source_map::Spanned, sym::todo_macro}; use crate::{ - annotations::{self, Annotation}, + annotations::{self, Annotation, ParsingError, Requirement}, axioms::{self, Axiom, AxiomFinder, AxiomaticBadness}, reachability::{self, CallsToBad, LocallyReachable}, utils::SniffTestDiagnostic, }; +mod expr; + /// Checks that all local functions in the crate are properly annotated. pub fn check_properly_annotated(tcx: TyCtxt) -> Result<(), ErrorGuaranteed> { let mut res = Ok(()); @@ -26,13 +29,27 @@ pub fn check_properly_annotated(tcx: TyCtxt) -> Result<(), ErrorGuaranteed> { for reachable in reachable.iter().cloned() { let axioms = axioms::find_axioms(axioms::SafetyFinder, tcx, &reachable); - let bad_calls = reachability::find_bad_calls(tcx, &reachable) - .map_err(|parsing_error| parsing_error.diag(tcx.dcx()).emit())?; + // Parse the requirements + let my_requirements = annotations::Requirement::try_parse(tcx, reachable.reach.to_def_id()); + // let find_requirements = |def_id| annotations::Requirement::parse(tcx, def_id); + // let find_justifications = |def_id| annotations::Justification::parse(tcx, def_id); - let annotations = annotations::Requirement::try_parse(tcx, reachable.reach.to_def_id()); + let bad_calls = reachability::find_bad_calls(tcx, &reachable) + .map_err(|parsing_error| parsing_error.diag(tcx.dcx()).emit())? + // Take only the unjustified call sites + .map(only_unjustified_callsites(tcx, reachable.reach)) + // Filter out everything that no longer has call sites + .filter(|calls| { + !calls + .as_ref() + .is_ok_and(|calls| calls.from_spans.is_empty()) + }) + .collect::, ErrorGuaranteed>>()?; + + // let justifications = annotations::Justification::try_parse(tcx, todo!()); // For now, just check that all functions with axioms have some annotations. - if annotations.is_none() && (!axioms.is_empty() || !bad_calls.is_empty()) { + if my_requirements.is_none() && (!axioms.is_empty() || !bad_calls.is_empty()) { res = Err(needs_annotation( tcx.dcx(), tcx, @@ -45,6 +62,31 @@ pub fn check_properly_annotated(tcx: TyCtxt) -> Result<(), ErrorGuaranteed> { res } +fn only_unjustified_callsites( + tcx: TyCtxt, + in_fn: LocalDefId, +) -> impl Fn(CallsToBad) -> Result { + move |mut calls| { + let mut new_spans = Vec::new(); + let requirements = + annotations::Requirement::parse(tcx, calls.def_id).map_err(|e| e.emit(tcx.dcx()))?; + + for call_span in calls.from_spans { + let expr = expr::find_expr_for_call(tcx, calls.def_id, in_fn, call_span); + let justs = annotations::Justification::try_parse(tcx, expr); + println!("justs are {justs:?}"); + match justs { + Some(Err(e)) => return Err(e.emit(tcx.dcx())), + Some(Ok(justs)) => annotations::check::check_consistency(&justs, &requirements) + .map_err(|e| e.diag(tcx.dcx()).emit())?, + None => new_spans.push(call_span), + } + } + calls.from_spans = new_spans; + Ok(calls) + } +} + struct FunctionIssues(Vec>, Vec); // pub fn check_function( @@ -83,16 +125,13 @@ fn needs_annotation( } fn diag_handle_bad_call<'d>(mut diag: Diag<'d>, tcx: TyCtxt, bad_call: CallsToBad) -> Diag<'d> { - let (num, s) = if bad_call.from_spans.len() > 1 { - (format!("{} ", bad_call.from_spans.len()), "s") - } else { - (String::new(), "") - }; + // let times = if bad_call.from_spans.len() > 1 { + // format!("{} times ", bad_call.from_spans.len()) + // } else { + // String::new() + // }; let call_to = tcx.def_path_str(bad_call.def_id); - diag = diag.with_span_note( - bad_call.from_spans, - format!("{num}call{s} to {call_to} here"), - ); + diag = diag.with_span_note(bad_call.from_spans, format!("{call_to} is called here")); diag } @@ -170,7 +209,7 @@ mod summary { x if x > 1 => "s", _ => return None, }; - Some(format!("{count} call{s} to {kind} functions")) + Some(format!("{count} unjustified call{s} to {kind} functions")) } fn axiom_summary(axioms: &[Spanned]) -> Option { @@ -181,6 +220,6 @@ mod summary { x if x > 1 => "s", _ => return None, }; - Some(format!("{count} {kind} axiom{s}")) + Some(format!("{count} unjustified {kind} axiom{s}")) } } diff --git a/crates/sniff-test/src/reachability/bad.rs b/crates/sniff-test/src/reachability/bad.rs index 2dc16c5..5eb2441 100644 --- a/crates/sniff-test/src/reachability/bad.rs +++ b/crates/sniff-test/src/reachability/bad.rs @@ -5,15 +5,32 @@ use crate::reachability::LocallyReachable; use std::collections::HashMap; use crate::utils::MultiEmittable; -use rustc_hir::def_id::DefId; +use rustc_hir::def_id::{DefId, DefPathHash}; use rustc_middle::ty::TyCtxt; use rustc_public::mir::Safety; use rustc_public::ty::FnDef; +use rustc_span::source_map::Spanned; use rustc_span::{ErrorGuaranteed, Span}; +// TODO: use this shit instead in all the parsing +enum Annotations { + General, + SpecificConditions(Vec), +} + +type BadMap = HashMap>; + +fn build_bad_map(tcx: TyCtxt) -> Result { + // for a in tcx.hir_crate_items(()).definitions() { + + // } + + todo!() +} + pub struct CallsToBad { pub def_id: DefId, - pub requirements: Vec, + pub requirements: Vec>, pub from_spans: Vec, } @@ -38,18 +55,19 @@ fn is_call_bad<'tcx>( pub fn find_bad_calls<'tcx>( tcx: TyCtxt<'tcx>, locally_reachable: &LocallyReachable, -) -> Result, ParsingError<'tcx>> { +) -> Result, ParsingError<'tcx>> { locally_reachable .calls_to .iter() .filter_map(is_call_bad(tcx)) .collect::, ParsingError>>() + .map(std::iter::IntoIterator::into_iter) } pub fn filter_bad_functions( tcx: TyCtxt, items: &[FnDef], -) -> Result>, ErrorGuaranteed> { +) -> Result>>, ErrorGuaranteed> { let annotated_bad = items .iter() .filter_map(|item| { diff --git a/tests/unsafe/fail_not_annotated/src/main.rs b/tests/unsafe/fail_not_annotated/src/main.rs index 02408bd..0596424 100644 --- a/tests/unsafe/fail_not_annotated/src/main.rs +++ b/tests/unsafe/fail_not_annotated/src/main.rs @@ -1,21 +1,17 @@ /// # Unsafe -/// - css: css +/// - non-null: ptr is non-null +/// - aligned: ptr is aligned for a i32 fn foo(ptr: *const i32) -> i32 { let a = unsafe { *ptr }; // std::mem::drop(ptr); a + 2 } -/// # Unsafe -/// - css: css -fn foo2(ptr: *const i32) -> i32 { - let a = unsafe { *ptr }; - a + 2 -} - fn bar(ptr: *const i32) -> i32 { - let a = foo(ptr); - foo2(ptr) + unsafe { *ptr } + foo(ptr) + a + /// SAFETY: + /// - non-null: i have checked this is non-null + /// - aligned: i have also checked it is aligned + foo(ptr) } #[sniff_test_attrs::check_unsafe] From 12b4bdb6d18ce110f9b57a0f2a280e7f273818bf Mon Sep 17 00:00:00 2001 From: AlexanderPortland Date: Thu, 23 Oct 2025 20:11:14 -0400 Subject: [PATCH 14/40] actual snapshot testing now --- crates/sniff-test/src/annotations/check.rs | 2 +- crates/sniff-test/src/annotations/mod.rs | 2 +- crates/sniff-test/src/check/expr.rs | 6 +-- crates/sniff-test/src/check/mod.rs | 6 +-- crates/sniff-test/src/reachability/entry.rs | 1 - tests/unsafe/.DS_Store | Bin 0 -> 6148 bytes tests/unsafe/fail_nested/Cargo.lock | 41 ++++++++++++++++++ tests/unsafe/fail_nested/Cargo.toml | 9 ++++ tests/unsafe/fail_nested/fail_nested.snap | 21 +++++++++ .../fail_not_annotated.snap | 16 ++++++- tests/unsafe/fail_not_annotated/src/main.rs | 8 +--- tests/unsafe/fail_simple/fail_simple.snap | 21 +++++++++ tests/unsafe/fail_simple/src/main.rs | 2 +- tests/unsafe/pass_nested/pass_nested.snap | 8 ++++ tests/unsafe/pass_nested/src/main.rs | 4 +- tests/unsafe/pass_simple/pass_simple.snap | 22 ++++++++++ tests/unsafe/pass_simple/src/main.rs | 13 ++---- 17 files changed, 152 insertions(+), 30 deletions(-) create mode 100644 tests/unsafe/.DS_Store create mode 100644 tests/unsafe/fail_nested/Cargo.lock create mode 100644 tests/unsafe/fail_nested/Cargo.toml create mode 100644 tests/unsafe/fail_nested/fail_nested.snap create mode 100644 tests/unsafe/fail_simple/fail_simple.snap create mode 100644 tests/unsafe/pass_nested/pass_nested.snap create mode 100644 tests/unsafe/pass_simple/pass_simple.snap diff --git a/crates/sniff-test/src/annotations/check.rs b/crates/sniff-test/src/annotations/check.rs index 646b1b6..0ef2d31 100644 --- a/crates/sniff-test/src/annotations/check.rs +++ b/crates/sniff-test/src/annotations/check.rs @@ -10,7 +10,7 @@ pub fn check_consistency<'r>( justifications: &[Spanned], for_requirements: &'r [Spanned], ) -> Result<(), ConsistencyIssue<'r>> { - println!("does {justifications:?} satisfy {for_requirements:?}??"); + // println!("does {justifications:?} satisfy {for_requirements:?}??"); for req in for_requirements { let sat = justifications .iter() diff --git a/crates/sniff-test/src/annotations/mod.rs b/crates/sniff-test/src/annotations/mod.rs index 55ffc93..eb31a08 100644 --- a/crates/sniff-test/src/annotations/mod.rs +++ b/crates/sniff-test/src/annotations/mod.rs @@ -38,7 +38,7 @@ pub trait Annotation<'a>: ParseBulletsFromString { let doc_str: Result = input.get_doc_str(tcx).ok_or(ParsingIssue::NoDocString); - println!("doc string is {doc_str:?}"); + // println!("doc string is {doc_str:?}"); Ok(doc_str .and_then(|doc_str| Self::parse_bullets_from_string(&doc_str)) diff --git a/crates/sniff-test/src/check/expr.rs b/crates/sniff-test/src/check/expr.rs index 14adf02..134982c 100644 --- a/crates/sniff-test/src/check/expr.rs +++ b/crates/sniff-test/src/check/expr.rs @@ -48,15 +48,15 @@ impl<'tcx> intravisit::Visitor<'tcx> for SpanExprFinder<'tcx> { if let ExprKind::Call(to, from) = ex.kind && ex.span == self.2 { - println!("call and matching spa to {to:?}"); + // println!("call and matching spa to {to:?}"); if let ExprKind::Path(qpath) = &to.kind { let tychck = self.0.typeck(ex.hir_id.owner.def_id); // Resolve the path to get the DefId if let Some(def_id) = tychck.qpath_res(qpath, to.hir_id).opt_def_id() { - println!("resolve to defid {def_id:?}"); + // println!("resolve to defid {def_id:?}"); if def_id == self.1 { - println!("WHICH MATCHES!!"); + // println!("WHICH MATCHES!!"); self.3 = Some(ex); return; } diff --git a/crates/sniff-test/src/check/mod.rs b/crates/sniff-test/src/check/mod.rs index aedc6d2..8573e8a 100644 --- a/crates/sniff-test/src/check/mod.rs +++ b/crates/sniff-test/src/check/mod.rs @@ -19,11 +19,11 @@ pub fn check_properly_annotated(tcx: TyCtxt) -> Result<(), ErrorGuaranteed> { let entry = reachability::annotated_local_entry_points(tcx).collect::>(); - println!("entry is {entry:?}"); + // println!("entry is {entry:?}"); let reachable = reachability::locally_reachable_from(tcx, entry).collect::>(); - println!("reachable is {reachable:?}"); + // println!("reachable is {reachable:?}"); // For all reachable local function definitions, ensure their axioms align with their annotations. for reachable in reachable.iter().cloned() { @@ -74,7 +74,7 @@ fn only_unjustified_callsites( for call_span in calls.from_spans { let expr = expr::find_expr_for_call(tcx, calls.def_id, in_fn, call_span); let justs = annotations::Justification::try_parse(tcx, expr); - println!("justs are {justs:?}"); + // println!("justs are {justs:?}"); match justs { Some(Err(e)) => return Err(e.emit(tcx.dcx())), Some(Ok(justs)) => annotations::check::check_consistency(&justs, &requirements) diff --git a/crates/sniff-test/src/reachability/entry.rs b/crates/sniff-test/src/reachability/entry.rs index 98f7187..e0be719 100644 --- a/crates/sniff-test/src/reachability/entry.rs +++ b/crates/sniff-test/src/reachability/entry.rs @@ -1,4 +1,3 @@ - use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::ty::TyCtxt; diff --git a/tests/unsafe/.DS_Store b/tests/unsafe/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..54280f5f7651030fd5cad439d2b2b27c51e1f99a GIT binary patch literal 6148 zcmeHKyG{c^3>-s>NNG}1?l15Mt0;UyJ|IB~qCp2DKz&udi%(e`MLYdt}0_hI`7zHzynTrW4z3qyTS|Z$vRE=$B*6X z@bo-9=IxhVrz$BR1*Cu!kOETR7X`fc(w3`4MJXT!q`921ictKq}y$yO7J#nX9zi*i^`RFncz zV5-1%Zr9%b@900w|5K87Qa}p)D+O$^-EB8~rRuG-m-AlR=m)yjeA3;x4hloGV`8*p hZoD1eL{Zi?U-P^dj)_5MKIlaK47e^bDe%_{d;!!*7773W literal 0 HcmV?d00001 diff --git a/tests/unsafe/fail_nested/Cargo.lock b/tests/unsafe/fail_nested/Cargo.lock new file mode 100644 index 0000000..d5f0a88 --- /dev/null +++ b/tests/unsafe/fail_nested/Cargo.lock @@ -0,0 +1,41 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "fail_nested" +version = "0.1.0" +dependencies = [ + "sniff-test-attrs", +] + +[[package]] +name = "proc-macro2" +version = "1.0.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "sniff-test-attrs" +version = "0.1.0" +dependencies = [ + "quote", +] + +[[package]] +name = "unicode-ident" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "462eeb75aeb73aea900253ce739c8e18a67423fadf006037cd3ff27e82748a06" diff --git a/tests/unsafe/fail_nested/Cargo.toml b/tests/unsafe/fail_nested/Cargo.toml new file mode 100644 index 0000000..9d99bb7 --- /dev/null +++ b/tests/unsafe/fail_nested/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "fail_nested" +version = "0.1.0" +edition = "2024" + +[dependencies] +sniff-test-attrs = { path = "../../../crates/sniff-test-attrs" } + +[workspace] \ No newline at end of file diff --git a/tests/unsafe/fail_nested/fail_nested.snap b/tests/unsafe/fail_nested/fail_nested.snap new file mode 100644 index 0000000..cf93a91 --- /dev/null +++ b/tests/unsafe/fail_nested/fail_nested.snap @@ -0,0 +1,21 @@ +--- +source: tests/lib.rs +--- +exit_code = 101 +stdout = '' +stderr = ''' +error: function bar directly contains 1 unjustified call to unsafe functions, but is not annotated unsafe + --> src/main.rs:8:1 + | +8 | fn bar(ptr: *const i32) -> i32 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: reachable from [main (src/main.rs:15:5) -> *bar*] +note: foo is called here + --> src/main.rs:9:5 + | +9 | foo(ptr) + | ^^^^^^^^ + +error: could not compile `fail_nested` (bin "fail_nested") due to 1 previous error +''' diff --git a/tests/unsafe/fail_not_annotated/fail_not_annotated.snap b/tests/unsafe/fail_not_annotated/fail_not_annotated.snap index b1ec081..78a82f9 100644 --- a/tests/unsafe/fail_not_annotated/fail_not_annotated.snap +++ b/tests/unsafe/fail_not_annotated/fail_not_annotated.snap @@ -4,12 +4,24 @@ source: tests/lib.rs exit_code = 101 stdout = '' stderr = ''' -error: function fail_not_annotated[801a]::foo has unsafe axioms, but is not annotated unsafe +warning: unused doc comment + --> src/main.rs:13:5 + | +13 | /// Hello + | ^^^^^^^^^ +14 | bar(&raw const x); + | ----------------- rustdoc does not generate documentation for expressions + | + = help: use `//` for a plain comment + = note: `#[warn(unused_doc_comments)]` on by default + +error: function foo directly contains 1 unjustified unsafe axiom, but is not annotated unsafe --> src/main.rs:1:1 | 1 | fn foo(ptr: *const i32) -> i32 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: reachable from [main (src/main.rs:14:5) -> bar (src/main.rs:7:5) -> *foo*] note: raw pointer derefence here --> src/main.rs:2:23 | @@ -19,5 +31,5 @@ note: raw pointer derefence here 1. the dereferenced pointer must be non-null 2. the dereferenced pointer must be aligned -error: could not compile `fail_not_annotated` (bin "fail_not_annotated") due to 1 previous error +error: could not compile `fail_not_annotated` (bin "fail_not_annotated") due to 1 previous error; 1 warning emitted ''' diff --git a/tests/unsafe/fail_not_annotated/src/main.rs b/tests/unsafe/fail_not_annotated/src/main.rs index 0596424..c807657 100644 --- a/tests/unsafe/fail_not_annotated/src/main.rs +++ b/tests/unsafe/fail_not_annotated/src/main.rs @@ -1,16 +1,9 @@ -/// # Unsafe -/// - non-null: ptr is non-null -/// - aligned: ptr is aligned for a i32 fn foo(ptr: *const i32) -> i32 { let a = unsafe { *ptr }; - // std::mem::drop(ptr); a + 2 } fn bar(ptr: *const i32) -> i32 { - /// SAFETY: - /// - non-null: i have checked this is non-null - /// - aligned: i have also checked it is aligned foo(ptr) } @@ -21,5 +14,6 @@ fn main() { bar(&raw const x); } +// Notes from justus // - instance safety for some traits // - when it cant be done alwyas deny and just allow specific instances diff --git a/tests/unsafe/fail_simple/fail_simple.snap b/tests/unsafe/fail_simple/fail_simple.snap new file mode 100644 index 0000000..a39fef5 --- /dev/null +++ b/tests/unsafe/fail_simple/fail_simple.snap @@ -0,0 +1,21 @@ +--- +source: tests/lib.rs +--- +exit_code = 101 +stdout = '' +stderr = ''' +error: function main directly contains 1 unjustified call to unsafe functions, but is not annotated unsafe + --> src/main.rs:8:1 + | + 8 | fn main() { + | ^^^^^^^^^ + | + = note: reachable from [*main*] +note: foo is called here + --> src/main.rs:10:5 + | +10 | foo(&raw const x); + | ^^^^^^^^^^^^^^^^^ + +error: could not compile `fail_simple` (bin "fail_simple") due to 1 previous error +''' diff --git a/tests/unsafe/fail_simple/src/main.rs b/tests/unsafe/fail_simple/src/main.rs index 9b6419f..90496cb 100644 --- a/tests/unsafe/fail_simple/src/main.rs +++ b/tests/unsafe/fail_simple/src/main.rs @@ -1,10 +1,10 @@ /// # Unsafe /// * nn: ptr should be non null -#[sniff_test_attrs::check_unsafe] fn foo(ptr: *const i32) -> i32 { unsafe { *ptr } } +#[sniff_test_attrs::check_unsafe] fn main() { let x = 1; foo(&raw const x); diff --git a/tests/unsafe/pass_nested/pass_nested.snap b/tests/unsafe/pass_nested/pass_nested.snap new file mode 100644 index 0000000..685329e --- /dev/null +++ b/tests/unsafe/pass_nested/pass_nested.snap @@ -0,0 +1,8 @@ +--- +source: tests/lib.rs +--- +exit_code = 0 +stdout = ''' +compilation successful!! +''' +stderr = '' diff --git a/tests/unsafe/pass_nested/src/main.rs b/tests/unsafe/pass_nested/src/main.rs index ddd1d76..9c39340 100644 --- a/tests/unsafe/pass_nested/src/main.rs +++ b/tests/unsafe/pass_nested/src/main.rs @@ -2,8 +2,8 @@ /// # Unsafe /// * nn: ptr should be non null -unsafe fn foo(val: *const i32) -> u32 { - unsafe { std::deref_in_std(val) } +unsafe fn foo(val: *const i32) -> i32 { + unsafe { *val } } #[sniff_test_attrs::check_unsafe] diff --git a/tests/unsafe/pass_simple/pass_simple.snap b/tests/unsafe/pass_simple/pass_simple.snap new file mode 100644 index 0000000..7b22e1f --- /dev/null +++ b/tests/unsafe/pass_simple/pass_simple.snap @@ -0,0 +1,22 @@ +--- +source: tests/lib.rs +--- +exit_code = 0 +stdout = ''' +compilation successful!! +''' +stderr = ''' +warning: unused doc comment + --> src/main.rs:13:9 + | +13 | / /// Safety: +14 | | /// * non-null: a pointer that comes from a reference is trivially non-null +15 | | /// * aligned: a pointer that comes from a reference is trivially aligned + | |_________________________________________________________________________________^ +16 | foo(&raw const x); + | ----------------- rustdoc does not generate documentation for expressions + | + = help: use `//` for a plain comment + = note: `#[warn(unused_doc_comments)]` on by default + +''' diff --git a/tests/unsafe/pass_simple/src/main.rs b/tests/unsafe/pass_simple/src/main.rs index ab0e23b..f1feaec 100644 --- a/tests/unsafe/pass_simple/src/main.rs +++ b/tests/unsafe/pass_simple/src/main.rs @@ -1,23 +1,18 @@ /// # Unsafe -/// - nonnn-nm: non null -/// - non-null: aligned -/// and ready for business +/// - non-null: ptr must be non-null +/// - aligned: ptr must be aligned for an i32 unsafe fn foo(ptr: *const i32) -> i32 { unsafe { *ptr } } -/// # Unsafe -/// - nonnnnm: non null -/// - non-null: aligned -/// and ready for business #[sniff_test_attrs::check_unsafe] fn main() { let x = 1; unsafe { /// Safety: - /// * nn-nn: ive done some check to make sure ptr isnt null - /// * nn-n: ive done some check to make sure ptr isnt null + /// * non-null: a pointer that comes from a reference is trivially non-null + /// * aligned: a pointer that comes from a reference is trivially aligned foo(&raw const x); } } From 43d74cf854b003c9baff5e9b7f8217c07d78e4fa Mon Sep 17 00:00:00 2001 From: AlexanderPortland Date: Fri, 24 Oct 2025 11:17:46 -0400 Subject: [PATCH 15/40] add support for single-file snapshot tests --- .gitignore | 4 +- Cargo.lock | 8 +- crates/sniff-test-attrs/src/lib.rs | 6 +- crates/sniff-test/src/lib.rs | 11 +- tests/Cargo.toml | 3 + tests/justified_call | Bin 0 -> 437488 bytes tests/lib.rs | 165 ++++++++++++++++++++--- tests/ref_deref | Bin 0 -> 436920 bytes tests/unsafe/axioms/raw_deref.rs | 11 ++ tests/unsafe/axioms/raw_deref.snap | 25 ++++ tests/unsafe/axioms/ref_deref.rs | 11 ++ tests/unsafe/axioms/ref_deref.snap | 8 ++ tests/unsafe/calls/justified_call.rs | 15 +++ tests/unsafe/calls/justified_call.snap | 23 ++++ tests/unsafe/calls/unjustified_call.rs | 13 ++ tests/unsafe/calls/unjustified_call.snap | 22 +++ 16 files changed, 299 insertions(+), 26 deletions(-) create mode 100755 tests/justified_call create mode 100755 tests/ref_deref create mode 100644 tests/unsafe/axioms/raw_deref.rs create mode 100644 tests/unsafe/axioms/raw_deref.snap create mode 100644 tests/unsafe/axioms/ref_deref.rs create mode 100644 tests/unsafe/axioms/ref_deref.snap create mode 100644 tests/unsafe/calls/justified_call.rs create mode 100644 tests/unsafe/calls/justified_call.snap create mode 100644 tests/unsafe/calls/unjustified_call.rs create mode 100644 tests/unsafe/calls/unjustified_call.snap diff --git a/.gitignore b/.gitignore index 7bbce1b..8c049ab 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ target review.sh -notes.md \ No newline at end of file +.DS_Store +notes.md +.snap.new \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 26d362f..bfc19b4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -426,14 +426,15 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.143" +version = "1.0.145" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d401abef1d108fbd9cbaebc3e46611f4b1021f714a0597a71f41ee463f5f4a5a" +checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" dependencies = [ "itoa", "memchr", "ryu", "serde", + "serde_core", ] [[package]] @@ -503,7 +504,10 @@ dependencies = [ "anyhow", "insta", "lazy_static", + "rustc_plugin", "serde", + "serde_json", + "sniff-test", "walkdir", ] diff --git a/crates/sniff-test-attrs/src/lib.rs b/crates/sniff-test-attrs/src/lib.rs index 2c3d054..95e1f2c 100644 --- a/crates/sniff-test-attrs/src/lib.rs +++ b/crates/sniff-test-attrs/src/lib.rs @@ -10,8 +10,10 @@ macro_rules! define_sniff_tool_annotation { let mut t = TokenStream::new(); // If we're registering the sniff-test tool, add the actual attribute to check unsafe. - if let Ok(rust_flags) = std::env::var("RUSTFLAGS") - && rust_flags.contains("-Zcrate-attr=register_tool(sniff_tool)") + let rustflags = std::env::var("RUSTFLAGS") + .map(|rust_flags| rust_flags.contains("-Zcrate-attr=register_tool(sniff_tool)")) + .unwrap_or(false); + if rustflags || std::env::var("PLUGIN_ARGS").is_ok() { t.extend(TokenStream::from(quote!( #[sniff_tool::$name] diff --git a/crates/sniff-test/src/lib.rs b/crates/sniff-test/src/lib.rs index 0d032b0..1eb81c3 100644 --- a/crates/sniff-test/src/lib.rs +++ b/crates/sniff-test/src/lib.rs @@ -46,8 +46,8 @@ pub struct PrintAllItemsPlugin; // To parse CLI arguments, we use Clap for this example. But that // detail is up to you. -#[derive(Parser, Serialize, Deserialize, Clone)] -pub struct PrintAllItemsPluginArgs { +#[derive(Parser, Serialize, Deserialize, Clone, Default)] +pub struct SniffTestArgs { #[arg(short, long)] allcaps: bool, @@ -56,7 +56,7 @@ pub struct PrintAllItemsPluginArgs { } impl RustcPlugin for PrintAllItemsPlugin { - type Args = PrintAllItemsPluginArgs; + type Args = SniffTestArgs; fn version(&self) -> Cow<'static, str> { env!("CARGO_PKG_VERSION").into() @@ -70,7 +70,7 @@ impl RustcPlugin for PrintAllItemsPlugin { // If one of the CLI arguments was a specific file to analyze, then you // could provide a different filter. fn args(&self, _target_dir: &Utf8Path) -> RustcPluginArgs { - let args = PrintAllItemsPluginArgs::parse_from(env::args().skip(1)); + let args = SniffTestArgs::parse_from(env::args().skip(1)); let filter = CrateFilter::AllCrates; RustcPluginArgs { args, filter } } @@ -90,6 +90,7 @@ impl RustcPlugin for PrintAllItemsPlugin { let mut callbacks = PrintAllItemsCallbacks { args: Some(plugin_args), }; + rustc_driver::run_compiler(&compiler_args, &mut callbacks); Ok(()) } @@ -97,7 +98,7 @@ impl RustcPlugin for PrintAllItemsPlugin { #[allow(dead_code)] struct PrintAllItemsCallbacks { - args: Option, + args: Option, } impl rustc_driver::Callbacks for PrintAllItemsCallbacks { diff --git a/tests/Cargo.toml b/tests/Cargo.toml index 5788598..26f7fd7 100644 --- a/tests/Cargo.toml +++ b/tests/Cargo.toml @@ -9,6 +9,9 @@ path = "lib.rs" [dependencies] anyhow = "1.0.100" insta = {version = "1.43.2", features = ["toml", "filters"]} +rustc_plugin = "=0.14.0-nightly-2025-08-20" +sniff-test ={ path = "../crates/sniff-test"} lazy_static = "1.5.0" serde = "1.0.228" walkdir = "2.5.0" +serde_json = "1.0.145" diff --git a/tests/justified_call b/tests/justified_call new file mode 100755 index 0000000000000000000000000000000000000000..a4010e00e743e5aeca2aee2580be0730794fcd3d GIT binary patch literal 437488 zcmeFadw5jU)%d^9OfF{QztV|M6`YT=kJl{ z8P3_awbx#I?X}ikd+n3oojCCE5T!K5KO4W1{HE$kJ*L`uQ))E7N`5sp*STiSxMjw? zxsrSKKeO@KS)WJ=oE>yfQ&Tp)islT4_xxiPys6OvNjm=DVA#OB`>v&DCS)+YcRUun zn=ZGYNP5sr$AgDn_uchC!(F%4G~D&|yD1qAujrQ+yg!Yynn`*vPVoS1YHqKu`T9L| zciwL04u+@xXu&&GA8kcCe#EIt#Y)Ty!p8xAH8s;+)vlU~xpU@Q+zh{3d>n-n^@cpDzvuS4+iLEwyGNwJV0eFWTkxKa zHk5QcytF|82jE4~91O4iNef)L?k6QFv3MEhHTeFS<

csPqB%a-1I`<-7X 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

@U7)kP08`zH6~tCnl?O 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 literal 0 HcmV?d00001 diff --git a/tests/lib.rs b/tests/lib.rs index 3f558fa..3bd0c13 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -1,4 +1,5 @@ #![allow(dead_code)] +#![feature(rustc_private)] use serde::Serialize; use std::{ @@ -11,8 +12,19 @@ use std::{ }; use walkdir::WalkDir; +const CARGO_SNIFF_NAME: &str = "cargo-sniff-test"; +const SNIFF_DRIVER_NAME: &str = "sniff-test-driver"; +const BUILD_DIR: &str = "../target/debug"; + static CARGO_SNIFF_TEST_PATH: LazyLock = LazyLock::new(|| { - let canon = Path::new("../target/debug/cargo-sniff-test").canonicalize(); + let canon = Path::new(&format!("{BUILD_DIR}/{CARGO_SNIFF_NAME}")).canonicalize(); + canon + .expect("issue with cargo sniff-test path") + .into_os_string() +}); + +static SNIFF_TEST_DRIVER_PATH: LazyLock = LazyLock::new(|| { + let canon = Path::new(&format!("{BUILD_DIR}/{SNIFF_DRIVER_NAME}")).canonicalize(); canon .expect("issue with cargo sniff-test path") .into_os_string() @@ -42,26 +54,73 @@ fn snapshots() -> anyhow::Result<()> { println!("root is {root:?}"); - let cargo_dirs = subdirectories(root) - .filter(|dir_path| is_cargo_project(dir_path)) - .map(|path| { - snapshot_cargo_dir(&path)?; - Ok(path) - }) - .collect::>>()?; + let mut cargo_dirs = Vec::new(); + let mut processed_dirs = std::collections::HashSet::new(); + + for entry in WalkDir::new(&root).min_depth(1).into_iter().flatten() { + let path = entry.path(); + + if !entry.metadata().map(|m| m.is_dir()).unwrap_or(false) { + continue; + } + + // Skip if we've already processed this directory as part of a cargo project + if processed_dirs.contains(path) { + continue; + } + + if is_cargo_project(path) { + // Process as a cargo project + snapshot_cargo_dir(path)?; + cargo_dirs.push(path.to_path_buf()); + + // Mark this directory and all subdirectories as processed + mark_descendants_as_processed(path, &mut processed_dirs); + } else if has_rust_files(path) && !is_inside_cargo_project(path, &root) { + // Process individual .rs files in this directory + snapshot_rust_files_dir(path)?; + cargo_dirs.push(path.to_path_buf()); + processed_dirs.insert(path.to_path_buf()); + } + } write_review_script(&cargo_dirs)?; Ok(()) } -fn subdirectories(root: PathBuf) -> impl Iterator { - WalkDir::new(root) - .min_depth(1) - .into_iter() - .flatten() - .filter(|e| e.metadata().map(|m| m.is_dir()).unwrap_or(false)) - .map(walkdir::DirEntry::into_path) +fn mark_descendants_as_processed(path: &Path, processed: &mut std::collections::HashSet) { + for entry in WalkDir::new(path).into_iter().flatten() { + if entry.metadata().map(|m| m.is_dir()).unwrap_or(false) { + processed.insert(entry.path().to_path_buf()); + } + } +} + +fn is_inside_cargo_project(path: &Path, root: &Path) -> bool { + let mut current = path; + while let Some(parent) = current.parent() { + if parent == root { + return false; + } + if is_cargo_project(parent) { + return true; + } + current = parent; + } + false +} + +fn has_rust_files(path: &Path) -> bool { + std::fs::read_dir(path) + .ok() + .and_then(|entries| { + entries.flatten().find(|entry| { + entry.path().extension().and_then(|s| s.to_str()) == Some("rs") + && entry.metadata().map(|m| m.is_file()).unwrap_or(false) + }) + }) + .is_some() } fn is_cargo_project(path: &Path) -> bool { @@ -69,7 +128,6 @@ fn is_cargo_project(path: &Path) -> bool { } fn snapshot_cargo_dir(path: &Path) -> anyhow::Result<()> { - println!("snapshotting {}", path.display()); let name = path .file_name() .expect("directory should have name") @@ -95,6 +153,52 @@ fn snapshot_cargo_dir(path: &Path) -> anyhow::Result<()> { Ok(()) } +fn snapshot_rust_files_dir(path: &Path) -> anyhow::Result<()> { + println!("snapshotting rust files in {}", path.display()); + + let rust_files: Vec<_> = std::fs::read_dir(path)? + .flatten() + .filter(|entry| { + entry.path().extension().and_then(|s| s.to_str()) == Some("rs") + && entry.metadata().map(|m| m.is_file()).unwrap_or(false) + }) + .collect(); + + for entry in rust_files { + let file_path = entry.path(); + snapshot_single_rust_file(&file_path)?; + } + + Ok(()) +} + +fn snapshot_single_rust_file(file_path: &Path) -> anyhow::Result<()> { + println!(" snapshotting rust file {}", file_path.display()); + + let name = file_path + .file_stem() + .and_then(|s| s.to_str()) + .unwrap_or("[unknown]") + .to_owned(); + + let out_path = file_path.parent().unwrap_or(Path::new(".")).to_path_buf(); + let out = rustc_sniff(file_path)?; + + insta::with_settings!({ + snapshot_path => out_path, + filters => vec![ + (r"process didn't exit successfully: `(.*?)`", "process didn't exit successfully: [BINARY PATH ELIDED]") + ], + prepend_module_to_snapshot => false, + omit_expression => true, + }, { + insta::assert_toml_snapshot!(name, &out); + }); + + println!(" file output is {out:?}"); + Ok(()) +} + fn cargo_sniff(path: &Path) -> anyhow::Result { // cargo clean first Command::new("cargo") @@ -114,6 +218,35 @@ fn cargo_sniff(path: &Path) -> anyhow::Result { Ok(cmd.output()?.try_into()?) } +fn rustc_sniff(file_path: &Path) -> anyhow::Result { + let mut cmd = Command::new(&*SNIFF_TEST_DRIVER_PATH); + + // Env vars needed for the single invocation of the driver to work. + cmd.env("RUSTC_PLUGIN_ALL_TARGETS", ""); + cmd.env("RUSTC_WORKSPACE_WRAPPER", ""); + + // We have to serialize the default plugin args so it knows what to do. + cmd.env( + "PLUGIN_ARGS", + serde_json::to_string(&sniff_test::SniffTestArgs::default()) + .expect("default args should be serializeable"), + ); + + // Link w/ our external attrs crate. + cmd.arg("--extern").arg(format!( + "sniff_test_attrs={BUILD_DIR}/libsniff_test_attrs.dylib" + )); + + // Register the sniff_tool. + cmd.arg("-Zcrate-attr=feature(register_tool)") + .arg("-Zcrate-attr=register_tool(sniff_tool)"); + + // Pass in compilation argument. + cmd.arg(file_path); + + Ok(cmd.output()?.try_into()?) +} + const REVIEW_SCRIPT_PATH: &str = "../review.sh"; fn write_review_script(cargo_dirs: &[PathBuf]) -> anyhow::Result<()> { diff --git a/tests/ref_deref b/tests/ref_deref new file mode 100755 index 0000000000000000000000000000000000000000..86b0ef739ad79d2fbfa7cbdcf65c805a59b17596 GIT binary patch literal 436920 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%0Aha9Ke-_*rd0ql2H7M8P50 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

;Ql#`UlY81F5^?a#^txqW85m(Jf87`f|He3e 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 i32 { + unsafe { *ptr } +} + +#[sniff_test_attrs::check_unsafe] +fn main() { + let x = 1; + foo(&raw const x); +} diff --git a/tests/unsafe/axioms/raw_deref.snap b/tests/unsafe/axioms/raw_deref.snap new file mode 100644 index 0000000..24403ae --- /dev/null +++ b/tests/unsafe/axioms/raw_deref.snap @@ -0,0 +1,25 @@ +--- +source: tests/lib.rs +--- +exit_code = 1 +stdout = '' +stderr = ''' +error: function foo directly contains 1 unjustified unsafe axiom, but is not annotated unsafe + --> /Users/alexanderportland/Desktop/research/sniff-test/tests/unsafe/axioms/raw_deref.rs:3:1 + | +3 | fn foo(ptr: *const i32) -> i32 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: reachable from [main (/Users/alexanderportland/Desktop/research/sniff-test/tests/unsafe/axioms/raw_deref.rs:10:5) -> *foo*] +note: raw pointer derefence here + --> /Users/alexanderportland/Desktop/research/sniff-test/tests/unsafe/axioms/raw_deref.rs:4:15 + | +4 | unsafe { *ptr } + | ^^^ + = help: this axiom has known requirements: + 1. the dereferenced pointer must be non-null + 2. the dereferenced pointer must be aligned + +error: aborting due to 1 previous error + +''' diff --git a/tests/unsafe/axioms/ref_deref.rs b/tests/unsafe/axioms/ref_deref.rs new file mode 100644 index 0000000..4de4590 --- /dev/null +++ b/tests/unsafe/axioms/ref_deref.rs @@ -0,0 +1,11 @@ +extern crate sniff_test_attrs; + +fn foo(ptr: &i32) -> i32 { + *ptr +} + +#[sniff_test_attrs::check_unsafe] +fn main() { + let x = 1; + foo(&x); +} diff --git a/tests/unsafe/axioms/ref_deref.snap b/tests/unsafe/axioms/ref_deref.snap new file mode 100644 index 0000000..685329e --- /dev/null +++ b/tests/unsafe/axioms/ref_deref.snap @@ -0,0 +1,8 @@ +--- +source: tests/lib.rs +--- +exit_code = 0 +stdout = ''' +compilation successful!! +''' +stderr = '' diff --git a/tests/unsafe/calls/justified_call.rs b/tests/unsafe/calls/justified_call.rs new file mode 100644 index 0000000..cd18e4c --- /dev/null +++ b/tests/unsafe/calls/justified_call.rs @@ -0,0 +1,15 @@ +extern crate sniff_test_attrs; + +/// # Unsafe +/// * nn: ptr should be non null +fn foo(ptr: *const i32) -> i32 { + unsafe { *ptr } +} + +#[sniff_test_attrs::check_unsafe] +fn main() { + let x = 1; + /// SAFETY: + /// - nn: pointers from references are trivially non-null + foo(&raw const x); +} diff --git a/tests/unsafe/calls/justified_call.snap b/tests/unsafe/calls/justified_call.snap new file mode 100644 index 0000000..ce0cfe5 --- /dev/null +++ b/tests/unsafe/calls/justified_call.snap @@ -0,0 +1,23 @@ +--- +source: tests/lib.rs +--- +exit_code = 0 +stdout = ''' +compilation successful!! +''' +stderr = ''' +warning: unused doc comment + --> /Users/alexanderportland/Desktop/research/sniff-test/tests/unsafe/calls/justified_call.rs:12:5 + | +12 | / /// SAFETY: +13 | | /// - nn: pointers from references are trivially non-null + | |_____________________________________________________________^ +14 | foo(&raw const x); + | ----------------- rustdoc does not generate documentation for expressions + | + = help: use `//` for a plain comment + = note: `#[warn(unused_doc_comments)]` on by default + +warning: 1 warning emitted + +''' diff --git a/tests/unsafe/calls/unjustified_call.rs b/tests/unsafe/calls/unjustified_call.rs new file mode 100644 index 0000000..3c4a699 --- /dev/null +++ b/tests/unsafe/calls/unjustified_call.rs @@ -0,0 +1,13 @@ +extern crate sniff_test_attrs; + +/// # Unsafe +/// * nn: ptr should be non null +fn foo(ptr: *const i32) -> i32 { + unsafe { *ptr } +} + +#[sniff_test_attrs::check_unsafe] +fn main() { + let x = 1; + foo(&raw const x); +} diff --git a/tests/unsafe/calls/unjustified_call.snap b/tests/unsafe/calls/unjustified_call.snap new file mode 100644 index 0000000..a622abd --- /dev/null +++ b/tests/unsafe/calls/unjustified_call.snap @@ -0,0 +1,22 @@ +--- +source: tests/lib.rs +--- +exit_code = 1 +stdout = '' +stderr = ''' +error: function main directly contains 1 unjustified call to unsafe functions, but is not annotated unsafe + --> /Users/alexanderportland/Desktop/research/sniff-test/tests/unsafe/calls/unjustified_call.rs:10:1 + | +10 | fn main() { + | ^^^^^^^^^ + | + = note: reachable from [*main*] +note: foo is called here + --> /Users/alexanderportland/Desktop/research/sniff-test/tests/unsafe/calls/unjustified_call.rs:12:5 + | +12 | foo(&raw const x); + | ^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + +''' From 73d650d243fcba16b2018af0005accfe7eac0dc2 Mon Sep 17 00:00:00 2001 From: AlexanderPortland Date: Fri, 24 Oct 2025 11:39:46 -0400 Subject: [PATCH 16/40] update test workflow to build first --- .github/workflows/sniff-test.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/sniff-test.yml b/.github/workflows/sniff-test.yml index 605eee0..11d2e38 100644 --- a/.github/workflows/sniff-test.yml +++ b/.github/workflows/sniff-test.yml @@ -30,7 +30,10 @@ jobs: runs-on: macos-latest steps: - uses: actions/checkout@v4 - - run: cargo test + - name: build the binaries first + run: cargo build + - name: run actual tests + run: cargo test format: runs-on: macos-latest From ef728473b717ce78f696e9b764a979a8afe7f54d Mon Sep 17 00:00:00 2001 From: AlexanderPortland Date: Fri, 24 Oct 2025 11:47:43 -0400 Subject: [PATCH 17/40] make snapshot tests agnostic to install directory --- tests/lib.rs | 22 ++++++++++++++-------- tests/unsafe/axioms/raw_deref.snap | 6 +++--- tests/unsafe/calls/justified_call.snap | 2 +- tests/unsafe/calls/unjustified_call.snap | 4 ++-- 4 files changed, 20 insertions(+), 14 deletions(-) diff --git a/tests/lib.rs b/tests/lib.rs index 3bd0c13..5f770f7 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -71,14 +71,14 @@ fn snapshots() -> anyhow::Result<()> { if is_cargo_project(path) { // Process as a cargo project - snapshot_cargo_dir(path)?; + snapshot_cargo_dir(path, &root)?; cargo_dirs.push(path.to_path_buf()); // Mark this directory and all subdirectories as processed mark_descendants_as_processed(path, &mut processed_dirs); } else if has_rust_files(path) && !is_inside_cargo_project(path, &root) { // Process individual .rs files in this directory - snapshot_rust_files_dir(path)?; + snapshot_rust_files_dir(path, &root)?; cargo_dirs.push(path.to_path_buf()); processed_dirs.insert(path.to_path_buf()); } @@ -127,7 +127,7 @@ fn is_cargo_project(path: &Path) -> bool { path.join("Cargo.toml").exists() } -fn snapshot_cargo_dir(path: &Path) -> anyhow::Result<()> { +fn snapshot_cargo_dir(path: &Path, root: &Path) -> anyhow::Result<()> { let name = path .file_name() .expect("directory should have name") @@ -138,10 +138,15 @@ fn snapshot_cargo_dir(path: &Path) -> anyhow::Result<()> { let out_path = path.to_path_buf(); let out = cargo_sniff(path)?; + // panic!( + // "root is {}", + // root.to_str().expect("should be valid unicode") + // ); insta::with_settings!({ snapshot_path => out_path, filters => vec![ - (r"process didn't exit successfully: `(.*?)`", "process didn't exit successfully: [BINARY PATH ELIDED]") + (r"process didn't exit successfully: `(.*?)`", "process didn't exit successfully: [BINARY PATH ELIDED]"), + (root.to_str().expect("should be valid unicode"), "[SNIFF_TEST_DIR]") ], prepend_module_to_snapshot => false, omit_expression => true, @@ -153,7 +158,7 @@ fn snapshot_cargo_dir(path: &Path) -> anyhow::Result<()> { Ok(()) } -fn snapshot_rust_files_dir(path: &Path) -> anyhow::Result<()> { +fn snapshot_rust_files_dir(path: &Path, root: &Path) -> anyhow::Result<()> { println!("snapshotting rust files in {}", path.display()); let rust_files: Vec<_> = std::fs::read_dir(path)? @@ -166,13 +171,13 @@ fn snapshot_rust_files_dir(path: &Path) -> anyhow::Result<()> { for entry in rust_files { let file_path = entry.path(); - snapshot_single_rust_file(&file_path)?; + snapshot_single_rust_file(&file_path, root)?; } Ok(()) } -fn snapshot_single_rust_file(file_path: &Path) -> anyhow::Result<()> { +fn snapshot_single_rust_file(file_path: &Path, root: &Path) -> anyhow::Result<()> { println!(" snapshotting rust file {}", file_path.display()); let name = file_path @@ -187,7 +192,8 @@ fn snapshot_single_rust_file(file_path: &Path) -> anyhow::Result<()> { insta::with_settings!({ snapshot_path => out_path, filters => vec![ - (r"process didn't exit successfully: `(.*?)`", "process didn't exit successfully: [BINARY PATH ELIDED]") + (r"process didn't exit successfully: `(.*?)`", "process didn't exit successfully: [BINARY PATH ELIDED]"), + (root.to_str().expect("should be valid unicode"), "[SNIFF_TEST_DIR]") ], prepend_module_to_snapshot => false, omit_expression => true, diff --git a/tests/unsafe/axioms/raw_deref.snap b/tests/unsafe/axioms/raw_deref.snap index 24403ae..39749c3 100644 --- a/tests/unsafe/axioms/raw_deref.snap +++ b/tests/unsafe/axioms/raw_deref.snap @@ -5,14 +5,14 @@ exit_code = 1 stdout = '' stderr = ''' error: function foo directly contains 1 unjustified unsafe axiom, but is not annotated unsafe - --> /Users/alexanderportland/Desktop/research/sniff-test/tests/unsafe/axioms/raw_deref.rs:3:1 + --> [SNIFF_TEST_DIR]/unsafe/axioms/raw_deref.rs:3:1 | 3 | fn foo(ptr: *const i32) -> i32 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: reachable from [main (/Users/alexanderportland/Desktop/research/sniff-test/tests/unsafe/axioms/raw_deref.rs:10:5) -> *foo*] + = note: reachable from [main ([SNIFF_TEST_DIR]/unsafe/axioms/raw_deref.rs:10:5) -> *foo*] note: raw pointer derefence here - --> /Users/alexanderportland/Desktop/research/sniff-test/tests/unsafe/axioms/raw_deref.rs:4:15 + --> [SNIFF_TEST_DIR]/unsafe/axioms/raw_deref.rs:4:15 | 4 | unsafe { *ptr } | ^^^ diff --git a/tests/unsafe/calls/justified_call.snap b/tests/unsafe/calls/justified_call.snap index ce0cfe5..da4facb 100644 --- a/tests/unsafe/calls/justified_call.snap +++ b/tests/unsafe/calls/justified_call.snap @@ -7,7 +7,7 @@ compilation successful!! ''' stderr = ''' warning: unused doc comment - --> /Users/alexanderportland/Desktop/research/sniff-test/tests/unsafe/calls/justified_call.rs:12:5 + --> [SNIFF_TEST_DIR]/unsafe/calls/justified_call.rs:12:5 | 12 | / /// SAFETY: 13 | | /// - nn: pointers from references are trivially non-null diff --git a/tests/unsafe/calls/unjustified_call.snap b/tests/unsafe/calls/unjustified_call.snap index a622abd..c128aeb 100644 --- a/tests/unsafe/calls/unjustified_call.snap +++ b/tests/unsafe/calls/unjustified_call.snap @@ -5,14 +5,14 @@ exit_code = 1 stdout = '' stderr = ''' error: function main directly contains 1 unjustified call to unsafe functions, but is not annotated unsafe - --> /Users/alexanderportland/Desktop/research/sniff-test/tests/unsafe/calls/unjustified_call.rs:10:1 + --> [SNIFF_TEST_DIR]/unsafe/calls/unjustified_call.rs:10:1 | 10 | fn main() { | ^^^^^^^^^ | = note: reachable from [*main*] note: foo is called here - --> /Users/alexanderportland/Desktop/research/sniff-test/tests/unsafe/calls/unjustified_call.rs:12:5 + --> [SNIFF_TEST_DIR]/unsafe/calls/unjustified_call.rs:12:5 | 12 | foo(&raw const x); | ^^^^^^^^^^^^^^^^^ From ac34e4e2c55bbe8a5a2018eadce3b513a0c4a7eb Mon Sep 17 00:00:00 2001 From: AlexanderPortland Date: Fri, 24 Oct 2025 11:51:11 -0400 Subject: [PATCH 18/40] no color --- tests/lib.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/lib.rs b/tests/lib.rs index 5f770f7..e8a7492 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -219,6 +219,7 @@ fn cargo_sniff(path: &Path) -> anyhow::Result { "RUSTFLAGS", "-Zcrate-attr=feature(register_tool) -Zcrate-attr=register_tool(sniff_tool)", ); + cmd.env("CARGO_TERM_COLOR", "never"); cmd.current_dir(path); Ok(cmd.output()?.try_into()?) @@ -230,6 +231,7 @@ fn rustc_sniff(file_path: &Path) -> anyhow::Result { // Env vars needed for the single invocation of the driver to work. cmd.env("RUSTC_PLUGIN_ALL_TARGETS", ""); cmd.env("RUSTC_WORKSPACE_WRAPPER", ""); + cmd.env("CARGO_TERM_COLOR", "never"); // We have to serialize the default plugin args so it knows what to do. cmd.env( From c1bdcfe867e1bb9cd591a760c0e917f644c3be24 Mon Sep 17 00:00:00 2001 From: AlexanderPortland Date: Fri, 24 Oct 2025 12:01:15 -0400 Subject: [PATCH 19/40] remove binaries and don't do codegen --- tests/justified_call | Bin 437488 -> 0 bytes tests/lib.rs | 3 +++ tests/ref_deref | Bin 436920 -> 0 bytes tests/unsafe/.DS_Store | Bin 6148 -> 0 bytes 4 files changed, 3 insertions(+) delete mode 100755 tests/justified_call delete mode 100755 tests/ref_deref delete mode 100644 tests/unsafe/.DS_Store diff --git a/tests/justified_call b/tests/justified_call deleted file mode 100755 index a4010e00e743e5aeca2aee2580be0730794fcd3d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 437488 zcmeFadw5jU)%d^9OfF{QztV|M6`YT=kJl{ z8P3_awbx#I?X}ikd+n3oojCCE5T!K5KO4W1{HE$kJ*L`uQ))E7N`5sp*STiSxMjw? zxsrSKKeO@KS)WJ=oE>yfQ&Tp)islT4_xxiPys6OvNjm=DVA#OB`>v&DCS)+YcRUun zn=ZGYNP5sr$AgDn_uchC!(F%4G~D&|yD1qAujrQ+yg!Yynn`*vPVoS1YHqKu`T9L| zciwL04u+@xXu&&GA8kcCe#EIt#Y)Ty!p8xAH8s;+)vlU~xpU@Q+zh{3d>n-n^@cpDzvuS4+iLEwyGNwJV0eFWTkxKa zHk5QcytF|82jE4~91O4iNef)L?k6QFv3MEhHTeFS<

csPqB%a-1I`<-7X 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

@U7)kP08`zH6~tCnl?O zvwm}~)t>LOnd!y~v%U0PNqdoRW`55FX1yl%xmEB}ne@SXJ#~;LAshWWz%3md*4iAN zwCla=t#t!^$*+UH=98&A1^Et-j7{v-44pM{)ts(e@|RaQJaYF>4Oi9h+PolZCI7MO@ey%8{VZ!{ z0&8X_Yv#-N8y>rke0%3%_;KmVLQgvSDgd8mjzsQ}rP z^R$#D8oVnqTYP@M{slIAsuR1}j-Tk<-*pKV{^kzZf0}&_Ro9EpXFp>NEQsowxyTK^ zOC~aANhtDMOl~Y79vj?V(J!;?E79AvKJ+$uit$SS;fL|%c(H$o%Qe?|bBd?9*y&BJ z;?CuTsq4Wv6u!J|-3uMqW5~H+vg=1>cJv@I*k=71F7EU>LNC0?m?kI-hRbD4%+TH3 zQ8#H)AEgs>-q5eroR_BQK$I(yjA zk7~Y$*jMW6T6(BrJ^Q2{t>4a5+NANV#o8Zfo@RJR+O45o{yH_e^$pE~?XV?CJMQ9# zTE2t5g}=IzXAyRtgV>qk%i8{ur#TPl+NyQ2dKJ%8k2PfH83cY&L;Zt!&Bcw)&j}Bu z`C|AzDENI_P39g=deMdD#l@T#^<9OIXy(r32iz55ju!G1dtf#?Ue4+!fMZ~`Mc0-P zWyI;+k?8DdE5IHsxaP$EzDV`8@N6+_a5iTeI^TfWb|-Pzj+-8;K#$zZUAlT=&-1ub zA$P{V0n9LaY|*Xq{W1lPIrz5z@@>usS`xhJ$bhulxHrH)PxPA;8}i18YwzDUuh5Yx zt@HKu;>XHHciArc&N|ui97JE}4?CZc`^7r@1>}AI@i)G^?iPFIE`g(ihqMjMv)bmw zwe`oft)y-5{^{QOHN-7}QwO$;gLc7rj`hXJ6p@iO&S&0AvSg$w8$HncU&zHH$d0wh zM3Im2vheWz_$QEs5^rC5CA@(g5_!~zOsrx32EeE3Q{+)hwhop{@$ml&{FtmQpYnf$ zKNzmueL_CYs~YWG7Gw?IpRo?KsWg57KBF^A_!R&8Uq9y#Uu0^inQ z|8@ksG5b=!vr*1|obhVdKDL!j^R9un!q6%_(P12!;xNL;Z(ByZ)})ape%Yq~D4BQp zmaO=X`oZNYXjpf@_!D#SA7%Tl0*25=(qiMgH<3o4F#aidS=^CD#y`mYb%|}pm*IB2 zTJxID{jr^oJvndj_)Yg|M zEVUNjd6v{uk0Fo2&o+AJ&Nc+r7Y5CF59>WP=NkL+Rm?eQBUqS#9*E96@=@kJFbaR z#?)NsQ7+~bJY#eEM|>ZLmku$GJTSzleca_eT&Rrw#~YWK^?N6Ig0w59-Prq-XRXj@ z;~Zn(i*t=&)b^n)J7U{yKiw=nb%jdfVolMW>bE9eHAy;XpqG-NOuv z#*;jGkMP~F=Y|=P^}{T?N|kzgp@W>6H)dh8Zk%g~4k;2}1vW($HU+wONda^<=QMwk z=dMKb0BuBezRY-7*K0(V6lqqhhju)k2MRq0tJGS#^SkfGxyJrYbB&@4%8S_(Pg>lB z-++5^qBjb8&gNUtF`d!D{bbR_3-O-~)*0LJdwiD8sQkXuD|%b@4MFzZ5_49-J*LCx zd2wrD7@f+~;@Bd9{?>~RTclBCJdy`vB{UOo^NvDz?PI@ot zKaxKDL}~BwCrbT)CH)@hlcXb0l!|WZu#e=M4Dg75lE;*Vs?75ObGVV;v&`WU<}0>8 zlz#KM18vrK=JIV-cn4n43ZRFRI4@{y?lVh%S*n%(vedunvC`g`A1hTZ-ZwwSzLT>Z zzMVD>J`F6n=B#*%UhY5-tVj6uN#^2m>c!TGi+TOOu8~mS>^1UF(&>zO1aJrQp+8zS zm`651?*Y7;3O!#3ufe#VRR`R^N}U+Zw8hwXGiO^ok310B@GBE9OU_BUhxB0ibQVnP z(@J2*Wc70&Bd5gH{ulP|Cg85%I}r=NAE|!c2FB`dH2UeDfa8IzX9jvyzhFvv{HN<_@g$U7uoMT zt^5~w>ft;60?lX}#+ev-OKq2UYPr{TJMcumbB||j{a9?&M07OcGGznf6raF#)LD_K z`u8nR)te>8jJ*54sjp{$|FrlVzFp4#5nU4V5lp9kypO?2I^M@Hjr0-rfLqHQ{o<3E zzdg~2?b}8|uYJUnmFE|j`-tM7(w4FJqT^)zmk6u~}AAt$lr`tv7Ra02MUzD;usfg!MJ3RM47(7&cs^$$VT)m+H=4&RNbxr~^@ zQre*NiPh`c8F0_r`S=g+c^mv{*z0!>r4Dcvew~{0RKGTjx}*6fh{L(8%HO!S-kKF)Zmk1WCdV2tA5v&}lgivweES9s5i#o09_ZYvrFv37g(L|e+34R(h2k$O9!%yw`7Ttr) zLmBf>dlh)W7aMrS`f%|c-^Z>0Mjt!azsGxOXGESYCuFAM(tv3X)s^|EJ^vzNfj za}43-di+em&2!kht1W%-)+}V|!d&pejw#|PHqBRvGn4Nj30`lqhT`G5kkPW%;^FlH zZ@j<-p7;dzXTx9EI~_cQ{?mXbzIycY9)T(6P7e0RJM~BREQXh6!Am}PNqjT`_;3e& zSOg!o!iV`<v%=PVg)H`%e9zAW1^Zh1GA0r^4Z3z6|84$ML8Ri^CZ~=^kSFoBk!MGoZoS_ z^d;I9F;Av06+J38+{xt00=o!5g&$nQ;ODqbd35}RLFtcrC%`x6Lm3BO`{}=u@3(Kn z=9RT3Ht-m`=5E?-eP=V~*BL|Irc=q2B?du!JH6QDRroyiWBFyLT)F#N zFW;$(^YM(v$5Uw^9a6>RCn~Ui^(D(pzfP~5eQ~Z4!^uWJP9u5pDf*epcll#<(5NTh zE3m;E1;CHZ-%U||8pE@Q`;-;(ogMJfd5X;7`=i7&jv;QsvVXsftu1z;b`HCu7M|S) z-S$JnSpDlpVpj-lv310*kaLsnB))aG=}~NpM@zetDmwj}dH;#LpYgYLC%HQP8_9q1 z(b51q{fr&q@azMZa`dbzpLuSvtF=bdo)AA$uY4B)-8aR?{5(b=;o6 z7T$>M8PH+SG0XS8A+$+y8NDekV+rm2x9Xk?frC@n@Q=l&K+lU#y@|5m#tLsRNizZ| z{HW(&fsSo?qg3%X9Q;r4bTpNgajxcPzua5Tw+ND1xAP)f>h0`jkWY2+viP$l=1iWc z?2|u09z2C_`z0;K{kwwH^#|FF ziByZvsI!ZoZVOy={PE_w5`JviLoepLp{Cu%7`5nr<$T6z?pGup zbOkn7%Sy(DzyAqru0izNz`p0l@R-Pm0OL3&HaI+_fEDA@hUi`K zi^lk|g1?(0>&VXYTsmu(wC_*;q<{1yxzB=sl;>doXgX^r)=$Mj;3G%uJO#eqaIfVb z{ZQ7?8UN@P>BoP7eo~aD<3MCfGrySJE##b4`U>D5ophb$FBSPa5&0VrBM%teAzfnO7k80v08fvyd%7B+Md{5!ke$s#=q%Ttgl~{`XkJly#?Ey_v9Ar^0W6@ zOa3nVzcc%+MWoRmYl84>%m*O8w=?@Yhv&l?__FwZ_il80yv}Oc3BQ4-=%4$*-?T~n z1>g%^8B@zo6Sz6?F~#GXy{ z9fy{T-*sqHRp3yumbx>vYSo@4J6}8$O6)$w8THN(c6PYdWgzu$a zxeGTnHh#`A^TA#GbvcYBpExqHTO0YA@iwfX!G5bGb573e6>X%y{u%X8ynpr{{ut?n z(fTHh@ber|@C1E{9=rnnxP&Nhh8RLhpK*w*1`3SdDSLiEc(D*FhQ~^A2hA#^}mGGr} z^GafqrM|V-y2R7Oo-GXgCiZMUf)1*XzgLke{aQHmQ>I#U&nBS}xI9BTR@TQmveNSZ zakmCKtgUAr?~L~GulyW^;3R9##dqYz*Etqm_%FsJ_Q#FD5j<70%g|C?#_#AWeIa@T zd!?0rjK@{j+7t4f87KE)DHomNNY)HJRWoAxripLnioR*$8@Gc0Lh4!cl9(es)SaTL ze`33}2qh+GUq~93r z)pnDHpLTJb1;?2H~_PnsiE?1{|(f&Ij)(nme^&<@6?C+coF z6OQ%ucgpX*vD|xaOVLAJr z)@R4$&<5vxlg$t zUSnUm_SiVhI66Tyj$Eo47&gYSDVh_5c-4rTdbTJMrbhYY&En7tmFfjIi51cUK@Mm(2B^Y+-&DR+i*ltC`xmM zQ5@>lawDB5KT;SP}oe=yzl)?A$9m`x}9>Zuu5S*N(}opER{BvQfPj$y5B@ zGtv`ONuUBBDc=wKdIo$!{NfH`V2%)L+?sUedlJubzV~g;_jVwY>P>xh?r$&rV&B>J z&QD46T|MFf@dIQz&F`T3?at@VHiFr_ByTSh= z7c2O^&l(WF<=?G(uZsMveOHxXV4tzi2sX=2{Wv0`7_X6WHWu(2pjG^A2I*Pvo$$f??%4lX^Q1IOZ)?b?MTa9Y% z)BFP8QijeQn?Osn{2i-&5oI&@nPuaKd(F0|tg^3>|D}PlVOH5U_*-1Q@QMe@QmwN3Bok&i`C|vlQmnFet84-JxdUYms|=YcxGW(b z13EeeJqpt*D`&6uzwF`XQXVK%MmjVw$M}I&?jm2}%8%Nc*JZ`Z60AONh?a#Z8yzdV z*eV+mEjvM3ZmjGbtL*Y<*)ht-#L5zq&Dd(e_w+ZA5m|U((lkS8A$Olb$g93@vEP`G z<_%4l%P*bZ9DW)6uH~1>?;3tt{ATmZ<~NJqXns}va`;v9%k}n^@g4jLW4y-~oaZ$b zp6@-mB+q;DIf;oyPGc(uu@wWu=|7L3-BBXGm%;MvM7(3{FCc@gZ%b^vM7(3 z{FCbwc;6W)i}HxcKe@gik-ui3EXpG$|K$39L%w^UEXpG$|K$4qO8%n*Wyx{;lj{@y znFIf9qg?K`rN!pcU+Kj&8HY2nN{z>CKOWxt3T;B8K z9X=}LeVn`tFY$h$S{rox;21Ye2(`G$l1X51navJJ$BE7F21$Qn(@QSzm+&E`v@}zqnA3iLcRru zeiQv7G!a_F;1~QO@>~`0j(>}N5_WTBBmDm&yuS&1<;Du{sh6>BHk1B|W?X?E^Efgx z=40XB(H`-2A4ebj1zmbe#dzjngr|4mQ1kBsw@(C*7q2UkxTRXot&gRa8z1R44z~g9z(!&nvDsu?e)~{#a*pqrg`DHP=wh#s=FYuYdF5V57`%?seyP~j zry^VPQbj&x`HmwaY(78Zw_$&Q5BKv7gYOL;+n((SuC#lCiV{ zMV;RE6I!kpb_Kx1ZmbbFkpI>rQE7d|ybKI(Z3oI?q!hpX4ci)Mo6vA$IN#NAWsBA1{H!_Bgzp#J?O~ zsEnQDiJdKVxAE>zzOnQ0LMPu3Rh@yQ*odQ)accgMWr5eZyRu-&vhaTR{-n*QPhk!g zW|stZxr`MtUZ@!6>EZ5GLG1+3d$%&?-w|(%?Ot2xSl`P$*m&>e&R0FW5s1#?^VoVp z`;c8B`VT^nzwviF1Sf0?(-!W2BhmA?6Iin=4B{*MoBHv0Jy2oUQOhfgIWne}3hS=P z6BR~mzvqaGutR~Vs#6-M9zvG<4U;@dVx;BNEX9Vk>rWohMJ`PM+?dD)`^ zm#VHBm#b0k-Ujz_FG|M7kFdvE;xcSi&MtE;u(tMZAMUwuEPTp(2t?Nd-$Cxre~RQGz!0^s;`3P6+Ca|xr2D#5PJS$WXqk%rOu$kgWqk$50@=|aEW7xyH?A4S9}@L zzUdj_=IqXrrP!x?qkZYA^u^iuhcmHv@dru28hgk1ep}qC`h5D@$a5OcqGt#7>HYLR z{opBmil6ew(LRG|mCN$J!{2XVO%!RZIf2(zS70+|@fqBKg9qdccoTJF^ewwt^$XwR zL$k6v)i1VF9q&PSp%4Fz@SL5yCw=28y!s>DE8#q8JGjbuqkPY!?^0)1jh5f&lJ<zC!~qZskV-7TVpob43-CV=?$tN&y}^PV&&c1pF?kezlsSf{j4R0#|F`@-7x`9> z_^7WSPxy3FtUi2e*0(F;3$Z--*~}ZRxEIa0vyh#RC(JYGt|0iw!y8Mv>}87|H|e%a zmozwgA5+zjLKE=~i0myU4PCp6={qPmrozkMDDhcl`$q@0Z&B6v#^`w;g5*4zQR%{TyWA4tY_NaY8Qi>>lO z8a4uU%7+W}Wr0Qdve4cUCGxjM{T0K}lOsHdBFjQ9kB=Kj;JNpqVf_oxy?2v z^aiqfGUIe1V+wc%wsA)*BhAgez}rB2BKXKRRQOvz#;SYqZ*l)=LS35Y;@f8}dkQ~S zevh^rAHbSU{8x89<_x#lhlM@_@3#xuZs{ygyA^-8o_ivmxA}Jcd&skH`WyD=$RzPa z_t}T|0*(B=5&lkg@qd>iOF18=FOh4)Bg6R(T(=}~wt2Uu2;bXmxyRM8 zB)o#MUSe1-8JXh#fV2M)cky;&Ppt;01H|XQG_)rC9(D3*lgC_j6MIlJlKau~m1$1~ z)^i?6y&}GQlSjQCVrYWM%UcsA=AHYg_YpUNEwsvRbBnAKnPaRcZ5 zLGGCgy#2%yZ6hAA0^6?R1m8q~@7k9DueavGt)tZLq8ZKyxwm)*p5ttIB{Jv8TKT&) zef$Kb+^3a$wH1qidFYWf(4xPcdnJ{~rP;`(dY3+aw&v`*23fTP*;Kzl_j!;_tjpbV zv4tv2saN7GxrTUqw<~r0EQhme7WHOrNcHIjJD(B1mh_dXjr6&Rwe4qoWwsIKw|(Sq zLEVsS-WlK1XV2jKP{TsoIoqF&Yzr;q{FSHJMN4i|TRv!Ln7TDZ?bi7_AH~okRU6`S zL$ia_`M{*vkWf1`JBZ#4A}5G9+4RQOC0<}esFkPKq6aJRO&*GD`DlVNK4kxN0DXHH zxi2>MtUE0m-@kpRW&gB~_q<=j{stb5tzUubU=2S=U4bVyu&kK_+h%${oai(@LM|_3 zOyZZ8vB=+c-pKkHi5(~PMXpI+U>tiJ&Y)#~TM)#C0|&9)PN9DS>-oK!Jo$X)s?|0; zrIq{VflJZ9!!7;!0=y>m&j$w={O8~)zA9;Zo!MrX)y7U6+NDDu`8&`1z(d-Nka6nR z!^DY6n+n>T)qm7R>+X~@XYM&-_wNJu?JG6U?(dsEIir>FokE_RV(lf zj8w<+|3B8=JU;5``u~5=OdvB^Adro%O#&!cP(aqyP$r2>5^#gK+a^dqAG2s}#0A7Q z39&U8tq!2JU_S(HYu=-%tx%IL9};c*0pkW#?fM~z{Wu|7jcggf&iDCx&%9xX!P?*B z_s2Zu{l4$JoO|xM=bn4cx#t>g))ZoJl%ON`@SKcp`OwRS!AB0P+A{~5=p4@780b#} zzbdqR+cpE=N!%NGzVCv23-81d>nRS$2OW=3IYwIFp_d)OZRj|cuV!sv%!S*-*jCja z@28>kN4O7adzquoaTVv+!K?V3zRh~-;<-D-3nRFG;is{4f6Kd#zmww(-aJ-0G_!x%j-RI+D$=<+=m@;(5M57NH{>?_{A$SBWeo_&S8(B1G1 z-IW&S^0X}E9CAHlUNxh6LrG)CKu%-$zIfpvgR?#+<2fEYg>C5LExXEo%KHCCOsXr4 zt>WK`;c*%51tRix0D1c@(xv+=z+P~IzJ*A;gY}UZN4tsTuvq(+{{!|$a4h?kIfOiZ19e2pkdDBo65&_ zx_$THo2omXj)QycJyc$M49W89dy(n|C!(_+@ah03^OeS)wGF=v`5T-g9FV6(Hl7I1 zW|2p+D`wH>F~|kNiEt)esGY9%P5|3MVAI)}o%G#q8$a5uZs1sjFRc8QWY^k{o}&!> z>kM}#whHkI^w@6}Wlr@OeBa0Sh0h|7;#a9M$-ppy^x4qISD=scp$`jg^@TN6_NX}W ztRT)@Nd~fBA?J8psmOjF|G+xdu*cv78y&%eoA|Bv2A7aeu&X~I*0=%IxDYaZ6?^Bl zDRa#2uJnOJ$RvLPru?R_ZwDs6*R79 z4#uW!X}|{1^Q(sWYgS({(7VbJmS@-}1lTVV>kK`eld?|yrmiAyBjr|;9~;T)rh>pK z#%XoTKo4_psdxqLj?tNi@yJ`OPrCPS9Q{4A-x-w5RB>{jDOqZ)|Np)YtsqBvm!*dH zm%yL>ys=&}Mvl=>-SrZUrxOdMH}Uub7lVgla7AAwo7gzgyCnzH=5g}M7NmSV*u?z! zVrf1GoZ<5$htS=K?`Td)ChJ+2;BzuBtY=r8@6a&i|9E%rT=|39{DU& zrUBnVjr(ENq~o$-#a_Fm(sggaz}4tku6G10n;Ht1HZ>Mhx_-}nv8xM?PH|ZAu5G`u zLe|m&%3ezymDsip(vQmTjo4C&eXH_2@ZJUJ2AtG0+{swP``$$#u=6?Q=3c(9eXziN z&^u6dC-#Hb@-3C$i^WcHCI4=07To`gZNf>M-QSRZrBnCka@OlcSAL)Z`^a_4W-oj) z0Dh|{rkHmvPUY;-W#-*yrp0>4YyQ)bN?<|_mr(r*UQMUF$qXr(_N>pP!x#X?csLM!cY`6*2BPlN|LW5Z<* zMf8`}_a3+J+(=yqNw;kg*0%{B-xR)0;uqF2drT`mJI<=Jfb2 zFVW`T(Fb0oJgXvk*w{2)(zi-dRw2 z@WFxxM4i6IIJc479F(rC{^wZcDG$y82a~U*oxe@lW#2 zr_KO%X5@s=KdR2w+wLuho-f6~qrF!Tw5z%HEc2y=v>1HI*KyT2}J^Y7U zS)XgS4m^#_aXoj|BDV$LH@(1VelmPOedsyL9m)}Sdty_z*zoqmrfxAmxoE)r#2Dx~ ziY{d@ekk3Y^Q)I%N*a9YBg)0D+VaH6d$zdh?k#ZEH5EAORu_P&f}W2$=bN9PNBqP& z(DOd!-tU~R`DA{=olO1I_fR7~Eyzf~qPcU7bznICJNTFpJi4dUJaX`2^Kf5@nFSBi zdVB(zZ#=$N?=g-mz`fRkjH|)D&du44?4W~2PF16S*IRI z)SlJtA7Lc6bP_YYb6CUtMApC8iEXl_(AZV)7|}P0y;LIKdAH8EeMntT&oIn|yu0~n zA11$k@8VGT`@p3&%z^H^?-_Jxz;q>WeuB(n!MofW)EO@8d4V@Ljc2WY3xN3v_9B8g zzRB=?2(R*_k0qW~y#HzTw9l|Vt7ktaS@jw8ajl8q9UZu0%_h1=w6x-{**eUzWdyK4 z*ZB2;*Bb@s{a7q?Kkx z?)+ju5>5-}S6%3L{3qDssEt(iljA-u*@Mq@`fT(P$JjHR;7-pTa9u@x*a`A2*rd-v zu3QQ&sJ_R@Z_8_fcOCB={#mkT<3BIoBV9q;m&Po~rM|!Oto+Txu?6$2^;Z6SvEMM( ze+eJihx$Oh&E)?%aU|DnD3NZPZkx$-A_i8R$&MEd!>|2OX= z`Bz#GI_G?3!asP7xncOmDJEXZwn&+9+Iau3@tG7qnanrAC?25lMx(rz^P!-R%kchACf#@)6IoP2awZZwUJW zrC&?>?XO>m9VvW=^u54CpSHS*3$oOb^}{}F(f(kI{`^`0FvVfqL*0YR6;i+AHcq8~ z9{OOPC(yoXC+$Svwdy90T#m=nl7*h{plBZ+B^ak$bto=gIKHm-&gzFjEEBsQQ-Dda zQ=;or9jDZZr=)$jgK4*#9TtJ| zAyxvH#%d05$;a^Vr$0-J_+W2M&h+@y*A$1N`%3Y3JX823&ofrr z#Q&zv0YASX?p#z^@s2j|)d1e?xjd1+uDh<#dNEBJF^ogx_4U7{KcAtK_A}54dZ`oh zz#FlcFQ*5%xFa0m4r0p}KPUro$W(In&6#(ZdI ztXlCSkCq#*r~DC%_nyAih(;RGLut`%Y6c1&1RH2mKNp>euFo zAA2kC$Y1mPNWYqgr$qW?w|C0#{5;wcJVVX-6mWVwK0r23w*k|mMNv4N=m@WG$Qe7F z#GjE5JutBLZruS4ZSV>UALty_&vf9~0Uk>f=MkQ3^N>-bTYHQVr{h1Kbn)R5(FWzB zaXWbZHY^(XES|fdi8JDnz3xdo(ih>;OJCX|ebIQTFB;#$eR=Pl&|__pzO+X5<$p<6 zUz$gp8Ru`k6UMpbR6u$<@m2n1r!WV}YdOP^)xe*|z?Rj1M;oFYdrm0coZvH%*=(Ht zI?_fo@6(-0vXe}9dyjo~J$CrBd!Th|{k;7&U-C+4tnaUL;eWr>JRS56p7|W##4`_B zYge-0f!;BC{{9eHZ2r7}FDd?Si-%c#O!mJvD9@Tmp4-WDxjFRuv>DnwIX^mw z`G{q__9$~iysfn;W|!*RHZj(sS9r2DXWfoFt$sR?X{3YIx^fSFImGx$clvqq;y38i zU>ejslB}rqenxw(H-_g&D|0h7GuEdy%U%x$*MGUy$29->^f8@2Mvt4tZ$D?vx-5c! zn;zDp|5-z=5eb(K1fZK}Sz;-$3Kx~C^IgSJ4D(&>#jQF?ga27;L=ts= z&?dc^lX&>2?w-;f1bKODT&vgAy(tIqsR%vgBvz4pKf7@$k@8m)$Lerjp_ zXv@MAX}{EcWULpzr*2|Co>n(-2Ltp&a12$qUtLbBZB++Ptb%fXXQTMxtSakm@! zqUE|dk@kN|`>SbxC?2n}$&6DvdL^}K%WrAOZ$GC#?QbN%HNykNhizMx@(#6j{ny(= z&kOBcZ5i&5mJFBX-$4C}t0H}a>fa$+JZXmu*MI-pf+5v^2YtALK75v!13zcG4nr?@ zvNl<3J-l3d74h;fvM$xp#!%~0E$J372exeb?oPDNf!TdOwT@O={XX?BUZ8m~_>Ljn z7kj7}T-Q5HbRrMy{%_r5cF7v_w%E~;CuYs$tlSR1xf@g1FQBvI9y`m&Rd=)F-)EKU zOd&>&;kyZ(WTIQE8Xi6?V!+#&H@h`HL){tlMeoU&YT+GTj?PcxoXxvp8}`H+!Og69 z%z>@;U4L1F@_vbTVog~-RI!YkXgomQswmR{J#S~vAovWv{q?CckLg?B{7&*)W4fAs zK4U80y@Tc6rG+Lo5OF3Mo+z4V^ysC6rJbOl>sdPM+11wCl75mu z?9luj)Yb;ZMDzE%(CJdfI-0*)yysrx+Jd+3$GL|kGHxDpHDO!4J zc&qA=UeIcLP`OoB+bRD4{2adVNHmSz7^X4F(u4O1Rn(1#vK z*XNyEN}h!t7(XPdFY{OzxaUdtmq|92elZ>SZwxy5U|-APW8g~j;UIn)M~fW&4fuR{ zV}DmL=>7oW-gf@kO`LxBr$u|l6CbtSmD<-uzl3Z1&Xrp5VsIz*jrfc-;m1kEwdzD!@)F*m*? zJu{m(^fLx(<0Jkpc3aZ(9>vBlDv#r3^>F@6RY!!NMu2tMiD6ni-iySsd$$HDtTwFzdZ*1+~| z)Tx|zY{}hEfXh&5m?>WnWah;)@W1H23qLB-^e%m+{4jzGjSkN+{IBuxd-(!<8L{j1 zQAaJdqeW+J+HhcI%Z3BR#KtVvH+*#Q=lfu;5%jXpuJ{kEfcQTz_>!Zpx|G;!jhzJ! z?up3ao`_uTY$)63Am&2kJ_g1)9vZ1}+`pj$Us>XZ;5SL0zj@axu2xHcxLPHzeA4ai z`Ghg)Q>^mu(qDXu>yBYtTZYe2TB5h(5Wc%<=Nhv-@}na*^^+GG<$vU^gA7+(UkT4g zkk#nl?&PeZoblYZE8L~irz6fW)|uV)MZ|t{rSw%&f1u{}_8W=S(?cGe?~pG`47geO zA7PvLl&SrZ`AFB{`TP?r#l$3Sx2E7H|$Z z3;J($Id^GK?gIW8*3_$?l$?9bfcmCG9!2{@(a#b3({R4 zt(+rx2Rht2+MB&7Hq_>3Zg4$Yr1Nnm+_E~&OZ9ry3D!DlGPd#eE)SNQIw$X+;$+auH(K*oS`eQ+6V`IVAy)(@hno?-{s)2pA+za7w^sQk| z2bM{uby)YQ9>QO~8UMHgHxbtX|L%#@rMvBAtNI%Kvgf1Cqjd*^=H?^&L)$WeMR(5h zQZ^2G$v7)+V}P}-B1p^*>J8v8VB2iEsCOy#ZMq773*r#=F#i>k^O7>`;MAk^)ud}& z6iaJOjc4PcW%9QkXT=Qokbm{7)zL7&1zxsjDLjtfCg>n@AAb7yYFy%B9&l#B@-cxn zy!e$UK7jm87P%5z8hCF2FW)EM_fw7FEuV(Ae!mfalciyQll}1DOUTE&PreEDf(ifP z@cnej{vR$f*8h}r&buR@r-kqSq2EV0b7$dwi%j8f(veVkH~#V2MtsXo_E8CZpPHSp zQD+1mcW?*PS&rc2rOx2vx4422G*0$y!H>QWSoh*5ul-g$`QvipH)eCr<_7YYVFQHT ztvhms+i0A&l79!hQ887bZO3o!CWi0TVLe{Y^{4cBuaMr_w5MQm(;o_Y?u*&d+VoaI z&$Nd5KS0Ox1oUW+$?M!R{;bmAIde~PuOgnCs@ zYpe4AfV}ec>ACNMExmc1V`5C3xl22%5ns+}o%1srn+oQ!<{e;7%Y|0@E`}~xd-Kc~ zGxN1!=7DLXzct*<-si~wbk%jpdDkNEU4z_rHS*t8=80RcG?53beU;?{MjP3T#UaL6 zI+&*hz%O%1xVQVIbir09+%G&u_h%ZTo0M;eFm)0v=!bPO|z58BY!2k4mUKSI->XF#~q)Sa`WoP7VoSG zzfWZiD*e-@#ij4OcpK|bZ38~Y*89;HZ_5O}(w}l?!^GCxxJNC10W!E16P~(avP$o^ z$`f%UvM>b;8?lqH$$ z!}!mM;m(L)XjYD=^SWGkcU;5f+w!pa$o?;0t2G7wQkTgc1ngV-m%)oZfLA>@tf+lE z_ZU>t*FJcv@<<2qA~dMFpM=k;?&>4|x^6EqRNPlY)qP>1Rk!*WU3V*WSLGDqQqp-{ z2|w-&@AGDr94kH;vhE(PGQFlJvGdO*{PfM4Rd%e3_=Q=9huE2Je+KaH=REEf>fs#! zu7Qf-%v<$@~d%Fyu_M}J1tN%bT`w&;soHWXH zttPG~X*YuJV)nD_T}CVR$xq2kjFg{sf@ig*{j`%jPmeY&a? zJe7d2i{XP8nc&aje=}*v4Q-ZEUv{J0-_|r?pe+>o*xfb7XYN*{6GfFJrEy0?U`bXq{b?&RnMvuJbDq{%6@rfah223$#wy z?=SLxm^+sLK)+uY)c4^Qe$xE?)bZLAjAN5)*Rh*C^gj+f;G26{0(6rI-MD<6@FVdZ z(M`$^FXH~p*2SSo!^~#zf}e7S?uOR5+(q9iohjXojQ4Dw_fxlB&b@iI&*<7d(2z__ zTE6up8?(_%e%yB3MZt`q_Y>{U(a|AKHtc?z^tX#<`*xy7`r~T!Coc2_+=F;@nUQ}0 zJIEgE&Q;Fy!<)3mYL7h8!fV5B`_N?h4YyYa6XfB{G+!s_dAh|J|wQ(Le4wp#7Tc0-{Sr| zdk5Y>(0tou(&q}v^EaGU#N(<-hZv-X}X(|^8In7@7jKbZ%C((IsGJMaz ziEfznwx{WL1wG05Z*wP=&SQVT8h#7qbcf-~@Qs@ri&xhE>||Q)YU;fuF`=b4HKE17 z%?K{PqR_NriXksno#ik!2TIS-rjIst2MJ^QrspRYS$*>Sg!`^Gfp_|joL-&@4qMTy zm4H9w`mLV#xF?+aW!yP|+`p?d%P<%G%m_Lz4C}aWrA}fO_1`_gNZlS9(#Cux!O0jT@>5_&3wA*66kLcbhr?DEJH3SWllnetWRy^bMMQJ=<`p% zBb@p6W>#hnb^wQOIW(R-Pg8g02ccP`c#c7CO*f3i-(dV4JR2us z=Vn8HJISBjH9P;Wq_;vdhB4YVKwYxidG$U$+lL(TW|246m&M+HKHoBtLBxNwuIS(H zdl!9IU!}V~-zA>KeRseRjgQF@d??R(kvs|HvG^Hj=S0$CNejI!JBSy= zN4CLUeVFq_X>YDwoR-{r+c5I}0T|aahcurWBJ-sIJfoxNYh}Ld<(_(U(AK(U;dJSg z2u^kHO~Yd8-xS}V^*-4X9X|YyEW0u`_O;e|V)p)DG?rH18{)+&Cv70_^F9e&Y0TX} zf~K%J3-39bFA64X9_CAg)}Lj5#^DRk{&?-P%+rTBKb>KW?E8rM`4RK;b>^qel$N1y z{D^rPip5Os?<)Y`R&QF(|Rc}fMo9VmqSTnS}iSY^5$C&D)#)b7~cMZV{?c0?v z97N8L4Z@not!LwRpXz@SxT9?<0bo>I#G>iVR@-mTuI8HBW<1IzLukI|M&Q=?Wg#PQ zx7yEo(l?E>?fv3e(e=6;*tZx-{dT>-K101JU!Y#%^C0KBpwSp;br?JW-+?CX3q>B1 zTvI~46AyDJhx>F{b9}kTz6&{n|1^Gc2KrEUA@ONgJ9^O5Txl2_WhTx6xIBfw)9-$y zJ&Om=N-|o;(2uL>vpt5}ok{(_IPV81$4NSZ@6re1YoFEt@Ebk8T2tj?--!-TJjz5j zo(rsHz^e7QWuoD`8CVmHgueZhXPsewB8vmF)^TpT|75){`FjNgBSr zt>~#V_X@cu7dn>AokpL+Yk~5(kt&?VgYBF|xy2^p93XPz5 zOk{nRKDH;;Yx$4z-PiWd@cQn~H1bvMS(SU)z~6>)tDMXm?kT5?+F*Wf^Zb2zzQ<+E z(inRFJ~RIy^@8^|jm~M7JzKHtEjy#m%xmp|UuCf0?b7_wy2H9v6*-^U2(0pR(Hj5o zxf+Y``6S8Anx}EhgF-|1;^sjY*iR;N4w*d769sF-?ndZ%oztK%VcRHhTk}xue_mU6 z(3a{O0Dpu1J=9lsr8hqSUbXJM!+yZ(Ph@@1q#sLZ*8$(IWKL;MWw)=myGLFNr9Vn6 z%}4mwMm}^1TeVjdUN%S8jIdurn!oS0LF+&7s=M&h(6;D0#Va{OZQ07RSW_FRbD~G< zPMZJEgX(yjcdfmWlT?@T+Hk&M{v23|Z&44EU#l6;-;B1coh;@?u=cJ_d+*jBqpdt$$_YXS@x@FIAejc=U8aA;M~Fb5V(oBNzkp<(cZr#_;UI$TOs<* zbXEc&N8l8b1r$$_U5aO-dJM}>&__A*-pwSUEeEcZ!`GCo-mg&-o3-w z`H9vGjZqu>#6UdrVR-l*KkyV{esok1H#!)<4(V2-eOLx63ema#u1&PxlIzXyqn!$e zaa)|XVR3vXdg4*{kE89m^53)48yXg0HEPqiQu3vF8yBx}61VA&FOSA{ocn_~@5*vu zz_uFfa;E1>Ub_msu?Ek`Vm`A^{mdGi!g_cJ*mp5TZptEWcD%uJGkwht#?Ea9roaII z^t+9J{6U4+#qW|wbfK|PJm=p$4$qDEc65>+E$?_1aVM3RvV-{dX2z?Md27o_Wv$pp ze#HJP6z0=a@IJ|CA=fZ`6GpHH90~0tK|7<6bw#+jh|9LZ)=WGaT0WqTka; z>5{CqBBFCJ<{Mk5f(P$>WAu9S@ztv;IX=Q8@R@DrIoC$p&u)leL{f%Ux9QHO3u(#Qy^@TY(m39C6 z4r7<-@i;o)X6dj;j&GUwcVr%Gf6o|Vi!+ARn`u{m)l9i$foa><>G$);F1sj)wXIyd z{ClrrLk?})@n>QrkDk)Zvv;n#BX#Y}^G4{Q( z3HqMK{j$ufM*8GQAKy~q8gJR`YKS30Tv4-OWL%4reW7BDt!JDcTXp_G?~{e*MEui? zba%_XbZlFs%dV?E#Xu<5tS2sH5%_JU&&j0CHH@HeQ4(v6nscRL&bq{5y65Ww|+b_Ch}t&Wdawok18gv!hVM@oxP6E_Ku~V==4#f>wItu>1`Iy?ERT1BKyUe ziiL$t#u_jEgwwZ>z16L>xnocp|3ofYm0|2UwgjIu=;Q|IMfkV|e0Ut=`+9-T!Uy|G z;bS8B=mj5_55k96_`oJmMtT5zh-U1*zX}|$2~K!h+SQCDGEfOPI5?@)JbrbVc@(=@ zPg8e6&-jM<%g5tS^%S2ny z?{V<(_OTFqNq3*__+7EOc;%nJSG*E>>pza3wh2E6aN#@hWGwpx`NDbp8Iik=MK>eC zo!%S3{ZV*j#(1OdF#GGJ?3V`9$ln-0?Vrj-BeWY$CvQvUg--6K?K__s<{J-Pca0d+ zlHnRx`x5k~I;##s-?VXqYfSeeJa^*vBOd!l=;aXOoI=_=HM0ipOdHd(nz%%w<;t}2 zjCGp-4e|(IolfZv3(cJq9cC4NjvnrR&t(1XWnFUMW2E|iOJ1!hq6w9$qCV_u^HZ;I zm^OWAj#Q5r-%`dMUzRVx-+}LYu9fxpFikv!U89dWUE{iI?yee$|GRO;5_EtI8(k}f z%Uo=@6(4e6Aw2O>#%eH~uM?i2^8x5w{7`&x6?D-!GPxx+J-Ov-?zE}~Cl)@Cy^nnI z?L7_LU8a5IBN1HOPMX%*=Gs{U?{W^vV2)@H_Fx1Ltr0w!;K5DY+LL%-Ul7IvcOQ{g zyh8P4M{r@4OGd6;>@bDjXncs@M&m=gL-@E6+Ne4Z#z)+$Fg~t113om*2Gi}51EFoA z+o!QJF9h#acc$EEZqo$q(l z%pKUnnBEAD9B2M_rcD4h$^MHXxTzFw=wlUq++op3xaPbc3q zBRb!5V&uyHdjz@@pU{3}CboR75ta@Y-jqOo$$`uHSK1QfZ}}yM^}uO}PtAl3gJ`l9@jY4xvfKjPa^<-bRH z$%l262{pwaVy}=d0+3^bV3mATRE^|m{o!~vDpE%HY4)ZYU*3n|a7sBT#G#B23PH7+S z)8bgSUoOmFz_}{%)g$5#C$bKfdOKSAwvTrAGk-2h z&>rHN0rpJ&Ui@^976Gg4+IjxuYv(<^?AjGKKk04X;<|1{Wo+mCqu0AlbmqG@xe{yH zyO#IvM>c%lk-w%f-rxIVY&9?^lK9FXd>HWk z0@#bDkZ!sg7N5nx<&TkreI1#s_k4Vn&|!10Shr;l|A`aZP{VG!ZlxV?<_^5V-uKW) ztcAdHm*_ErI8td1^A8jgm-Rf-YKWcqpAKR@In6s3yUaVTiZSK?QnGi&+KFmAg1^E2 zR6D&cPj2a#R=ki?2+r`EYtz|ZXsH2vg3i?KLq6@`Ty8$?X7Bd~$3Q#R0hfn*+eZ`z z_3dunrF%to-`xyOlqU!+yLq?aF3s?+#gE7zSmrPZydJD%zpgQV7g|Fmw(i#Wbk!Bm z`Q_02WzhYl(ElaKql>UL#aQ~4R?g9X(+7P3(qcUWj@U$_r@zwW_NS<&^<2g2odk|v%JDwYjrIPJzVzp%}_oW83JZ~hX_-s~O0 zJfi=}<*eKE5kK6HC+X)b^b*aV6k78v3!kiJbmkt$v6uV4`q=kmao#Zj+I|(DBKxMt z1D)VE)c`-%dm=t%-{-!^Hym*-AAdV>+i_7xn3l9|$n$lg7Hm;@$ zS4TqDeMRv;Z+m=_qaEJR;Z89+;=I^$6R>+RUfNU2E+l)p^t;z{CPngv#arRgg3*0E zw9Q1XpfjxEUC8+5mK`F3uS)!kn_mf!oxZIpiuGj!qjWIhrLs}_*LvIIfWbe)+Ytv0 z9$;_-Lp?A^pV`3r+{C$1onr|1ImO@euwY5US23*TRGrP}({kx|cBJ1~jFsBx1$O)z z(Jd0==z4Hf4A16n0j)pMTlV4;)>HgjVhA$Ful9Bvm}GPqoec$X6O4{j19=-d^dw3D zSOVQ%%zVK|f^|(gi#+hxw=SkV2mJM3W>D6VAIO9MHBn!2V}TLVF#i(zVXear?0tYi z_jZ4swf^(Ya)g@FEFGO~Gg3c-#mT+_;`xBt#q+c@yzqr9U-N;x0@ z)`@(-i}M4Syf^zQ+ShbdwCBupx3{^{+LiA%(%(jAJ8~DX7*{#5RbXqKlxX5d6Aaal zFuj?~A?6#t5WC^ci(je1ADH_FmNE~;Ujknyt}b^D)MoA6aF-*UIL!0r`W~R~73dq^<=cUmjgAkx(Ty!3#^ck@ zju0^sL%-r*F;KhtujT(Q{1XRKF(5;V1-a4Lq5XVov1`}9CzE|y#Huu1OXe{L`yDqR zmozOI7)$)Fai3nkXAJA;n)=GMJHP6Ep=LqSk{gIS*|vNJ{)}r80gnP_ z)!^yvuO#H|{i<=B0Y5XBa6dP5a1s5_qwWLrzmNWJr0zw|d2{-R37bdVanx;pOCUb- zM%q~9;QQr@1I~Bq)_2`|;`X4UqRqhdM)|7q-MK3ka3=je_Nd$?(Z0l(B^v64Zg*bB zxqaI1PV>$?pSEqftD)_Mw7u$PW9#`Ef7-Uc#nW~TZ7-zlRkeJl?KIl9zuRrQuQAHY z^4+-=jPcT&7~|r?;K0SiWnEZ^FLIpE%bvWj@#TV|#@`m~YZVcy!VQ!c%|ejYfGjysCFkOh zmpN&)_qGs66Zn<_U(bCBTPhpzyScSteof;=1FTDY>*5=Fh5OJ@o(5OBZyL|hA zZ#O=~-me>TH}-_KNoIeC`L2D!+s^SV;vu0aG5Mhk=gPn|WS0Js?eJBfyZ^HG0DTCI zEbPdp4{8e^d8@7Lnepwa`+n?4_{3X0Cwt~XzPZ~i-X&l8vkT2u>z=nUTl^F84PNI6 z-d}VfT@P_&1Hj!|?+CV@?ftZ^%-fMb%>GTpN0*M$&D|Ioj?6mo zuS8&Nb2M*wkmv97{F>vz4VxTsHEzyS`1$ob=J@mk{S8fXBJ=a({+~cG{}&Uhe<8oi zct;m{B#-|mxr1dR?GiUPa9?4tx1})n3bIyUN|JdZZxrV&VtlEM>>t({!O(N8Gtk*S z(lUq-+UqLI55$&f57D2+ygRZE83H}|5#nUrnWj5<7Mt&Z^CR$(qwtU(_{qM@h${`> z$>KY@?cD>=Rqw{aU;%rFRIlNC2e`(v=lBc%JNWfZN-#4SBhD4HSFP0;m$X-nFgor+ zUwvnsL3<6Bo#q+%{DF}du8g1LZU2BdQTv;3?WyU~eGu53xYze)@|Kdf8ryUkd3#m84$=eLftj(CpLRx} zQFn>zxR5hKDtilelSsa&jm^4CKGIj}4cAd;^zXw?WYqy(D3*7Q_IdIzrd(;{ITLxN zI`X^}K4;f+sa?-GoE5+~*Qy8FQd~sw$V_B%!PLdSU8YcFrd(~3-v1THh7E5MGu1lZ z5P>ba^>aPM+h@V>PXD{v%P}@vU9oJLzh(_a=0n6`Z}}TVNS{ zpg*+Du0wQd;c*-7AUmiX$rioLfdF$Lo9Do?uq+tj|J&5j#@@O|~zWdaoeC|E;y~mm>9mQFtz|Y+iz3*I(UzJgJJbBHAF{;D)`*;$y-Au@rSjQ6>G--A8TGpAakDjU3;7w(c$`d;Qy zN_akM932m3jSNg$7nWNmN6cuCXJiZ-+cMUw{2x<(DKF#<&$6UMbQsOO- z-x4^kISns$y;TsH66Z7eA1VkSck3Q4odwh#Oh?{vaNe<;GfaDkSquN&&-|Qpf!X^$ zdHVR}k?$krSxlZ?1wF^fbDZ?^Ne}TqlYbZYrNts6pkwTfho6q*$2|qT$^54ybB^a9 z8VqDOIg2+cKk%ZL`(#GtAHI(}QtEk5CT+?UIlbxpkJt0%IlUSDPvWA^2jc?}x@8Kof82}v%M$Naj_hRSdK#OlX$FwY}zK6jaFy|3n54!WXqk!NRM51fTe z`xRu`Yst@?RZQH)WBDoH3GJ*5R$#AO&76|mG=-n;pqWj*YClJFhv$yuCG&nYX~~NA;wA0BMh^c9X*x@tgWqY* z3}e@h^9)}%_T*QwEx$I}yYiXBgxuGLdpovp-^eqY6a2Sky}B-mx+;hz{4(c5p5rWQ z2z>_j_HxOxZ=LO3!N&QDid18Un>uIEZ|PsfXSmO+WdS_@X3o<|pU_H7<^}9C9Q?C? z>M#8OyM@EMay#RrJ_vq%uvYetG<*w?v3k*I&%zg?&Z^VxFWFSJr}?WZUfA&^?+d-I zQMp>b#cM{PdydBaPU@**Z{cnn!jYLQ!)73cS^yQH1F@7jC!V&g})JF=X8deiINi}zSTZ#{Yz z&YqdBG3;;S`Wl`Om7{lS_pCz?iOkmKZ`M`Rae%$a_R&UNDSEH_ zxr^fi?B3S6vHzKY4r(uTVoxlW?y@ZF^>N)3MK|#^UeZF$z0I^2O{?0+Xl(DNZmTcs zdqg)m&|WU}{grW5%xmK>7MofmoAe?hqq;7P~@mhK`<_X++Y+Kk4V(&v-*@ry>sM^_uco#?LuwI1^y(&;TR ztaAh0W#W%xk89Gm0}mM;HN?aSlBV%n#@yYBFIiv-=K~p2<;jlq<_B6h7w^k``*6$h}*#UslIqL1OC$A17FIG8ppm>M#t0m3&t}} zedx{mSS!&TT~W&&fPFJL%Sx;W=ODgm!NS@tSpE;X`&p!qoW(s2_u88)ukwjLcSZ93 ziRb>v^V>Z4QP&5^0C&Oze~~u_`G~Xr)8=xw$e00*K^1f2e(qffO~cm=8=v-W3&CX{ zb{KH9yAK|80$O;W_U?JF;>V=BJ05V2YuN;CU~ey<11{I_-sk#?zlJqE2R>lZ&YwpU zM~pL#2asp9K6J6}x1#4}EI9vkuJ6AtU_aUv{_X+Z(k#xJ^Pg8|m|yWk&X)s|A2@%J zcc;128Alrv{59xSFQ?5z^xLw{F;8Yb61Kfb2DR=*k=^i@cB$@Vte3i*Sr^{ZUJa8ZD=6EC6jLuzh zXdnaqJF=5I%ahB#yhFGQ)W?{zB?j^?!0#ijWgPwM&9mq|xC&hUivE=?MTaxRpe|%6 z{5iBgvfD+z>oAR0;zW6J_ahU&$5{Mhgt7kEa{5Q#q*tv#F4w+HF%Yb~KB2>txb~jw zD~{kgFv$r1FZ8XkmP}kl-)~25xEr}aJi3>@m6F~I-h_wCfLr+j85iUe3&QdT%;wH8 zt%vvqw(I;`3U!S8^qM_Kzy)!d{Y8`!F4T8Rhq+vI6t1V4HBI23N{xSB7(WL%k7tcPeb@MR zfv4Un*!4eW{I%BZ&>rAc#wkjk|LV)geUmgsMt@t{rg5y_bD;^--V4m(yYO{{@zq$U zj#g+qdLMC)>R?XTb&zMS-c?5r<6A`e$>hsnw+A+$)WoJed8bd1(LFz=4Ma*GQcmJ?l;1D%wC{z`E) z)ywAf z!4H>lX2N=RxLWGrbMkG;2gkkS$sz54Ym)Ae2=m2BbId0>cWC45UGn&$)f3`X$-vM; z-+)DU>cpOVI-W*F;c4_~c-jYVJ&C8vX}&vbJf*V^KTQk`Xt?Ao_r~62Z*am{r}$4# z?BXr^~Maci`y2#lNt?|15qc?n} zqd#`t(1RnlyFaAiRxv{yskuMbs)q^e3?Wi8eK)zfWY3HX|oL!3K3m^-- z|IOILKNTM6lkNXJRP5m&b%kNc1{P%9hjXeEefM)8b6$1TyfROGi`S9yb`I^jCmW_< z$;rg#or&!jo2~WUhCRHE^GEi3l6NI`+?6Na-QErlwq5((#=)^bxZQz@-(c%?VDojF zletS)evQ>hF)d~HxR;a^B#q8!^wupj?jJW}g4g_Tf79qof${ZSBYY!!nnq7&K3u^2 zz2zf)7xMp;%n`oZQ@kr59d2B)_gQR(toO6Y^BDbUuex*I(YP@!JclUrs?FwAu$j4SF_6L$;Q8kr&K?ds*+FPhfU zN?oyI!Z1rOn(B=0o`rwmW1m#a+xyS3JvD^wHygjDfpOloVTIam?u@%e$mKo$<9tzDBo*K!2 zA8YhM^4-b)IFWS->j@uctO^jI+ zu`-rJQyRY_@Tj~sk-S%uSAKy?OGO@#AD{J1y7;@E@8DVd-AYG(mT#V(<)0v49Da`X zZ^frzIq-`dbe?7(wwu>9LuMD>D-K zWg6|HNEgp{6CW^}IbOouWPHy*b>GU%*0~YrrF#~!`*r}M^3QO_w#>N4Fje0Nz@ajn z0m--PO`u-IedPP@;pnx7UqH++-rbZJO!6yJ%&j%xA_Cva{d~_zGFD_vpq}YQyT+6E zcI*9eV?_k^e8K$3sJcYQszdG5&z1alD34^iowOH>{O_RMBRrQVwmLeUrRWQUs|Dza zN}1a^=sDu>3(5r#|4MHpeA>7YAGGRW&)y5pU`_S?lQ-ymNNGI zWsaooY0mhTspNgw5#OE1ynL1Cy8eoJ+ao?C@^`^5RX!1(SCskMh7!Z=?~k1~2VI44 z3w|U?l*x$jyqke5fIp0U`?RjlZQ%SNeOgC6tiyW^v*$j}av^tiLD#aC&S73#w#kv$ zC6K*N+9vTm+BeC-Hp$+?!Mcn*Df@wJf`|X&FlF16U*%qWH68HUBb3!$zdNK$XV0_) zyH%Uh-JL^Uc4D{ci$@O%UCD0r$hn5uf-lzs{F4?;4UhX-z^lAD%mJn8TLSY#cH3>} zFK17M-VcSg9faOKbR~7?%`(hp`jCKs#2X%b=g>Rf2+i#n<_(U(=k(#M5gXn9!hDTi zfV17%)R{NSX-=Q)GIQ_Io|F0V&IS0BB>UZ*jS+8P4A&~3+Ahfr&+9YAnRz488@v_W z*z2RPk%04exkG+GcgTO^<8SZzxXZC?6m|U=8oCe}CBreS@9)^(f0DWBx_dK?T}dxF zd|G#Y!o1lY6ZU2L$+7Sq^8NVjzJ8RuwG&6ReDtHD;Oq3Smp-eFcK)N!X=P7GHi+0( zKR~W?dyFeGa-4O|xy(KEI60oAuZYUa%p8#ZDKJi{E6?+Jcl<$}M5y{F!@CXpW*YWyG= zCkz4O&Mafj8upZ<$g8=bd7(b>zP@vqF;}$N4Bf)Z`b8I=*sIl+{BuIkhYe#R=TX$Z zo%HXYQR!Xyc`3b@^a0W{#v1((Aot+=+~1&o-ZvBTQ+Wbk8u-Nl@^KOLf+CpiK?HcFLiqdkJ5oPwWp!S4YdYX`y4`)A=#ioh@5Siuh*UmXO; zy+f4SIU)i-GL*`>fkXRg8;@PcJr*8;<6DE^;QcdjlqOJLp|{_OUChlMU#-cF+>-TgM0mUem~@F7bHzGmuk59-&YLzH8`5vC8;AeActAII2NM~|m> zh;pUF!{waJbqgPq`(RMH^M)w5CMI02NIZ@9vVrq|2bG&VL^$ef1{8Q6}*2U_0=mD~Hh7W5a{?8kbU za~{?vJ6*DdTl|Z*7E!nOQl{Dl25$t0ef&FsA(OI}YywYch5w2t$md&db@A^2E<29{ zzIO7Nc27Q&XQ?spqWx|ld#FzIFQ>&uD7`0X$t~>PreEMSNAxr;p2nK+(b5#|p-qHu zCvng1DF4IkRWh6-Y7@XUa>NxG>{+VtnM22(^xn#Et(XxP(~`-ar3`;a#lHI(T~Q4C zfh$;-rXzzsFvb}DWA-LLTWV~*0vk~hb`Pb;V3&Dd%-ET~J+WZUu1db)tCoa~M&E2- z#I|p7uP(lbe}e{l_ctxhaC&N=k=zKZdd`GyN+Zu*mm&w27+d4%Yl85PuKpbU{f@Y9 zH*!!S^3tY=ytJJ)-+i%B{wzMXuV=lwq1zGfzvb)mbS_+Hb4N*kR>62{kC;R3a?g9= z_8LlQJMvt(khTllOBNu*ZG%gY*%jGS$lH-Fo`?wk>>GalKzOtN{T-COWCRNIr3 z51i#({_o*Tu-t;4vijSVYjbID6!nzN`{Fn(nR_}8A6z^%4xbhdnV)O&&fE|6x1TXA zJJ;BX&%tg_^*87BUSiBbCi7J|M)WnZZ?2`Dg%ie%uE(!Z^S73HT8kW3|2Icn3GY*x za}RW-`W|FHeZRVP-WCscFgwrzu*Juc$Z zxRKdiUh96KtU1K3L^hAc?JJZKzf&B5cFLB*yIfO@@)3;Z8u+4r>KDg(8#s)fYaf;k zjdOHODfd(FndqzDVbt{zGcXtWK}Qk6Yf{}lXeb)5RlHkx-JBlA>&n^{HeNNRIYnn4 z(=zJ5hr0b4j48BT3TI zjA%(<-X=0{J_NN=GT zAK!alOP{Izw)lto+o1j?d)uq=-S5SQ zU5)QP|G_H!sjKnp(|A@njo=8%hg`-=?1k;*Ur|HZIQr(H?tf6n0{OHtmXhhZBI~X> z{@;UHbY|g)J=B@-QwDzUqYcjqeBjQQkG}tjd_~x1#2cPHhP}>Sv!M;G+0wB@H8Jz5lz`};f9~tJUf*A+71e{R}mZSAc{ zTH={%(yH?ZnYx z|Lw#m|LvRc-;QVeN8m^MGI0{Joe3@3^9*wnGRRKqZbqK{7=1w^w!!Dv--M8XC!&*8 zpIq$I)m9E?)mG=A7s%y~sk6QL(U?Bh6N46HA4 zM%j&?V=}ak9;hw=9;Z?6qpTg{UY^*nIOK5Ecu5-xu8XmuyvrDKE<*FWI|sVTfVYhF zI?Nci({xRDnWHkHwM<8T{A5Rd;(BA{AAn8c^c?elven;2zs^wEW2p6B&&s2*7p%YL zyI|L|;-+Me@aCU{k1?|0d((n1sYbe|nb?RQf(A8C#k_|k+tSx2XksEXF%6oS4oysk zCLZ=C<<5X6G)~i>Nb>h*y}3^G84brqU|{U~OR1{~UC2cIm{mr2xBy?zdhF2&e5=Q1 zCB3<9w+-OwV{B6Y$4}o2x%1#M`XT$T-Cy-{`e?)VJJRa$d-VciJ${2dte+>#jzd=a zh&m@gldQkDVoSMvf;azyG2Z+O-QJZy_QvF1NIc@7{B^~iAGgN%lP3Oloz-vhs^2@I zPwcz9E-RqSJj#smuDl4HToHCKmHl0$+#@MSSBYG)06=8M4g5U^b{2;Y~% zPee-}V-G)zZyHxq^-VW+(Z`OW>4r~uD2sgCiM}%W+cds$zu0MGczLGbD_8zvC-G@q z#OH`1PRB5OQcjPbAw9*MOs|=ZZ?o($?=aWKu#U{BWIsXL;UnMK^JcsJZBqS(wDWtO zGx5KW@2Y&mk2X2X4?~+I-#?#~Io(H8q2RovupKs)Jghs5zlr~DH)ruHB6`7k*#gnQ z-^?ERfvi_HJmN@2j+!^8EOHh)Zzykp*6`Na>Q zd&NhSv%uV4KzpL|vuQ8hKF1Gym!PLp+qLNGTBzdz&Z@7m&aSJD_|Mdl$$Zngn85k| zO~4`F#A}%I)>#RB+aJ9VzXIxj&($^aEgPL{APR;q##Qk-b+_3w`S@+&pSO>@-rVl- zE!fdGXM@ktFxDe%xQY#O92rS5Uo#x(eHw#8&RSM*w;g-^@}8!yf=b1y!X8|O9IE}O zWcaGl#>)CH^LxT**I69-{7Pn@#P<@$D)gko)EEZfAyvq*_IKfF2X_KXr~e8#DPueW zjE9@?P>kpul$Gr9Hg_;S`kk==qox_#z4h| z(C!7qmMK0NH$ya~z9iC~o`qiz$|HJ!@^;7Y?Fe7_U)(FcN;eOU5=^Sl8g1w@D z=Jy+x4(YWG0SD*PT=VA0hd^@c0!O^1L&{}s75w7;x}QwXI)~Ei;0_IIKIBRKz68ha3)u}bo!G(-yQ(&Zfp=X+~PHD!2K<7odn#8 z&P0C;a7%YA*mHz$WGlfwH3GZ#^~AjCJ{Q}P=*At9gEJ!g`h-F75|^p_T*e^d1aWzg zQ`q-g`y|(7V&`SM%tT}kOQv+W;KjqC=U8~L8(!?eKajg9R>c#K)#(e(jA;)Q8yzv| zr0lq?;?MHq4{UA?Coiz>Gh2W!Ne{ZX+Wi$P>ZMPW%mB_hkv;3tmu0dR zD!q|+_U--8AP2;8E+>AzcWuDs&Q;n6_@TS;ty#djRYfcV^lbel{Oinz&Qa8}-zTO^ zc|9^2I`^(`de*m2`l)ZN{BN?$DNW@f--L@F@GbC3=*0ki(7E?!J%g{cJZJN) zbAS)=T*VFL)$nKe4=OgR#!GV`Pz*0CWBr4!OF3y=S6vMa3i7_vm*HYk$tt@jmD(Y3j~l zW5d{asK@SGUPOm)T}8JqE0OB70VL z#__Zlg2l<4{ylp#eD1f>-&sdDd)9Yxu#IM9hfo`BwDM~|0?L@IB(%BQ@ox=CeV#e}s zlqGJsF`ac?$#1Q-#j6B$dD8D{Y&ui=9n$e>4@+l#Ha$MRRo$?7gZlHnV3`9fcTzT_ zKWYur`I8sW(j5wpqF!)_&yrrxg6nzXLgt$@)vY_#9Ls+eUcE8=%nHY7@1^n1 z8e`br)7g|v)rvf+_N32U#F>}wy2=d5SsAQv_}U+(tpv3NJ(C>JW*^_Jr{Bj}uwV+a zLpkVUFX!KZeop@ReZhB>dLf)59qnv%w2RQu5{v7Lrhm<4Z~d(LkD>oo`X9(yKLn1P zfUc6gXyG04^@s5nD}YB=Ot0i1#Xd`R)R=tGqGzE+TcAb4X}Wi;k@E5hKXqFKyvdjE z;p_)43g?ag4PLmj#qj(9epoqsx`_GLzB+~6{0{dji&sjW0sl*x5dYgqUSGw2TDel9 z%BRbpTD)0P6ghp!<2Vam7#^{#8J@R^+_g>i^683+lb^rJ6q8#;GPC$?<^L&GU3=j9 zJv{I2t9bp*HlpiF6Hg(! z#cyYr&Dq(@N52UEx{h%ciB?iy`yHIqfj+b_@@x40r{g2lyG`|70DX6Y>sc?$uc)sw zz~12mc4wH*zjrwsYpcDj@j4C8i{c=zG491C*c~Gv{-Yf~?j`hf6#Bo0ekJ$KL~i>n zI-7Lu4?g18j^M)`jbFDrxv{#)bS_#*o;2mFb@ZB-E1?BT;5o-5gQ~3zbU-slEPruP zu)Rjk@ln>aEht-aKDy&aGzQ6RSE8?8f*xo*yqwhryxhzY-+yt95rF9##-(`381&Rj zz|-T=^H}A`Pcd^uX?Hm{>#Tc1-e69b#8WOlST0uOZtX5tijU=Mlv@Yv61OFQQV+ZhpT$2-th zPhQGUJLAaB?WLWyjAJo;c82zi`aL&T{x_$Wj~Y-uSNXi6S+m8XDL*<`J~>#v`SkMb zl=rB8##DhQTKqt!LU(;juO3DMv*wP@weBMdMc5wC=?lmeC z6)dB7&Eymlj8V*a?{~^+H;M5R>-M;GZ;HwLgmV;6zfR&c(%F;g=A_P9{X2g-jQ^hw zK)y9?BlhklXH&(U(-Ob1m({T!_S){U;zmt)LgCs5?v9%Akg-1WTzSMpcZ0 zNZQL_FX(I(kYhH(-ucU+JkuRyPWmXZ`dDc7F^@iqY4al5bO38fA9s%Zb%^e>?71_F zHM4T}2JrYro`welIW@xLK_q`U#uImgZnOBJ9^Gc=FZ>%yE2+Nz+p?6mV z>lF0VY1i|)(tl9r2Iem;&qB!W`S36N38CNGo4Swq^V=QB^?lz-{F%KUcaPY~#T>X( zQt-Nd4LxK}Z2T?zYP0EiU>>sL2UmDIbLbNtvE-j7_D0))++XOo3C>@BSn;s|{jvNO zn8O3);W?1S+_!#UcsmEdcZ_7b#67n4&s&b3q)hfv$tZ1k_-WJ5VR+m&<{}dO7&SVw z2K_ks0EpL}b*>dNGv12Vjke--7qfrXz%#6aXIKr-kV&7Rb~bS?`fSHDs?T=T(axG+ zJ7a05)98FjHjVkv=e#84_d17on&G}DD~hCY~kpy^8;*n73lipkkpe zvEGfO&IojD!+kHaFFMR8iNAUO@c&#UPV!Ue{Z{LJ zWClJD*vun+t=#9seHC5ZIn`OO_bSET#Q6qKX5C83X*pnqbT4JZ)1WIdJxCkuHuJI zhYO!x>#m4a__%k9iJ?1~?>#&=Fc#fSlgoa*tJhd^+0RYrz69?G;2qdKt~lTC$^EeN zRA^kf8zSBs*C5I@kwee2onZ5j?WC_el|R3oyKO52`m%jKa`TTH;MHAi`>@}(wHV7~ zKiwCJUhz(2$8LTvu6KFE_pai4^elWI-oi7jyR|oBUCY;?1G<-I+B2bN>v(pb>h?Md zitEv{@b=1hX4P}LcBrj&=#y>@d#1M5@a#682?uDM8<@w?It#x;<1BrW=Bmls13h!~ z>lXs|2&%5NcVx>6&iB9bPP(NntI#3ZZQQlm4}D_eOI?2-m_(S+Bj)IO%(XFMZE`!=uDPl9z;Yx%9*Yv>ZUr7>p)dD|MW zfr-8xJYag?W-Sfce-W63>l%g`U59oXy3hc>{;AF~x#4y0 zbsi3{G}cE0UllmY(L5}8PbqqS;PaCUMfpi8c$b`%z+F{_rw;s)#N7p=FMEUZMSE3r zOY^34c71FhN5gl33psil_Zemtf>*x9|3JR{K)j~*@om<4<9%~AuiQOyrh7*eAJ~~{ z^CTFqtj}_gjrqN38uuX0fR=!>YdJF;!Nu{M`7QljfqSX>{}T67?%?dE+1dMAPv%DV zQYH&G@IQt1)w9ckaG2n2<>brdzs|ZPQz1ir)+rqwDFs}Vq5rqj(*z$?d4{9hHtie%MJ9}*IeM)m~Za?fOTm- zlq;WCV*LZLKDF%e3g)1%yDdWZS|pHLVCi z$dAHxTEkDD51bA0D|**^ZjV{-ZHfgl*h|Kca2rj?F4MdIwZQPjeLJ}ag*!%>@80XLIg5lQ zs88t;gujbSY*kLzsb&ohPxhrcP_dz8$ zWw9>|&x{8D2H_9gt=`JM`ck=uORRF!DVGG^YX*;K&*swiXzc~?NN6u<|4s_-qw{!Y z0&l3S_*es?L3G#lXLQWUOa0cy<&26+d|~ciz~zLzOs*ZF~5z zKeNc$Y~8Ujf34;xK&S86?%%-q+SZzHcy23W{<&{Qd|@sypG5W)jZ)lrQ|^9?sv1^lSU`KSH?nEyu=hcxEvdtz)r6iyqop z7wAB7f0y?#eQlc`kkihT_u&&{lhBzLE)}o+7BrXK7nv2n{J;3kzTS~In!L39N9Wwd zd3nqDe3U1bvTeb##n_2-wpG6&tp2*Q)c<3seu`1(3f6xY%xw@n3t;c&dL_{8LwSz0H5!-L;)>EB`FKihghB4$8eYqtWSnyE=Vie2vfMY|H@% zwAt5G4?`atxGycZPO^Pcdp>OSAy@*F>Fs~>>7ik;;yVj z?2DbmoNWo6t%{2+-pct!twZamcAxrB{|0N!PxkK`_Z+!)d9L|Q=C?r{&0)r$U>G|# z+J;%gKuj`Tfa=E{K*Urwgfd+Sv&w^i`3BNo8ei`3^ z$^gIotq0I+v#u{z1kR~&K?Z))C4T=~j$LCtZ40nhz>l|bpIwR8-W(I;q48Pp+r6!+ z;1*=tdAv(@jqzxVzXMlJrp=#x-8ScqK69IOqpdbyq0J=Pv|yMwrMrB9j|UE55G~g} zdH)dn8Ze7j{}B1`T*e5_IboC}d(aoWl~*^#Vy(&8JU;7P z1#S=VTw1G*@Dvq13)~++)c0-nUtM(h+|$QKu8E!nz_GxX z?zxrkRdv}Ooej?4+}ogA+7sBp6NF=W_vNB5;S(og3XK7}WZkb^Wg}l>3OO8T(~+G0 zmGiwOY`#6r_fLa-vesiia)$U7i-+L<8W=-`GSF8_ax5r5$q;IAMouhLa)}w`PP{p%3cX?+l5RLfb9Zu{q5{@ zp^Kf${xtd-lb`r)ge7M^K_7R{zra(%o$I1Qe(oCdvp@WsSwHqy3HKMP&GjoUVEpBe zi`Q_hLV>1rd)QTv?xtSlfZ0>hA3hh}ncrna@7Qy6X4dB@F(r8NeQ;GIr8hko{~ro@=9b(Yh77qM^M*~Z{LpacoW69%mi;b zSU=@nc5>b`zPR^bB)0wZFG>zN-y)9|_U0`1#A?<^cVw+K$%#eVL0eFl^rN--qOC@6 zJ13L=GqJe>}gvZNCuSX$5xDEzEr~?ItHRT5%*f zhJBG}qn~jm_sn6p-6xjz<;xhH+in|XA~wtz-o48^Y$0>+03O*Yo{u0#0bZaA-b3&y zXWL-D8BbOymz?VDi;Z9i^m{0DJdQIL4_+JQ{h~6$^I4c}APpR~mpLr&&)M#8)R%Jy*2;l- z_04WueM@5b^eSu|$QNCQdEQ*<&OThZCcAk^!}R9Lwb`v1yt^GaE7HZgD&DQ;KC?X9 zG3%Qi&aZEI;Tk96t6#u8wq>}yU1MBbe_fR4ZBNPd zwj*~ONws@BZ_4+6l9!wH;~}mck8aBK)(#>@1slNX{;saahPie;0{=p6*!J2eZ0W?t zFB@P?O|%bdPXbqd4qnk&@8rxRn#0=5*{_aDWOC&59PVQNm=1I<)EtSJNw^W+k`#0S3&4nHv zP`xzvNo$^&wWY<}??mq3$o;nS&_|Z1lIJbzGH-jcf5UM4D6ia;T~Yb#?3I?`DU$^*N{a=#A)t7{Bg(PbQzV)**?U(#1o{r>AkpTuFw}mBigy$>g2ZTF<1d zlEb#FFYdd6{c%0}q>%k`9s6c3KBL!?YdFF>lSjyB{J$yNMr_e>=CuhpTG7iLL&iQa zmU|D-kt8sF?eCqNr+If)j_8~+FV{N~yYn~F@g2htmU9x9e*4H8=klqYpW(~>OUiip z9*%$YJHwoA?tAJuHrCaJE~W5g?1|{b4}|7cc~0eLegqjMhcoO2_m1P<)@9(Y*N4Ts z*Rd`;iIdpN`Y8wcTIfzKaiP~&JX!q_uqsw%ALTMAS426N=f+dQ(;1Xgj*&F|Mwg=B z`)E6hHE(0>wO{hU8(!AXZ^JG|J~Z83Z1JxoXufR%`TOnP>eRiq&uqRI-AX`rH31nq zIwry0_NzQ^26K13(&ard*0rO9Jt#YQ8+rAQ5X;uVT>hAORSZ;shqR+#8R2WD@0+1@ z+Q&S9KCda=^G*JX#)%hl@)51m{miZKgLS}Qa=)i^weLLBqqo<-aln5Bc%_Awy%qj3 zU{{5%LzgW2_7e2=aoS%=S@{Hq?AAr(Io)>&wm10K3!!s~#F^zXKiW6qg^?k>iTzAI zHa>Q5B02vOoBDMMk2@|U=Mgr+3g))pZX?`H;|xp}q`JieN{F*L8q*z(E-vMd z<0ly(S^t1!%obuiWBHbRulYMuIh7gA=i&!^HS38BTSjVtJZQc}6QMh|0PhO+!>o)R z__i??3&t@<;R}i7b2G=hH8PVNg_*Py3%oF)AMI~y`siZdT}GZ>CV!Gw@>5JBU5X<;>o=B%{lj=1h;ehCQ&wSUyf`gD=^hB%|;}c-b=M zJ%@SUOa8&h?76#%Nz4Rp&zSv+eJI<=oSX^n7UUz%^K-z=y&_hdPXyc4T&dkObU>S! ztGx5~kK9e(!Hel*8GWSCNAG#d9JAZ%GZ!3mraoVyuS4n!-I3s*5Bx==fFB?H$()C~ zi8IW*8{Ew)&Br(-+LTUr6xgL$?L*t@Kk%A2ab+p3FJBoAb7cc2|v|9em%K z`)KFs(EQSdU{xD}RqdpaQ{!jA`m^(YJ@PlPz)G9TX!AkZJRey50qZJY{WY+zI{!CT zAGT+zMgZf3!1xF))AvAx~6>O?2*i=6aU*Mku+Xv^rI`Xvv zz(!lkXzMlF8Ut+of$bq+dllGTJ^wYU?c6Zfh6LfthwlD(ay)TGZvTz0Mo<3 z^cpaIaQ;E7-Ozj;!{^jGAJ87bvy66k>U@KXlgkayf^uX3i=4eD#vH8PMcLoeCpaQ& zC^RAke5vys&$rexpK%H{wPCF#?QDVHcnR3v8T0nY8~!$6N~q0kv^fdbh639Yz;+PW z?i};`YRV@Ful1%=;dIcFlY(^6gig(bt~-pL{MMly3Zlafm4kK-=sb4ERJf5vvyFJNoNCV`!`$L1cgw~J@F3mfz@`1mdGCMCcu{lb@Z zTXDXh0+(d(kPW(y|MJm2BaF$Ho)Jd)wda%TF12h|FW#q|oq@aRli~TKPfLL>6dVut z>a)`NAMaZ#9TM}`m!E^|8M5P}qj=sRMp|nT($lu0W7e1*=uxCo+xw6qebw_u(`n_h zG@sDstS#6diw)@)FOp8~KneZcGmv>=zWlQ3Gq2WIj2y-?%y(#558sbU(_`sisJn@GN$^ii{AMh3H}c%?z;k61bf|{fPTo@;}zVUfsV?Mo+xdcbePXCD4!b8VS=Be z!<>hX_TO1s>Cw(wr=h3L^VE@@=B#y+%x$fW<(kd?#`q@EDBw ze=iT{f2HTH-Ws^4CeY==_fu3W_*})e_WVh5 zr)Z3y*!#m9^~Zm%AO1ad-!$b;jB@R08Ja5`GiA@?*ddv-z3i(T>NZp6Fk^4ANBI6i zz4vKHa}=;?;j6>Dzi^J<=iK(bpHsG8^iJ}}I}n{!K6eSS; zsCcBh)Qo8q><)CPQIwlKI;y6W_bYf`%-9P?uc^*JH==j5c$bdI8IkRF=t4$rf9wCaFCzArqBE8r%FTGza<1H_yE=Vd|NZHdSG)vw-nrLMFE4r4 zseH*(_)l9n0G&=>W6`?WkSUXC@87|J{`~&vcZMRT$04uBvyQ`9#{}vQM{nKVGbPQ{ zb;xFGUw6AvC>%dE33>KBY<8^KkukYh$W&!DwDn_PTVt=O*1bl`1=a4$} zMo%vNwUn=A-W8X96YC@&>e3Xu*Go={k}>%BVh7=lLFDnM_WAHz4)FBM zS0DSpbqmpFIQP4j=Pbjq1vRy8t@R@HI>s#29?@{h> zfon(IX50RG_zbUo-@n0EdHu8^?zEd%im!Tx`X1IUny`*~E$Da-v)2|+$@j)A4vgKw z*sr$7G(N&u6qBA996S4|Y|HmTG3k4&oi?Yhov|w>-9fDBalZY*v1eLiAJn*%vF~G_ zY3$<|do*L$U7NevgBp8Dud&af4UJu6yE|-5B`GfJ&hyZ?ZU`IK##;m9(wIWykx!T6 zKNiuJ#v9EY?5`L|@3xt}$E{CV^Q`yX_5=9sbV z9mH#7rqtdvI0f6)F4I#FY?;``bI2*s!1`Vr%(?#|x}(?UGsc)0cN97I*#lP2{k_EY zOD|PS4omrWM;3A3==Vzcy^4N+N53=aH=2H*qu=MPeh0Uopx?ptdz^R%^{YKKn0}SZ zK>a>{ERgH}C~=gfHyhh##zea#>6cgltKY+eoL=&Zb}c-7xwj3yndUN;xoplfw&B?7 z(_Jq975xaC7~u8agZ_T1v197d`wzx3XLZoLjqIIIKfo{UAag!8H>=5R_xzOS%{RKb z#$0+r*B`+zIhPw{6Ts&=vjTe8oZoOy zJ!dZGT(c}09a!8c|MpP(+iCxMQ(Rpeqn3LY><-Msd(6RKI5Pv#(|q@D_+Bv=Cx6ad za5m~LMW4hx>{LJBHOpL_@0=ZGSuuCew;HR65qFdt{QjlhBd;b24&a$bEPtra9|gzM zitRlS-A@JOBi{wb(Qn%5T(9ogZgS7`R(=CLZ)$GVR>rItwY9-}w)ddZau7$N_O~K; z<^Y$Ay8|TOSLEVH#rd2yU1eO$TUhV)AN7oP`5D&So8D{9(JyPwPjX+o?2TG``2{cRUjdI}7^Nsx9V!z?#pN8$Tn}g%sg0FodHkbz1S>xXIVc+An zlf$;Jap$v#LgPNFJ;S&S?hml^8rgwyd#y6A;DGwj`8l7ce+{C6>mOH zCXE~a&o0Tf=ngyT*mH>^=o2|r5hOtBYT|8|n zZ90JO2ryrnewBAN_B3mcjDv5P%^lm&z&X=r9vuHbbj?C=?;iAA_3V)k(OnmuJA6nH zxu>P0LuT!8^6n@)+STW}vet}nWx1V!dxhQPnh3vFSn{KAhwKRYZNUT{v0$bp*2OdFJzU7)(ixf)SQq--m&TgXUnKoO8?Aec*`GTc*xMZ3W1L2u-!%GQ zPj?)dh@E0I=Zt>gId%{~=T2w-+bmevi|FeQ(GPPq4c;@ZEuVY;g8w!De+c}(SM)*i zSwbw2Y(NKi-p2d4g6~!Kjll2DstC&Pe;@w^e}ixo@HeLi;BQMkJN&|}qI<>3*4fLF z{<}yvza;Db4r>gosn%2R2G7!$${W4PuMRKI+)7q$on&-vqC9rSt~z}K>reQ8np{jF zo}f1le&{_5|4!3gx6SO6aN5~H42gKCW_0=Dqn-y=i(at47QKLOh=$yQd?uMGB)^HD zw|FU|pXc*2$WzF6PV6MDDbAWB*guHf?uz7o%J^&Xv4d_nV~wsOKcC@^937Ev$#;>A z2wh&pg7CXo; z&Smj@WG;BaWO%~4W5IpEv~URfEk4eDWFj~?9e(~hrgydYG<@-IpzSTtOauE<(?tB8 zz|R_ko(tY~==mF&x!!^Ay1EAa4m+Q1u)F@n$=>IFHO2e|-^`0NW)TX(n&$gjaFQYFsyyr%!=Z!z7ocXJ#V>_K6IW6 zwC?!L9OCzuC$697ZMpv5XEtB|a%qLr=Y`e?$DZI_)5M19=uoCB|7%_4+u7yB`UL$j zEI2d{#diON_aPY6b~FF|_I}96k&GdVu|zYb7{)db`FIeqNp^HpcHgq|bF+4)pj&1f ztHF^I$sbiZE#JErJF~+ay~`@J93ukjsaxE z7dC^JbT(}Cu@~4J=y${OjzB^VYF5yrM}ne})ej&lc+$ zG;RPg^85B&Z!`He4#VHHkX!6M=J7Akm=5x%&!?P!kIvX&_FpXLY6!aDe&i}Kee!uM z=^wBIjE4t=_u6iXPk8xUk78AufN2wOC*44dgr1|z#uxRmRpk-H)R~?Ic?K@p<#Wrw z9en@eb3K=#V_juT^&IB8^0F`I-Cy`D)?S0ISHSn5q;ARIz}4uHt#;SbANxuD9XLm38>;rG|%l0-pciy>qSk+fAKSd>;6gv0gc5G|yY? z=S;Ke561~d zMAaCFWrwK!o6}oWV07j3F1ab%nwQI$1=hzJx9moYJB9v62FDx0oGM1hX&@s3dqMJK zPu}u{or{2_p!qycF2AMY`Qi0O++oT&Rw<6g;TwIOV%s@S#75b`gDxZSoioMk#1WUH zn4EuOkBX+g!yS{`$xrLzZ0)rbbyks^VeiVK&Y65S!1J3Q-f#KjbZqi(_=Gc4!n3`= z?rdIuFge!IC|W0GsOKUbLEz`lbDTlOZ! z1mKHr)oX~e&ST?U0ozIlhZxMQ?B3e{;kK-hP4Vm66CYz-Y9nM%T+9C>j8ne<8XfG#p46uUZQsf}7x0_Rzv3PH$^#mTe-aIM zl7}Y^-}0H*3#zcSTeduY@8yoeW$cG7>=y@gRsK-qA`-jkVXm zGsaU8Ut4`7)#lwo%$5V&?I*6F@JCx^RwG}5B?;FN=W&4y(SbKSmX{=v` zeY`e0pf9X-K>yMA;FAOo3V)%#*uRsQpHQ6#s3RUgx*($y`VKzd#hNR}f#7>#fzCBL zjL!y4{p8Osuk;nGk*W8gFL$sn)-X?s`#Xo{pTN6+@`-=jrxQ8P-~eOQXiqLYd4T>8 z^Ie3UP4aj-adw*jR>r7$t;}s2@|{)Z=x9$xSRL@_dIKLVKV>DWg~sq;wJZJMf$%Mr z*b*5(Is{~}c;8jyk?E18Xe&!`Qi{(^M?Q1Lh+jKBH)nV3r}{rJV5($M=D0g%^nUhd z?>2Nkgr81cO`QFG4(vTP&k@dG8|#3db9;(tZmQP9hP_QTG$*`Ir0@J<<`H`v^uNrc z%!lC5BLk2LQ?KwwLGO3MdlsY9dylm!H=^9~dEEqm){&FvJ%KN*&5Uhq;ZERD%t15d zL|2>X<1lS^08^r2lpRZ`9l2HW>1GcT4{?}!P4scB(v`IvezAx)=cDIylpLOxXquTB z{9aFaYzhZf8xA-3a?MSGXI07nX}z;CLTf?o6Iajt3CQBU)3a9{eXx`W*qTG|9}t-chS-Gu+;PSa>V zjQ*K2`xD{!=Tp~d^mFHsD`!6Tq(^9D7I`8M!DrS{ceN4g{*W=hL;W`9DFiF@uJ8o& z^daMYfw^3XEHu!JX>XbINc9Db>DOjV<67>bb}&|rQ8Ke+>hSUIhKIR|{*H})v-$%6 zfGNlDi>*U<`WM#lefoSbIKIP_do4IV2}&}TPD zpNJ1Z3iUNlEBSuKZ-UnnOO%ty9_FWF;ywiRH5ACT)+oBL_gh2Lxv_0CjYwrguHnw-ogWJmacLh)LPFBV-9UY)3Mk{201W{UPi0&vFRdvF)@F&?{i zc-ixVW%vGVz|^LPFSFW-oK1ajp5_(YOb-2DXE)<}5B;xis(dxOiClqgInWaLkrL=$ z(*WWjh$EUu98r^%7jR{^=v2u8yLZ_b;qn6DpT+u-D`rn%-)MiTZWm{#1fMDw{RrPy zfG;zEv4A`5(}1~%^QbXOe=wABWDF*EuY-5dfp_y*7ri^5clwt9!5n-T)`1V6O^&L0 zvl;!HX=_ifSXa&c_Kj*!J`9nR%Seu_Dd2q(?;AM3>7!Ryua-YO@6veZz=y#J9Z$!P zZcM0sVj8|y`;|J1)>9&lRyu^-jn z_r7j_*o?yW#y5NS$6WSq`|4oZXWcKsw(}{kIl6$k63zPjb`v`AWx6#Moc8lVW81{v z=Xx_PbnPh0&FyH#2HZ9%a(24&+#%>^A1{T6TWmTS(=K*-FLt=Po;L?IX1+z<7<8?9 z#Jc4(cKoyFz5rh8gctb~oUi+8{M=jQ8w?(LtOVhz}~xo z`iH15+w>vThc`MzJ@b0{>xUisTBFc{hkLm?9lAeE9;e!uI1m#ACa-09Aw)mw|&zH-|*D8 zpSXg){lIU{7w~Hw);#GxDEj{ccYEu;3B_uSV6I;wm%>d0Tv<8(fZvwxm)UZKQTXk1 zT#w(E`p4>f$TRWEsA*HO5{=k*uvaO@PCi=~;j824o~Uy8cdLE;pmXOKg*P#eMa1ew z!$+$v7dGh7IusGBmpnVL4y!LS3OiYcpR*2Qnaf|Y4j18f6k2oEze97JbUE|Oe80qf zA;I~za%%XALvixXD$kv7oveYiCWDygeCmYeS!>L_S@DeH`dP#_*|^6f(9N5DNz8|H${lrs# z^wmT0OTj)FYOg4j{lys7p7$d54(1A9WF_V7+~Q2PS<-ta?PO}s6ky^{I4*i3ML zQ!)u>XO8@Ubau!ilc@Ms%I;)uEu`F!Y_8?kGCxmqZvRM5>`r4?V}I_n$^!0FoRcEX zXVWCkBzu{BmvcXd|9{#x%Kcvs{858@`4DYajW-HkWiP*)^ylh78Y6r^88U6keeB~O zV?QslkFw4<_JFvT>1TKpcUIBQCG<0`q^F~_@0MmynKQ>dN+$T>f}89 zobwRGV=sdbwrT!#f7+AA@WxM(&;JZADGI{7g84`OEc~7||9`UP|F8Im3YXjj%;=Ln zT5sXm7Hi+cTl;3TJ;A-qj9Bv*>|@Bqarcfiw!QB#IxO7Cd^MzSK7l)&zCjOCUajX$tlt#x`$N+2pYY13hQ07kG`UrbQH`&GM?(94GxPOXaNqA?4km@|``5uq z*1m^kY2PIif-M`B~?Qa_^e1Xsub=1_MY z_)>LoIx2h>Ke4y*6MGjwF|E;?$a`<%C-&w>)qV4cAwjs3D9hYtNxvevyy)BbzvF$| z2y1-%z%_#3U`)(ace&N*#`wQu#0ufC5$y}mpA;e>Am(B&jtHF?$Zdt{zqV+oPRp(Zv(rf8=}u*cn{j@hN%tSkpDZhCdZ)d z)q)*)F^|6Bcen$(d~O!MU$PBwPZ=D@U2FZm-{#f(<=9J)v2GUz%d3p)93%c<9M3*5 zhP%g}R(607-Ef@h$X=hs?=9f53+xWJ=2!kE$KYYp%tYS^{)b=~9`^efHifwG|G;kf z1JTYv+PNUCKk2>GfX8t&zG3h$va`=Tm%JYExXO>8Kpv41@X;!hM!hcLUq`%5j(yc( z9{SSHe11E*Z_w#TJ{BK0^>6;klDX5VuenqHI*m`h8k*Dp8TZt0ZqX=qR3TyP)Q4llA$Vg>kudjm!SQ@|dNF9Wd1o}xJK_wkd+BaUCswDwUE zBYksdQ+h5tI4=@eD++ywVkvfWF7g+2nNgkG zusUh@jB8)%thBL*#{>I^$XjaTk%-*RL+HNqC@=lH?lIDsa?wv|&z`Bg{A_xcZ$l@j z`{#1-@vPLHZj3?g3ht1uSoY{NbYmIVFAIR9Jpo;sNh}NUZ*jz~>|C>9x``i=E21{L ziFF`$twXSA|7x#~i*Wd=POUiTjQD1wBVxAYqnG{wdNO@X=Wiop8~&uV+6<05i7mbA z*!>5!UQ^NE>&`a$*0w%p_a4E&6kS!E%`~y=4)r~^lzdf#uCQX7hDXHt4vChr-c!h1 zxuw*$-?8v+Y#@=PmEf%|&R8qwaOCp4JHPGEJvfTbO#AQ*hv|C!F8e5Vt?|IPn@g1oAGtAY+me%&>qfd9Iwm?huZWi#!UpX?SsB`w9qE4-K!KA9{ zcJv5Gr`C>iv5rZs;Z4_#cRQ{f=Pt4jZSNO*{izE0q>u4ak&bvHf1M%t>;oYyq zYkRUr$Z|uT}LgJRPs4hVWXP?{j=IT4sRP zc%~dF+z)!7^&70gF7%!Fv$bI}b`oFH1~258hc5|!<3qvQ!gD9_OQ?e13E?`$HEj># zIz11^b$-rk9<=?hI{&m^H)d!}n{@Huh51@{a-+2Mh3nAA3%+h#ho9r8#1Y|yvi>+{ zM(;v6?;6?`o~jhiLyz7k&ZAG^j;h``F9=Hr=i%hngY$xQTJb#<&bwG+7{r|%jG-In zJ$M$JcZTw3#ChryoR=TOdApgTaGWQbfpDI$f4qA(@li*g;XWVirsF0It#R}1G7n|X zl3pd_4w5Cto*hkw(2KKZq9GM!#ku9uiIF4Mv|Ksp2KcMXZ zo_w-e_lFE;o=?)Qbg;sgBbmplAii83I5%C9>u%|s{pc-U!k1U#(_`UGvwZplr_oit z@Wq;v zFV@^dTifRo!-+llvZ3Fy+F3;#x~u$TBDfR$skIxvd}0uHPMlT?PH6ovf8jU5omIVY zXVeUQ4dViMlXdwq^XA|4PvFf;@Fw$V;Z63V@MbDHg0JKUL%1`DH^0OWf+Iux;IsJO zwP;;<245fG2ieb&xn>XEgeSD{W<>yR3TJ){&MZNm3gJxgho5!xhvcv7#UF0s92^n8 zq3xu2@<|2pR7zm&&&(eJTQ|<+%tZ_cz#GDqSJI|%WvXx`cF8Ds#4quOLA>`R{xAqb z2v=SbY|G*ggLOjup>h-oSB?kvZd@6W_tpI28OomxSBCgQ(UWjoDS1k`vi-%g zxpV7H@iFd__-OdW1dCtH1?PPhnwipQR-U!Vqy^Au`Z|ciV5wGGx3V7%W1qK^FE3>@>l-P#d&4;@b-!GlK*Goyj9Mx zz z;XL#<8JvOtn>eqAIr>-QycX<5|0+K3V&Wb8#ChWLOw)6OdoUuAlaZD8w~Zt2=AYp8 zb|YJj#YS}|UT+ru$$jbqd+~Z-^ul{fq1EE`^5H4O>p3l6&)L2Jx*m;=BnscNBFW(% ze6ND~K@*#a^pw))Ne_~PE~W(;=yKW$@t`68?}lLe&G4=nz3Sv6Gfz_;c)D@$fND>% z3DWbyXW_RTZRrLZ=yx%4MlG@jar)$?zNK?1@~Zyt_FQ?Y5}K{HL$HX~OQ9V-la5f& z6M=CLF`4pDZiAjr2==EtGas>dPTFS7&%rMoqTR!u*{3$sZ$Rf5?Q2ICJQCDZN~fgp zhqv8AOs4pMJrBW=&$C6uU!RfR92bzw|GW6j1=wrO#&1d%5Ai!8zO!m!-#Bi^3;wp!$y~)pyld;jwIiiB z7yn9*jzx==FDA&J%APcivpUBfz}Ib*t!2MUuSwpfMH!|sclOYV>SEw&>MwpZz^j&@ zAiq+A)6$hD@q1PnpSzO&*~wWlLy6ZxzC;(mhEZx-f|EKLIa&O00r2 z+y(^B@2wX#h@%PDhYBvicLF`yarAJf=|@L>waoAM2lS&Qz4W6;8B@2+|KQnW{=Uke zP39NAw|IEwEF1@i^rJ_dgZkEwMj-dcAos`Q)c5E{ZJostIrWPlJhxB%Xe+j`ZW~b_ z`cbWEDm1*6KBXT$$+|ve3%3!WAKlsCE58!G3*h3BzR@K;>n6SEk)2m~PvjFv65LzT z2RPX)!-(ZfTNJPvZHAU>T_@jrcjvGE7O)qAr!0F>xNcPTq7(Vp0nCKPk=G8b!PmbJ zdy#A>U)GH-Chkf5DI6aw{ywA=t%4sYU@VqSwDjxgL~jhXDSTXs{J)bq%kQNJ*aK}} zMtjl&Y+PAg?Qnis5Bi7Odi0=ef%DQuQ1SjK&ZYz2cXiN~~b0!IA>u}0VS z^cQQYCZG?c&Q9A%bOVK_n!$;uf;#IB7VeGndGXH;=?1(P_1Kce)1LGLxpt#|&QSb@ zBVMez{(5wyn+=a*M1DFXpcmCW=NE!wLweC^_g>hUvFJkdp@Yt>53RY}(uYc4ExnAB zc{`gv)Ss_=p$A|icVHuT5|m@} zpD6NAL=Pgzu{p4P9lDrxwix%)%(c~z*ao^^fWK?vvx|?7wsH(x`{vBYs&j}#c_H)B z>f@P})iD>XtJd?u7d=w_M&`QeXM=SP5vTPmWj^Ft68BV0#7Fz~A-Z?YsBeJgy~$cE zB_?Cu%F68Gl`FIBcvjD|C6`dqOD2y7n4v7gwj!I$`Ij%4|2N*PZhHkR>>VIZH|sq3=p8|}##t*O?% z1LH4xta>1O<(f=S^%DB<1AhVSlrmnG5A}C@<|EaOJQp9a7I?R^FY6+RN8$fb{U1$i zYDHysT?Kcn@~o6+&ty^NL0i3x{{{T_U8yovlzBLN4g2gFo1;-a4hzT!{yFFKujI}= zg%3+7abP8!5#=Hq#hP`o&+i>(T%799Kj?@npF8gwM~x%3eC~X{bL?h^bj($ZFCBS7 zb~^DIv#sAz?eguOX*vpW*bi;|CU%40M%k>v71fD+my_epPT#Uy*s-q+A7EVTFya~= zU*sQb`@r@K?^92Glt3;vqaS?7!$!RW8ASdTui$q-6COn}iu$ynpFV`IPYZs8vQMU6 zJ*uXSHrw&%Ju-Jx%~3w`(K-wtKY@9@%FOL_=sdFqOD?LauAefhCW(3CE}X7sgLAum z%#+-e#~Fp^S^%H3!W_|FM}5_MCM8h5m^IM(UQ8X8ZO5-={B@&hRA&#gQGPL7BIDgQ z_K?OXUEYh|Gu9_#S5aGAfJ?a$jtl^Ij2l&>wK8aPHf=`HCVhDd=nvVWBN=%IKi_RR z)J;tyR|a+el21%2Z7QGqd)R&62R{?vvq5XN^C4`hANdQdJlo8TojQND8(sK&2Il97 zqiR+Y`*%e1WX(^MH9vEhp9$Ub6WzWzrK)=IqyTJJ0@pg=DhI~8F&69jARsJ*PXdH8-dYhRe-Mdi|b3;%}A?8S0$z#4GC zq9ESLVC~$tNcSQ>#f(X3Yc_M>VoVuf=V*Qeahb@gbDZQ4q>gwR`Sx_sPlJ3Cu!{{^ zd0uA&cd8h++U&K=#ZJ!Ov!mBluS8~e&KZO4W1#Q2g>MGA@30MW|Bk*I=yMRT7~rr$ zoU_5uEa4yv=bjbAKGa7s-Upd>c04$2TUn{Jc(MCGZ=y*>AGW z$AjyC4f$^mGlpxaulq_eKYHNcW8lIhKC#TD@M`Q}#?a5GkLAo7<+pSSXC8)*Hp90b zX52|ejN2$@9OaCIa`y6~PGm~%Yq7OA!9&=Mn>+LB$ZcC^?9aibD_K98I`U142Hqq6 z${&9=Bf4e@G-M*M9bw+v+1rotKa)Kz+^aq_GuKo%fxnxGOiFEQk{+}o^tk{!Jqvn0 z6JL-S+$Fuel@Jt5Jhef#`85Ze|#NTcZ_ZQYm z?q&V7U$2DDi*I<0buHsl$45Ma6|)SzOti(eKW5R=mDR69i}n0X)^RJpbq|p0>?AL( z_z%%)?a^Y+kJd-`Ar)KSHj8g4?r*PmgDV%0fH$C?1qZNx2&_x9TwQmhE6#Fo`!Qf! zY7TTS!Ircb8NUD+#OUqv||&jnW#d$qy(HZA(z6k)3`xBdes`(Z1zeFb}|5?|jpIK$m^eI;}q8eq}% zApx3Rah~1n81=8G=f0R8dY% z1fQGowZ!DCguX;GA4}}Ho#_?Eeyzjei&j^!jgNO55xcgQGcTgsiQqNiyCP_|i#jT+ z_ZgHE-af+KcLRsYRf2;)1&3_H9vh<3zvWz%a}Sj0bQ1Mjp&yR;5pIiCb6$)H|5jH- z#a7W}e8~#8hv+iA)R$;7w0&YYO-9di3H@oTsgxI;(pXnpV{}?$jAV?ZjPb|lgI1t} zT$J+T>Vo)@)))o-;j4!xg7G2#bUY(C``%-AoB5;H57etn^d}%~aa4FDq@kn<7*An^~h;HRL?Z`H-d=>_D(FJUoMvnJQ_SkXYQ@uMzyQ}k{ zhh@}hhaO%C9dz*#jxnHZqJgGS1PwIX^MKF55A85?umw7p3r$Pv2aJ^4Y1-QxpeN@W z-|1XXPQI0L(Y}7|E!4@QTobUq#J+ulbG;Z`coi_T1?k?S{1?8-uFy!E}41T%UIX)nGB7~ z0oP0bH-*zUt#3MY3gXF;z=sYXm<=Z@ypV@ofDW@Al7)07uFMAKTxhx|+A;7nGn4%%rNP(J;>AtT(?$XfFG(i*OWrVDT76JsVhOEOj~yu=aYtajo; z+9$cI-9w@RxSI1k-h_@Xy1#Q^ZU|RDQk}$kE?>Sqdn2$YPIHCq>{x zwtQ>$+R#W?19j_XR*)9 z*$1c5kl1h*1&qd zC+t0I(EXk@(EI!BX0U!uwZR(b{Y}(oZ9EpOVhvUgNr2{JLu5_`LnLb;*zW6wt)^OV zh3K2sK=iGg@+t#;%P#%_?}M~0UGZwc@v2?<3@LYL-tnGwco#e&8ka;I+4>uU!^d1(Ei|nv^ zZo0c_Zkjt9Iub+dd=c~Q1K+MewsgbaxouHy*?A`Nxr0wEAK`9SW>xhec*U#0;py;- zk>FZAcfh+Y;`i)e9r2U1tukw>8<^jDd_;G(-%abc$sM7?-A>kA`yvP4q74|Ovr$e; z={{GW6L|)hqRc3FP46TE->Y^HSbxuaz)X&Esz1 zaPxa2u#Bgl7%Q&Jy1N-2fWtR2&+yiRM`#P26xlwJd@Cu?lT6C$zSP0+2gM6J&<&s` zVE>%PzmRvX3Hx*h{6R9ZPm*ycI|;s{7P&r2JdANmXC^ema1mb)FQaplNx2r_dkLKM zI`2yPA4C7*55(Jrui-$}Fr?Gez7bw>TzjEA{o0A{rOeNBe6*g=vX**ZzG!RqF?fU0 z*n#e2@CNmKucd9`+dFcBXDeeY3yi2|iH|wdh-!1P>fliM3n({9Dvy4w2pIv;umb@FR z^LNX;@yJ@#Jx$)73~m~I7I~LC&+)m2kB5(N)z^}DDa)PN|CGG@Cg;DKk6PKoN8S5X z@-FL#>jV@aj!zg6BH$iDwa zau z;U1Y+bRs14=AA+2l`dN{FR_1JnbHH>fKPhhinGhTrVSVkxnl-VCF_dh`H4Wn(R%e~#S4Y@a_$XNdjAIZJFX~_u9!f@-lL-1AWp4{1@)#BOcgEzJ!nrG^3yTR{X#) z-(~!k-4XwT##!h^ip=5dd%y?ekM0v+{~@7o{p4YI!gcKJN8q#5*gvv69s+M~;&}o8 z=UD%vEg!y3o`O?kl7Wt_xLYAJ* zNB`&3R$kC{SvjsRIuJ?jPa|$AWpVBAA)OSpOlQ-1YCOFTSqGWQn+4p6?^FKp%cr<_h;EF zQ~Rb9H;2izEAczKP5m(^8k^Q&g&9+t%$;4eJeRDyAmw!WAs@TN%uNh)BR%O#d_cuh ziH;PpHl;&;TwNN}n-()KH<=?X`BU>^=~$T;)sr1cK5nYlPW-awMRKP>xijfiH8-KYxjzM+rfhqXRcuz9d6xgKY?MiqSAK{hbWXb&&y|cP3YqyRcqBk4hxrCw z#(nKBYdrgQqG_M=Beo-^8u8C#y|bmua*e8zSN-R&O6 zmTI+~e`*20xzp3_qK@uh`6YAS&Nxeu`CsQdB$th({m0nPlKmxf9pk*`*zh^wOuT6h zTJ&gaRrO=k>99}8sKDZjaD`>0+`{E7WIe6xvKYl;4mfx)XesEPs z19ImZ;Li)t1MCEs=sZkdA2qP2T%41EJb#pr`rpL3lsjP}@Vo`yRrwErDbWUOz*KJz zT=XXRNBgFC-QC<1soc58nYV+C*$sRFnJ}t-eCEGZEB;Dtln3jkqbt^Uq*H4~UI%u| z*C=2QJ*(dM`5xKuOZ4+COE!dlPXCUv{?B}Z^z*H7+3@>3Kb?Li_-2sPL-g}A-kr^N z>V0yBeBOuu)F%A$q&H5zBtSoF?T+?*^v0Ggl=xlI&4r_}g<_|0Gslt*yZxt-3m?Ho z8c96;T70K&m;V&Hqrti(p0$X%DC9r&SipaZbt>lrU)Xh+Pr!fb(V+j-+Um9VPsu+@ z&yQncwEU-nbq=wQpGEg0eNPfPmkI2VC6U<1(MdEQx4*%jSTc3;0bvT75fZ-{K=5iICq^9kA5{ z+d3z{E9f2s>xcRu&;N>w>|*|x^531z|Cn<06AjY~_`ha?-mf~%U&;=C@8mpm%b4?# zF{6m@Wqo8RL4@?YAqKX&^|C0PDaN5HR*a})5D3itv^f4_t}j(H*d zeO2|=|Bt$NkBjoU_W$=YqcQ_{K|$2mGGI&qV{`F>v|0vCQbcpnczQ|N0@@3RNlI>w zHAaxM0WoPNF|oxqplMGSQc|0ki>K{Z)YDdDniKUjy`Gan+jBs2)2IQX;rsqP&pa^T zB~5?ld|$8MAM=`-=h>IF*Is+AwbxpE?JH6@2EdPO_bxu|SgBI+K_?bSIz zgPWIZyr3&Et|{O}dWVA-+01Jj>MwQ1c?s~~@98N4wjbpDfcu;sd!P8fbeOg%UWCJJ z%GT5VGPgW-ZIwTPk0IN}O?+RBRBhbE0k}yAH#3NRRnD+l%Gxnfe-D#KH#9+mRq%$j@P=hk-Y_6Wig9TzX`VIbu`yEG zTiP*FL;GW-q@TQvF8Y>bdLm<>Tkb1b2M#356&tk~S@qMQPHfa$@RaW&&%eRvE&7Ov z2H;I2fMW#wLa|Yj>57et=>EVlRdXbJXf4h|XSdi0dw@LPuRw#eZO6qaE=u<4h164A)Mdm) zg~*v7;By)H6OT36aYy+~k8}{lMTwV59}TQ=;3r2sdfZ6tzW9ZSjS5gcgV?AH>THK! z8^(~1zHvEx$dr(K6`%4GjOB95>rS*pU_I=KiH!oj0kKigviPfb@qpMUV7nX`D@B{% z#!nTEjrtj7Bhm79TvW82a4P(s5f?>&@)>Ue&JOVM6F!fgEiQ_=6py|+x)u@y_dgaF z6{80XjEiC)?dSo-MSY6g41eS^P!E`B`;WiDb2~0-5I?$-JUEJrI>vh+yuqJr)hD3; zz0H17bo>tAiJvs#gqc=&ezgfne^I=^YItq{Iyj6D*@fJb>`~k<`x{&Td=q?X@1j_R zx3IasNvv@ssuQWrUgkLnO}vdCL1)VX=xGKW?`?8^m57GT$oeF7NQ;<<)!23LR}t5s zHuF!47W7`U@L_p`bgz~Cx;}6}(-7wiJ?ZW?jje+4);e>63!t3FtQ-axzI)*|@qV_y~F8Dhs`}4VfSGKA)Q!>{0xDnTMDbtzl%a zd{Tbo@t;ohZnZYu8@?c>jYGnBw2d;_xN#|G96soMLG{J=HMaBRPU0@teX;ZP24m9N zeT(miw+-E{aCJj~O>3%d2Z1Ks;|Y!b3l^M6@OQhh@qbrVx+8x*e@4sOQ56p zDl4>rI`~r-`I0$%;`L`IB>U_A$%*v~>^11v3ku-9vK2_yYfm8EYZuQ(La&$c8N3(Z z|FY}YpER=fUI1JbN#AXVPqKBkWxgbQm;6>+%j~w|?fiAx@5sk=9Us{!4u-BhsdEFd zeXfDV``cXG;MQM?ELGi0ZCK*F4uhLs?N6v*j9nz#hM}&ZlliP-exOs%;py9n?+Xke z=HLGBZT+yd(d!+vuh(nr95GL@Z|`PqK6#4#YjMyZaw&y-X*$_oD4$0jxq*+f7Z7~P z!PU<52=UoFEoU#GIB;z4_ko-K@(c z_S#NuIZdtycU}6lwomsy-vGSQMLK|iyH45f{^xAz0rRWL*9HvJk-JswDQms{dMka^ zfc82EwWs)!-KTqB_&3&#?l;o8lbtbR{S@#{fL9#@pQ3&7D2*xgt0pX5_~}o)Vm)Ja z>+inkv4+izc@OwI5goJ69qXQ*JF#JE+)dGOH#6=Rz7`B`V%)PCcSdyF+hgFYW!xR7 zdY{)kX+Dkv^C|L%G?OdVFm}V({fu3(=&VwN^KTmWteEzmifK=H{J~P2zwYZ`>}qE( z&{j8d+rii;V&f{w2!?lD6bvULcRcuZABkzd z)>GTST_Zo+v-6P#jWqxt%VLhRfZcz3^?_;Eys*)Cdi5h6oK^J=UG?y5;DlI~P!nyI zUfkd2y=Q4NymO=7W>vJ!I@(lQo!-or8UK{C@q(LkHfla(gV+Qf-T>Y*+72^6#~2s) zFwE2(zjVbT4Z$dE+J|M+j`qLvFK=vk4co`zX=@v9CuTxrOFZ*VBG(tQKF^y!?_Ko3 z|KOaysfC z6T^{U&K|=t7azFnDNYPW&EFlv5k%iB0T;m`RdWLR_EoX(;X4stk$7dd&cG-(>s)Zk zmY^7uSojveFQ@Vm?-VZ=T-O7i`0oPfC5t_{Voa`SGokB^71I0ISd&jsXEl7*jWwwf zJfos;CP(2MS2br|n-#KQome%eFrYhL9NFf(VoihV`_}saWArVWQeSj^cKv*0-~wc$ z;wYa2mJ+?Eei!iuSxE`?UBnwa#djhwT*F5&Cjx7qElK6Um0}Bu7EZ0V_ps4&%V|%r z27v7iyS>EvH)yXSDe?U6f%EgW$Cy7-dz!oR!3Qn}w^xzR-jI*x(^&IP=3}>%%sRbt zJLmRH=pyL0wO1-1tSSll6lYrBgl8rads>Cutm3>`HRsMARGi*q)AJ^}+k>2|Y~3W?2VDVO zX*gy1A8MEGQ{(79C%^u4;w~-XE!VP zSzUvCSD8Os+pwPRNR)4mi?(@HOq=82%T>JJ1We!JYE{SQQL%f+bYN@-2@&=tC9y#Xjv*Y1~hPjaa zZ5ehr$>xCmV}C2lFg=n%P0|~%zm;K!JH7Hs@H-bg7l7}4;%RE@~(Z7>^+YD7PR}nZ?@#t;Y+zMleNj+TlIM!kA2qTC&ce*ZRt!X`ZD8rs3Gx+ zbqx{f1zDT2Yh26v)Hs5y(N_Lnlfrt{e{7TM_`e|CU}NGN`(%k-?!MXe=!fe#_i^*k z1Y*}Y*UA3jQ>^=vD4v$l-{Az)BU?=cvJ<`#T5EBpE!wYZvysm;wjJq*ihpmR-dogp zo4tti${m)c-q3cyRLyzSGVDLoy0O0zf9C6YXYzOLGi^tP5<4C}52kZ!ZHj@Xj-gHx z@Fe-L8DPuM++@Hj6kp)nM`=PC+#?vo-VvniT*}O)tf$1;@9v;K#k?tgzJ_`_)AkAA z>jb`RYlI!UzXrG!qgM&+ve}G;KHs5z!LEJ+z@fGSRcYPWYxa#o2a(LFBvw#1rxNhk z_>A^cjZ+!Jb-?rn`mAhS3z_QxAK_^sGE8t(K`XM) zaN$@_C3;a2xIIGrbr#>UpNVcG(K@c3#-P`#j%+oKohBiAevP~0=udVU`}`X9pW-8Z zOuB_)`$doHQ}igiuk1<>&~KJCy#9@8>vX>yejCO4&p){X*#u8PA1i>*0dwOySw-o)Ul`we_Dxr*kzCn9?qj%Evw;0Ugqb{Q*#gK+*&Gr zKAlH?@m}9X%cRzO$iIJxcHYLeD;rL=C$)YJahbA3=y@m4b*{aX=S%G8ItNOwbe@an z$-X1~Pj|;k|I=I4cjD-JYs7sa@gl)bTY^UgWuhWkj*Iyaoj>7N_? zvvtHe^^L{;{r}Uk{14OF`R-mjT_gR z@haA1|NW$=V(zo}u(jDo%m4MQ1I^I$xTOC^n{cfhsJ&VR|^wDNu zaxiSA2gBG!yE3pbyu+RG?mn)J_4=m|3X$3Jr;ly>mkH~PJSr6V<15za7IH=X7MyM8 zKepk;57O2vw9(49^sLvhZ9G7XRt5im!siyAxp6t7xxX-uH?eE!{klQ#H#1J@_SJk! znLp`nw*t$9e4eIX!SWMe=^}1Q@aT-(ZrXGA=pPm<`d8@bB>I@-f^r0jj>KtoM&UVO4QRWUNj;M5CFi|;456Z-S1i_G+c?BC`p&kV5>cQ3~OgdVhl?_#fYvWcaMc_uz&0-%T=G zPl8MJb0DUlj>QA{!$=~+;>!THANa#D`04~- z;&bA6x-)dogZbSp;7a*hl@CeydKP@W0KT@N+guRES2y^IVAn~pCSq^@0rxMFTO(#1 zn!9;7_2VnD=JDBw*Q9kvfax$Wx%j#fTmgRweC_k`>Gh21n#5TCOdPG+9~0C5<1y`v zkA9T)$1P=_r#WCgWEV=oFX5T?1Lj$=+T&a9k7;`_?4l*vqjK;C+c|l_S3YoSF7wQU zu7kugN1)SbCV8WHqV`f9gJ{$TZ#3pi8oiUTcX-oVZp8m|kaeN8d5AUoS9}A1Vf`q6 z=NR!Rnp^ev9&7G*tjnFYj2PE)f;y5DpBn`K02+$IKl4k#pWxtLbehQ+(k$R-Z|Q+% zx)_6hYVt<$&}Goc;piAd@1pxEb{!MpT_`fh=V;l7Q67+jGL1nRvL~-*H^w9>MRo}&NfOdqNG1i#+ znc!wMF-Mb-QOAjwTl&G=1ErrIw{gkm$8TKivFtmicGIq6``vxs-5eb$l;Dzis44 z5-#>&E4>-J(<|6KUxr`orH`M&FSfv6-^5m=yftZ_gsvp;9srNBDOFXcbyrnCKD+AM zJ7!-74g=uOH@UV!_Ngs=8nG8nLRS78=L#OAzI4!$)Q^DocliHMO#Qbsf8bp8TT5B* z)XSs%ht0D^`8+eGYYBMx)aRW!)?CQ9sd1Gsr_!@_$INjD|I2t^!uxyR^;*NX%bpI- z55iMqU->KcmwD_9-y>hZ3D&gcKZBV6>(M!c@BeLFuf}fsp}2;|2jlwE|Hh{QZspJT zP+U{r#q|`%rSX5*+WgvSXWgIgelPo88uU=tKcc+l@{xRBJ`&_YPSlqyzA)~Fe);(x za^d&rE~|+>Zet(PaL|N4kKQL9`PsKuhwouuzQo>_6Dtr?uNM8MjJ-C#+7P~4VhNNl zYHZ7D&$uq#i=o(lwV97TruNd%y)5`i$AH`2D;ByK0OwEtEXX<=0JY_L=0eS8F>zsUg;?;kJzRp$mTJU?malgE%A72`G zGy92ija&M$I~RXt4t(4XA^)p*l=OGKYvVfspJ@?zc>}%RX72pj4qwUOc@ef~<8ab4`7B^=Ygcg-QdCI0d__a5+{UUeXk{Zi+9tDh+_^G?Rn&5Kd^cf0g*{N6s8 z74H^HEBX9Cbj?SnmBx<>Gy1>(^gRyDZ?8H7=K8@f%O`anJU{;rzFZk%|^M#KHf4HV$e^&DoN9#Vh`)JsECj3uC;rCxX z2><;5F#PZR2jIW|Bf_uzQU22_&$(7_kHX)_6F-EHKmHHEd?S6-BHz<0&5;L?xoLND zPJ;OEv=w}F79wpG=WEdQq_fvG2gCkm^6VJ)d&uCla`YdSx!D{cC&A*(yV)nOS6PeC z&YwPyTyF7QbJ1hDi=y7}9Zwrm%9qWmh%?ir!w}EhRgHaH_W}Bd(eVXLZYI3lZ9glZ zHoRSj&@a?xmgTLVKQZ`l(W(UQV8*73KB_y`RWEHepI6P@X%Cqf)rQ}PjuC~^t{c$( z$k;uBQ}9&r?ZVUL83>Qg89Q|f?K-l(s!jwr+&c5EfpuIs2KOzz#o|ou6iqavi_^K^ zUikhP@{n_rnI8-0W{(f%PT_w0W%=>hS=?El^&i~hzKIxy^gWO0ELhrbbEJ-(SJ`?O za9}$KOy}x5I|{QO80MFk&l1d>m$LJ73GcD>;$!e7nB#xcKhM2$t$l;zwtUP-Ep{qD zw9`4sggfTSuWv%1nns*6`$NufZas*-M)uA!*|X5qCSPjSHyJZSzc=+ZF3P*ytPg$= zH#5L|>D;@%v8CI3q#Mgb-=SY#LcBEZ92+a~)#&2V{a(1ltdA|{>agd!58jS(3Xn&@ z>)7=(1H@DrN8c>v%w~WwHSsR<`uwo}!h#jbskW1~ptxb#z3Yg%ZXRZ~Hjf~7zH|s@ z+QznIvaiu^=-JKhETvu>!_s(9gJoFU5m0=OA!o|~<4 z2lB(U=sjkg^kj2n2XmwQMOdkr3R>d)WPyCHm0!3x>6JAjulRjgqTAz!M-^L&r)vrHlO%Y?HM zP0yV-n(!U$^*;_=f@%GO{V>UIRC^v!?s?4aJD0vy z-YwI?-NHWV`KhHL1`##2}0%eU(6J_6KZ zukfm=8X5W%yi7JV`+s0$=r#V^F&=p)^iAZc=*~hW{|CQ&y`t&ZcoSklCK0ztnOm`2 zXzwBVW*#2a{?~n17Jb(Y4&(zcN&b4D3FfBFvnt!ct8ZP9{DgOOvxhmN`*ODDdVe?c zFTERxfxrjl#EQ_jy@!#k{vV;$uN0l1R@;;NX_em}nO4gS&ZN~J6r7({qcHW+>a)=5 zlhA5eK|igQ6b+!&)|Jre*NXmeT7A49CYx550k>$CzEkPjrNgt)>Vx!MOL@19O{>)N zQ*SV>)=>6CX_dP1)QzRpJE`Z=>ZOBdbxI7azKk3ft$vngS3s*}@Ys3W9pXjS=DkVI zQRLo-#eU>)K4shy6T&Cb({WdDMOt-MWxLJGWEUQ4$5tsmL@k}uDe?`~dzKz`}p`sm~F5YWBo#@88+b}<|W%Az8Ic0 zpR*$smpA??&jgPaS>&Gt?}v#g$itr!NVme-Q$69wDaUz<+ytMayCfj{mQ}~MbbWR0 z{wYs|kM8}>ua9;OjU1(4J1+7tyw$Crm*ojRNPQcIJr{@MBes8kAv075JooW#aQyNK zn|>YthGVCD6RN?h4q=1*_*~#o5^9+j{N-<_2S>S=i#D!QLPB0g%j6Tf11zS-yJQ*8OW3V|_*f5L@5fjSkyUP}LhOJ)4vO5@Jp zo6=)NXZbFmt-@$qP0Xj;Ru<)-;(hEI)!K32NBatGrcBIQe|W%q z@Y=w84?0OfWF$JVuO%CPo@tpazS28#%}}$@hyIT)Us=PRXs{jvJnxv~#83x(Xa{sn zoW=Tf){D=)vtKk?4LpU=$nAV|mNGIaKb(e5wgkLu-S6Pr)<<@j%2IwWj+Rv&{y(R^ z4ez(@`N@Ne>Kf(OU>~lmyS$$BnC3Q#}VXoqSO-r1st8ov6bi>mt^RfT#Z2s{I;#GFZMm>c8*r!+GC&eD@ zyD-QdtDW8cp}~hc@!RKVJ;MKd$L~FgKEGIFk{&1CB3(BH9pC>?!Elx}t-E|k_X}gm zOMC)<)|k_czTL<`U-j*?(oTCTMH{<4jxOi=LE7;1J;8js&*fK_ju!#;oBs&D7*DKR z0$xYgqy5bWnrMp)4S_c9D@h8qGslOh2OnBAZoZ?tYOgi;oQ(WGiiH+#-~n4q$)zFY zkhq1s*9_lj_!Ra4s|garL|Z@OF52=B4(~3ulDm%4M>V{!qb7g651x3( z&h6dOyP-GMRJpA~i{5Sg(tZl~m44>#`E<@j`$O&fnBUR%{L&U@NM{_Uoo3CYwRINj zqB02lP0XD|+cTNJrrzG??Dy5%XDR>H;-h>Y`xyVbzYm6; zn65D`J)*}CdbjHTXK6b^J#^l#a@tVa@C^H%bUU@9xZ(c;Z10IikrD8}Ed@=(Ly~9m zCAQ6T=sR^)$+O~RwO=;jM{K)*VkMk52Jijk>uJ8bH#LVgT)5QN6ZCW9brX)%w9T%< zXWqd+td>3N+3E|oHY`C07UAlLz#_Y*>jBw zuAgbvH`mgju`4YJKA~7g8k-s_4rfKo3!F^62)aPaP z|1m8WfTvhF(8urEws#}%x7PAL=rJ=gxzos3d38@(Pw;5FE$gZl)nx>8C6hYi$kSM0 za?2OVXXwZb&A;aGn~dX|v|&Ezo&FzJoAs|2;s-Wn(Gk}Bxy~o{#s%$ja?&x04c+T+ zu3l7bnr_Q8{;sUc>Kb(ZC9Ar&A)fPZc{|LJ>G(zSerO%p30!$YtRsIV=2vTd7x6cL zgT}8t2(OF_a!%&#=k)60lj~>7hxFg(newkW_UumhpW<(z;fD%>8Sq>uzvdgj|2+Iv zc?o*7cll=ThE(QIF$fmlf8>7&>sNe2F7Xe=_Fj&AK z`VdW=3*MdI>`m4D4le%-`qkd`$s)7<)U9Vf_jv|hM>m`oukttN4fULXSMMkXud5V$=fs!bxC?v@oWtanmCT`V7+ZgN6n~%le~7O9Z7cIa=&ne-QM=6Ur3<}hvGnDO z=4rpXWs&yIeQ@s}cm&HV!9m~3t!1o6 z&JM{p;`CJ<9ec6y+WoX+)BOVd$i6W6Y^}-`Vnb0`_FcC9R(i1Fg(G|n{h-5d-A+9E zW^%KLp2cVNT;r7PAs#{QdK$BkEXVJ`-k`QTEptL=k);?#yQ(}hddHlVY! zu1_Sw_=4C4deF=E7Xts>A?V!+_<<6Ma~_V4IRagCB>LSba!3pbjk!J;Zr6U)nCHsY z1aq1HoH5LMEqbSwi8}|M>iM!EhH%+=ac{Ei%Oqs0ePiYUhMSH-`r-p@l^Gr_*cG<&TYehD7JEvG- zyWEZ`A?+JGpKxLXJEwTUW+<_1b4}=$O!jO;&CFYY5!!qxYhPAq*%It>PYw(FwI@#> zW5*TtwN-sd$Z6YYFSf0l)K)@2tnJLJVC@9=Hk_3c`rw=goaEMAVfV3VP#?gnoB*Ad zp4mqMeN_4EyW)G~i`L#neGI_exTH`9>qxjO8D?hAVr;^n&ueCu#N~6ZGr72w_c66< zPN_H8+FoN?Z8*V4OK6O<*m)Aj` z*FvY)K(7nf3(dzqF~r^r`Pj4B_Id5ax_TG)9FCj$FS{nZ=+f4X=zN`vwu(L?ZT%kj z0`JG=oH0MaPlr6TrTGb*jLRw6%o!xcrZZ8U%z+`^TlqBN*$W?5oF=(mGSYcY`KE5C zz3>f|&e}XQ?%8Rf&O^hJ*na*BM_%QQxnD|bY)}IBQrW0{FzXxZ} z*NlHraM`$~eik@9SG^xoFLLaRaoF=9+-oiboA|T#ESZtGnLm&X$KJ0`U@p$SXV<<+ zd-l9jLyth4vT3lllK(daK9$_^tIwGAuWR4FlzltTwQv97723Do_~LH-42J!fF-alW z+xVX&yK0m7rtUq|^TFHLr_Lc2{{eeK~a*(dw;3+WMVZVvp2J@b&4*!X)op%?LJ z`~$hY*nfL3Fxz?+*Nttiy@op!$uFOVk1uV!=}BuB{Sd?Lb!@iK|3fB{5?U@;{}7=7vTxzA@g^@8v<2r zv(u|M=X1Yly@C4Ed}bTGyz&X?DeFScAA^I;iNvR2H__Y)hw>-uE_LDZo6L#kQS(bj_{L5U2!bvIUVF79zprlo)NY$)kitye7YrL#Kzs*f?*Hv!YB4m&oo(6 zFR`*RXW#r68f%Nc;$+9|8(Vw0A(}D@irzU*mFBEP$}eB&EoxZ-p}NH zD&+^`QG8B#lx@q!<769;jxDP!ikHa!`8EzSg}X1B@R-Hka5DHDd!Je1r{8%zcgyI` zgW;LPwOxW8pE8M*IlXcob6&{Ye+C-38oAB=b2W}lelg`;*yg?8`<(7g@`r*i`iU__ zSKQ`HG}}f7OzsF`=LC=D?hVRha!y2REf|Ok%_aA$Lkm9aB!0#dkM5a(4m!N$=btp| z-^8BRg`G+H(L1p*iB38+cGk7#=B;;opZh*-itlZ>$RuasJJeY7=9tP_=r0dHqT)6c zi*XIM`MfMsN#Bd}rkYA}7A+>mt`a?r`-3Hid@Z6a(e)eD2@f^X^}Cev;)y;!$eW(* zl;EuS0dz8&mNq_4jJlY@7I|Cs+(cPnPH@BLL(FG3ISVFw3V_or?h!hD~7?WYYf zmFeVKe>ZxL(zdb6cf$X#Aj3qTy%(Ep?T?6Oj%oQK&t&WBxR`iC*5Uj3N8RTgOF1L= zgeUwx>|m17$*I9v-JEZ4{J>jz9NEw_(rgQWr`icaZV+EtPAsBtjG3-I2XQot>!{o@ znz)rG*wer>ebuR|@HVeOIj?PvKpT|5G?A^foQ;eaG zZ{k)TE`nCLZ^x#Ua^_R-9`#PB-$>iK*FDcl=~~0MB8Q}7rM6s4994{8PHFVztmqwhBkpBh2XcIV&AO zCzTGW+_3KR<2*;k=45)U`o%}`W+w68m&O^tBdZ>69ARz?0#^zBoQ(&by7kIFKIpqY z*e!aU{&wC>$$@Xek3@U!SjWE+H?tXi$XEKwkXfL!SOfgQ;LDbu z^pC$|{jcb=lur;HUC(3n40|nEVBA{S_@7e8$WYtmw!r3c5ew#i{nefG-lWK~bI z_oG=>c6XTbl5Q?e@oVt>j;Xqg^lbQxnInH7h_17vnf=_%0I;ZU6a7}1EPU+ZM?U0- z=GumhvBuh@>^1|J4e;A{;J25)haczRJ3Po8?vU9nogMlu8)16N@$F?M`Rv>hicu83 zlzH%l%a^OzlBT@S3C0sZH!Z^-*nyr|LLG~<1=3X(RQ7IAdD;v4`Copo6)wBigl$-2 z;tn)-vH{dULz1!fSct>vK<=@&&g#FPysvkI8;|AA)0con@f#V~Uc{S&CJlcr`ebEq zD)V}z(_7sj+$eX)L7u<7u{YJ?Y*+z(rc);39TjSyJ2LeBpCKcobKuZb+G~+r!#P*T zJT}FLetH!8qy8_bUrybQi-(3gpcTR1F%3PocUU;W|Mt07={!fHuEHn<*bNqbHm$ zJaED3>kkNq3sy1L>~lMIS+)+^5m$gsfOrhGZ`{p3}_BfDryOEGwiJQD1g`atAc(u66C*#aBLkZ|{bu3y8BAlv~waoBv)AZe~0VJlIWvXH&H8 z%{DyAEw|ZiBcqWk9_Aw!o(kYoOub-AM+X;78R+K1>sJQVD~ZB59~cM2!XDdR|Jswt zHhU9g4gG1azmVSnWJq&o-TuOarlW-|FC8sgd-y2p_@S&yWX^>qoW_}hX8!xq^FqGs zJ>fCqOp+myNNmuX95_BCno9^>RlCQhM6xXUEwGOb$q z8lCey^MSdPv1cOh?dRyKKH{0v&{sRqQQ*`27p&U5vDcf}rTtWqpEEn0e=f?;eCiGE zFne>j$w?nVzRuHeGnXS%OF7>?37yN&XC8UM6*F23%w6DIF_wkuADwW>_@ZwG=}YZH z(;;$l*>@M+L>mEOCiDMh>=>$^dWP#r4ZcFQLrinkgcGASn*Dn3h zq+4z#zH&I{TU57#kJ|MU>op%45zj|)WzE2=c1vk5BidFv^%Z}43H8?z>uI4Y2}YIQ zL;cmnTqwRmaig*LG7~oqh?Q+ZpDF@hMZ}QC`-|$g+Iy&~{fd*7Tox}0(vKUj9i&Yc zzlGpeFg{70+9=MK@$3oy2m0&u#eEj>PBur|hSzqXZ9_R4H0vFk-emj#Tl|mJJ!FsB z0d1lSj?9=Z5I#cOmpLW>m$u7<`mGiJmut#D%2`y#p zsr|{pS!&0yADc4NT3E4S!sv=DlXQvV^#8`)nAPjB4|pmHz^D4T+^N%!io~n8tbx^by2(V9TFUyC&oWZOU5n7FyH;7(_F7#)TzBkRoo^EMR*g^c*UGxvx4>SjiFRDK)~O5kRO++>_l~~x$@&IoTBo9ke8qJ~&qTN};2L8EW2|6J z&iBthV~pa98fz76%#C?xUi;SZGVmh)F&H<@&l%5JqPVO$3oa{&2S1|?Xms$ik{CDy zyUS0`)~0xg3v(c*Y!v3u;I_p_qUGVU4xh5iGJk{1D(6T!b~WvPv5njD%}w;7{|VTd z-+-1MIGumsX)C_|-_jE{zAZZ*{J*IB!3ORN-rER0`{YzmTS=TsAN19UZjAerj8R z;ziL((^=E9Nht1g<}maE_|0nWk(FGOuHc*4HVYcRd@pdU9$}84LoF6B$A_8RJfaOb zYF*yN|IO?-3$Ew9679_8Gl{k+m!mdhzej&iJnZxi`gCm}@)fDy>xW`DPY7;1!CqZ9 z7K43Exy79LBl%0lv|I%*ksgyvJC7+=HC|^kSij#1h9BlxEqa`fG1Z~h5!1BoFypKz zM~L>K-%MIN;k`+mWyY@H0k7`3)prkl2Q4$>G3wW%BkDda;KbfKmh+gwo}BW`S-a7} z70jxNpE&_M^DjZ}QB)=N9E+p?xgvSw_{-#+cYF8hu1h3O1=8Le!ZBpB|XbHgDP4n7XM_9Bs(;3 z`d&V?sD5fnV!iTQ=9%GL73BOc8d|hhWiz48?39H1c~kSliml8D%s&a<7SBWX-2>gv z$6k;ZZBsNayPy4yJ^D>(|JtF~)c@P6#ErL>-`efcee2L`_HK{1t=#1cc)z@Sd3R$B z-5-vjdk=iZPq}$hxkrOFmQCL}-%^&8UTjIsz$4*jRfl=3M%`&$9L^u2OoPYzqckoA!b7r&dBQWm+>< za(x-J9lMVZ4GVsi(;5-2o|=Q*hVsgNdp5tGiyOh${GFg3ORc@bUD!j^_v^s12|U>P zLEFXPJ*A}z+7%2{oZT}ko}aCCCYyb5fB(~7XHD;5&FXx^+42m|NW8lH`C;UuWIlzz&6-E>(u@o!$>?uuBW(rf zCpHJ6dyYXozZ4wSa@L}jdR5p29tRg~r+c3hzZ) zmj_>!vCs0SvYtWfd3w^m62HQcr;d#Mt;ejtn=*!+acR@Y2@KC}W_|7P z_|O$hS2h3dI+z^taHmGc2w%Nrr2xa&mRlHyAAZ@)e82Rq^6neTJw5YE<5%QyM}79> zx(1CyclZ_aUpi%^=3nt8|7v#CFi&fw=GU{UCREMo%tKyBeauzdjTx!gNts=gv0CfC z92c&=))%fV()t;Ak2rabZN6vYq$w*@&H5++A6kRR*oO>vSlRCaQ$iLpJt<~xu#MQ~ zMYOJWL)*fIVQ=cLvEP9Y@iB|D-?HiSRLK63-11l9yGC(r!|^eW0OupYIq_>NlkhVS z;S7n#jzy7f=SN>?Lyd03N@>*AF>!YxmJGTclXO-rqPvG868ypc(5bK2L= zW!-pNmt=5$=O)%Ha}|jz;F;ALiPJmgns_mMm#wE)E(BlKgSYFz-?hY?T!U}IiL0{b zY&o`2(YVPDZ6f~UNAN?fC(*5VPP6z>4F9T#&eOe`mtEq8KHA6Uzmj!;@7G-eL(fC| zBWR=fBH~oeLYs%7&9xbE_W2~mK%7CJ&}O4en?>|Hk8u^^w{U#U;sG`dJ?YR;S(Jvv z(?9G!`gfrh(UN5ISZL<=tj(TbCh5;h#@IA5fpuCsa$J2ed9ll(gBiy3RKaH>ah}#H z_-y0?@`l61;B~Fl@Y!~+)tbyamyDcHf66m%@0xd49asY#cdne(eXe>w__uYFZ)1>; z+NeFW;(#Y<;$F3NJ9YJ5^X%ij_+pwITc!3hcFYTFP=58zteYuA zP15|Y#;=$^++SaMv!^G4aZTa=V#$J%sN5=v%B_;9+`^aMD%~=EstGIabnF==n~sA~ z-cyntvN-#GboTk>!ZywZi@&@Kz4v-`K5Z=HNM$_Z7}t2lHvyWy0KPs99^#zgczWl}fUL2^|GrI#@eF-{ASv>jFnfH#1uL~cCmILtBbm%+-9^9VbX-$U* zw?ixG@ZSvRo7h2~!GD?K_inmA{C>s4a5rtmlQ$$D-RTtl$=~HGEn3m?WDa~`T(@9o zn&jDM$4kM-4&f92D}3#Fe3mX;to_9<3{}8T4Ge3dFjPljs0M~LQ5dRYU{K%7h$9v~ z$?pdGNxEM~2_KX;gSUeB=B2u*drWa!Tu6 zFuQVa{0}@mb*!gAg{LQPY5a<+i%hub;@oi4E^D7B-O)$fG3^D{E0>w@-Qe}~%A1&% z8=0RkFi)RnzCH)teU_Lg=geFLK4#joLl?*JFtzy`&ZgpbNd5#gA-*OY*)j;2Vr9^D znSmXHR&=@ud@KYn*MpzyprLD#QI5>Db%Gc;F9lA;u>KzX+SUnT-evOc zy^ouHuk!9(^7ww~1n5l-(Dq=yE1gL8<3?x2cvvA80EwH(2Dqx>dgJ2r>6|vw!9>MMJzwI^@%EUK=cWlHdp1sfJr10nse5Y;N^b9F4W|0g;k-F5Gmu%kwH{Y| zvwOx@;#X)bbl#|S;K=R3ct>srxSvyUJKb{R_Vz2tw~cL9`($*0kTraK{bur+R?*gj zz@c@QjttfvM;`7tk{qe!x%g$t8i!x%UdbhE9DZ4{#^IMb^SgxmD1XmdD_yf@_T8Q{ zb!^@LF+k4_WEv4whUytI-=3&sY&BLH|W376|)uZKK6+MgJ=)7As?;YrI zzEz%$2AXJRKh{Y-@kAfA*Ez|AGA+|{kp16g%C*yWDc`z(J+)jm1Sc+JAbnXa7VXML z<^{GP-~`(ed&vA}(xA6$Dj;y7A(Tv811o~|pVva1c){<{OzAKscWoC#Sk964U-Am5G zwehR|9bZj+*Cy!QT9v#}@yO&wwEY9vAZ>nxz4JLAaz}c(`b-gC*qbbaA7-r@vhnbD z$sY%PI>6b%rQ$E%mZx(WYc$_7xFWtR7?zJld+0mhq3GYwxb_Fx9^^Zdt>*0aH2GTO zQ`B1R^m>5Xzt+F14Y={&qAxjmsc9Lz%0%J!?3FE`7Jm8~^Q&{D&z5Pw~rpt(eu^&xd+Im!G7D8dk^3DRG*x4cl^nOmE+;ObB~SW z0eI;7=Kj0j%iUAg(zZcI7tP+w?-FRuwFMfUS-kuAnDY0iJo`eGzwK=0dAFPLvOS!c z1H!p?NBqH;m`{E=vvm{ms{Np zJ_h^(_a{~?@6IzLy58E*IN_D_#v9kscWb)Y_X=?yuVagkV27-)^z0)hdHPz)XAMuN z&-!6OkNgul*C2bUNise7>cgT%Gn9QUy0rV-PYg=}@AY3iqYOCwz>&@G#L_XL;lT4W z@R%LeKJ3yDKTRLsC6=_9JFnjcrniCV72uH_K)%4YfvXp|+JNg)&I@?JukKJ{y>0aY zn-AEKCHp#oP3unm=HYWJg|1y%k+0XuS?O!J1pLTH5FtLak6xf>)ze3Dsc!taZ4V$8 zLUA{1Sf8T%Oi$Bo_X30VBl9hPeL{fTkm&Fhu?_R_KQ13?EnJ81cOAapo8_bZo2jg? zeqh3C#S7!3Trf14`v7HHDbq@s2PxA?nV(cYIH57$R4&1%xh^Rod)<&(Id9xRO#cnm z-Mz)+ce%l_KX=3#JC8|(|JQRypxOJS7r}8((-W)0kteLMMc%pEM8#T?FDs>ORw4L% z$=^MbImn%oLf)flZ{;L-R(z5fjjtd#i)T~DCuFDX@K$o?>tg>X_6doc7vs5)=Y{?e z)8qqhw7iu|gac30BKtq>=zl&q5zRMJ{~-TM`7a&I@8c|Z(u8Rp_(DIS_wC-w4Cb(! z_wq+*Y;Q4!mziUCj8nT;A85rls2r{2j0(NQSmUjP`XcZhDe{2FKuH@h9*J{~KlArp()vd6hD+Q|7JehbFuZjtk(2FD1oiuT3$t zBgtCSJ+~jE(uLUCRHi6 z@2}nvIM`AUyu`L$ErFk8T5Y++k;3Q6H^#f{g;PRJPs|Qy^4qs5JJh+9b9Yb9VNdq) z?&d>g-#o?La1OEg;=C~Omb@fWLv`S+<4KP_@8$YUENJKIA>nr3r<+fN6qme|zS51^ zt5}i(=HXz5Nv@wn{3i5#zBp@Jt`ma8t48B9v~zJ0U)_eitsK6&hggb=7M*QL=#o7%i+sg-JFH5J-}9iAa`@zK zVmj3>djZ-V+aem29k#!(@h#~*8%bZ-M(s0r&F~@3f%+YSU!?>6qzv65!X73PXSJ5n zUcTC^!A9dZ>(Nzn`r8|4!~XtQVCTG}+V~*BInPycGHxdPB)N?9W-6ay!<5n@Io@AC z)rO~w`uG}ccviA^Ej-ct9C4)kM^X0pq+qVf??m2i_YiA>Jj}x9m7Y}FPz#=YJ4QnX z#K2xNEEM3`A84xteyDkp?)YIb#Og=!sCROP>=-nz|C!)Zwg%-!9VnZPz2_3n+__!C zc@@pA^mffbTCP>u#+;oD7Ab06gc%&p2_NEyLKF1rm?@YeOC`q(+D3;g=K3p?Es4e|i*{VN zR|B&-xor^ZNPOG>yxX@*LHXXL7X{*gVlJo=I$90yJL%%`b=c(3g^ygY(AU#Z~J3 z+1Y6CND8!ffyoh$Vrj3FacMvJ^3~SD#!aR&lRe7=z}K4Z4LxYgsGpWEpY@7=B=@$b zy|$YEchY`VdBv=}ZC0i986R>=>s5Uobm{$#xW4&3K)+^!LvOPAPfldcQXPJiIi7Q0 zz!OV1zXG1uhp~b4Ok=O;0^NsQtqbL>FetOVA~QzZvr*VIL z-;BP`^o7bk1eQywR|OA_#a*iGqwrbr(%mt{QK)pnKiFR%LMz&{3~VJ{xfc78+`NF6OJyj1{@C7J>bce(m!JL6O@?s z0dfSSfPdi=+ePlvv?F*j{u1r$oj6<0a&TsS)t}>L5}R(n?;BeTjcyVw?>b{!DP4^7 zO?A=oI~~6Fs=35x>k^MqHu#QH_IV$)^|mv{C4aE{ebvnJ*)eMCC}()5yNLZw;_rUj zUuE-rc)a%DJ|B7l`v&gSu=g@Pbfm0RB?tV>m0$W2i$2r)yUaqtsQw;W^$IqsQFg4*Lx20$fy7~nd)HZ) zKBYX)z>=E{Z1J3J7jE4;jf^!wT!P@PQ#-({7%%O02A?6fWqX>*)jp^8LbJ6T8BRM% z<;d{7GiCUzCaOQ8fvwlMM^_Ki+?PSu%aLKO{^vp8l{`;j{H|WM{R*q{x5CYrt;%)8 zi*KKaeoVRTpR_8g`LFd_g8Yz=`*+C9t)9Cd);fuqke_eGPva!&-x93$EG^3J++#39hSwYdbPr@?!f4cqaR=?H3_Cfkl1ltj3G<8-({J zNB1gyYw1d7jqIXr^jMpZKqKO@ubO+Dy`bdY&v_4>+UH9OCp&t^Qsf@IH%D@5`x1CG z^sxPFR%L*_fyU)=+llh(7TPF@>bc}C8KCE;@ZXLb0^U+=!Bc^^V;3>$$V1zP`I{(T zBLAxRP%ICEPrVx5BfaYGk%GX~&Us6X|Bg8NJr$R8jA#0P4ZOnUPcD2hI0?4vpJ^4td{2XxNADelv)+Y7Edf-h@vbIljK!!=*R zUg~ezJ=(Datl`_Ht0>J~1dL7a_a-XGK$>H7^UjZhYZiYw45!Ek_jW+AQDtHeCb2q??Y}&^T z7dzH2$^<(cd^aEKeNJT#f>XOppPtg64?%XO{~Yb~*GFp$9J%)g+KT)QdStB!pvUdk zveu(?xx~?rUNxf}x|GaPUz=T8|GY2M&X|5f8*PW;a^$l(K8=`HXUto54l`YQtAlYl z?i{MV=CPJD)A(8(nD6%4`}5~$M|>ebo6Ltjm&YzJJ?ZS@)z*^}k@=CR?%~3Q?(u2x zv~iMH!oYtzZ5<>hgy>>7??mIVdm9g9(z95*h-wc!j*x&ZK?|_!PdaVAzMH}`$u&8^k34MS5gNquv z?pw66zJ5{TT2l$nT-;cIU6FOtc!iS>;u!JrjTbp*h#IrWcLwkF(I010S7b6C!IBRw z`+#LS`-L{n^!x=JHqInZf!ceVZ|XGO7TqsW_kHRrKbP96OZX1C0L%*8H^u)Revjr| z;|B?qtTp6Ba?9H!Sx8@2#XYk$p2rzW$?>?HA7BsL z?wQ!tj*VDjdx3FvfH%Q${V3>*m_KN&r(;@h1$R-d=%@(hcHYYUB7^!vud7%Jzmm@5 z&RuMr?BKh)@5L73`U(77g5gGV8e|{31!rH`j~D;Ws@w#;@{=T@uS{W#ntyEAi&SL5=I!V}9-ghCyod7JKW1)|j0+wdA1}w(;z**wF8*x;%7efWp_yud=6bqJWM*CWOp9pwE4KpGy7yl ze~fx}F*&2~6tmL>et&&7Oe&Ai*wyWv89k7exZ zk(KN50c`h-?b7_7fF^7h_}1FYr``+q6h@KlDpY33|Vi5**|c-WvF2P?S# zhR)>1#Ts$}X&;}({xNUzz;;zuI^dt7gEnNMaMm|obj@_${Wp9K{%VhxzybLsZ_DJl z8CpxIs52L8<0aZC%w&eRL{&~FL;-5_nsr|XVS zG$23fN2PUqa|37{dOIhrZ$FEk`eWb`t>crhXKAt3-^4)+GK5fH26X@8JBd6`2TY|9x*GV-`9di?223AYg<)+nCi

O!KZHaRo~Aiiu@DN{m5}__HA8-E@qW2#(i(b%Bt12zV4Ud?;7~* z;$x$&Y{S;NDPv7lHgPB~XFOGPBBP=zX8fuuJ?}q$b=BJ$tEyfM);Ua^){B(+glCD| zQ!x%7?fVAm-Z`VL9-8+KYjH0z8MBsFWECx4npMlQI-V`KoH9??>I~|{P-npnDpN_B zC$q+KMppyh?=Ez8yh}fRV#`i2wv&wQz%|4MWB?HV?yEkU>8mbbJo~Y+ zjA0CY`P@fcmsQ_rO&Y(VO7{+o8Na5gFMH*t3{TYp`tSpPKJAn+UX>5^cVEWps{K3{ zAF&d6x3Dj3BZx=g|1td^L2PPyMOJM&cdYWPgl8{gQs!}6os0kZ{P$h2GL@8hGHV6< z>;;=+zkD3#kPrMT&gWmqop~A`mUiO6ia8_7MK+u@>tLThGT68*#h-V`5nDEM)=iFT zM@reu*?ec)%{J+nD;ZxJ@`CJi;x(pQzoS~^+db8EpZzqRTx>=!_>L!yItMa{{4IWk-~Cj0 z6v-&+(}sTfFup!b_z}uJnR?^!>K58;#h>@+%;D9?_{c}=2z>ll=Jf_Mr`@6R%o;2h zUs+W*X?S%a^Tb^^9WMswcKgU@xGRq{3ePnMK4*zJw6&J{s`o;2pnMT)pz}SSIx5?W zU(1+VhF7c39%!TdVm3#{xozwrjZwP1)ju@WC1F=lTbqGPxe$)_0e6fZUahqfb%#EEof3X`K_JDXtANd;v#$B^(}(0U%})vQud&Ps&W+|tK9(x~C37^IIa0k%%#rThD2}?| ztU0=dIhu%XfP8U_DXTop-*%3&ska9oM*J!dK1f~7!(ZTscenTpeup1jU>$Tndtlxa zOYmprt>lb<{U-Ke88~1CIAC57Z=|z!Zd;^#9-kt{q_Z`hIdCzi^ssX@JA$}Ox`YpYvy`DQ&3|mdsO6FoG=kLW4tE!eFGrZ)C!S>PDcf!Iq z{oME4`ni8cU-k6a4_FLvSU=8Le`uC)kc~NSLoUAGHo$Ex{m(3O>3?OZj6q%j{O~$5 zHj)dH`88~JQr>9YL-|t5$~S8aeay9?>t+p-k>OYJ`zBz&9@y)6*OzmD0>2l@gpGU~ zHsHrMWPBdcNMj7KMV;q#Tmld`nQ*vL6t+fFj!fxEzo?A<9 z+gjs5Ha1~3^o!}y)eE2@(k_Ox)X`pn2!QPlwc zZUi4C0#^p`m9n1NqiGj!sg6wDQeDEhLUc%V+Jf{%Wd{V;;^c&ye~+0IU41g8=HL5W z6e+!>y@Szcoy&fN_2h%DnZ+}p%hRFH`OxWU(CexAf?P+QCA;N^mult1=;M)Grh8Z&#DDqy5nko-z#nc+ zQf&+|k*4R)yNz|H`6QBun)u2!xkg`}UjQx|>hthixtF`+s2}`5F;9biaeOO3!B_Y7 zrvE;`;Q*eq?`Hl8I?)r)FdI9Rc!mo6=0iNgCVcWOo&lSU#WUcuyMh?_5YKRwIg%gG z%FDqs={z4CN2NB1EWS>HB`Zz$?*uXBSd=MRN9 zpq>Q>uzmup_hz~}?oU&kW&hUWz;>_M*S!E+(tKq6d|;H1*?#K0#OEeH9zKGto<5i0 zN3izRs-{W^r3evX(ylmH&AvfAGLi0<$OFBTn+5idh6S?=zBwit**@a51j0W zEztHQ?4=5Pec$E`chdEx&~<2lMbifcXnOfYcDG~rKcAlaV!G&g{F!SG89^HU=-{F5 z>cR2u?lgQUe%+$s6-faaE}ziA{YUXWH|1-H$yo}0iDo_)*mK&`%8dhBhxy}|SFMbT za~l!6wv;h1qT31JHQ~ELXts+wDy#SDloQ@Q%HDSahssregT4TVY{VWLqR~I+T$FJS zl<0IK^_!s|j<}(2i&k@9j0pc0S48<1(Peze3bu#nGQ8B+Xfm{YTsTce&vQBbX{;%f z7oE~rms?|WT4Ri4j3tcmr|5&0po5&3{L`xZxM9{91^*qBs~Drx8l&iL5iqK(#yEHI zFn6NL$Y+3YF1N;s9+z<{w@hwp*EmZU=S2Ik)*|$S>!{Z?PUtN#bsuLoWjEmqE|^7E zcavAP4{i2HQyKS$Fa7J61!=0z)(ZA_2_Kiv7BI@cHMCb}>a;=+FNF@e_z1@s&^FOP(I+PPqvh)CSIK0A~q~BKB{7oZ(K38(`tk1Hp3d2615n>vIAcw=%Au z`vf%Z9lq;mUodE3iaSMr$%jmrktj0HD^(>Sef8g=sH$dSN%S0`ONJGaT{d#;17 zad$AXr~DjKxhFxnX99H19;9pBGmg$JNqL?`*Y|)6UK@a4wo=V@*ZVlovWg)0)VK{7dBE zcKm&JUPWvIH0_~*aqjTG=c8XP!yjuFpWQZ_rD(?n z{hi@KJUt9NP0psXx7&FOPlChfMC5|FzwGtQ7I>BA#9vBtC)tu)sCUkt>qwRfj zLb!T$RU+rPY|-|tE#PU%Vyk)Ik9`%8#h$84jKGI%(Uz>0BUV<8h5xnQ?+SbG40{hf z)_aF(cFJ;zF@g8bP(KaZTefHc{G)pyx^8~Y23HD(G5DVgHb*CHl~saE^h4!z#za4a zTU90zA8~{Cq8+1&lM0R1Y9HN{bnqM51EF<~WuKL?56+??1Hx&@;VfuKR(BdA8MY@H za!VKunSH`va2Ne)EmS^4Lt0pamI>r>80cgTpe3w9Bx~Siob&TSv;SB!TQxz25X@A zcTk_T@mREqHCR3{9-4~{kvSC%k*tAWTigj-b(P=>(KoGu=vx`(RR;Q&RrDj?2WeZH z;?;uVRlD*TQtr^)6J6`@3vhvGTq1E~>jnmCoV5-i8h7?Oh{nw!rYuC`jx-^A(B`>l z+})pX-wpJ@ic2C6PP&lgoJ+ye48E1#!{Tv~9hT2bb63txbw@)-Vu+nDWWIgi+ZD)` zZumR5Ey^uB&p1B!^BKTLxZ9OcS#=m*@dj{s8oXj8xK_^{@UHXtJv~@Q{N!}2%!;ad z=64n!(OvC#)B0_4N9Yi@lQq}A$cDFQ0Y>R;l#^1r&n4(YUI3;jGs+!#bGqAkbDDc4 zuqhw>eCk}!r*E)7!E`_US$r69AU z@RH-^OWkQVk8|J4{Jg|R>-i#UsrO~`wqzZLHz*m<*L@t`ppNgAv`u__TMqDSVT>hw z0=z*qyg_9bZ=m*>Q?>25`4Z+Xy45hJ2W8%_TsiH9*Fm4Jg*VV0Pl3ESXY&SU=LYQL z4Jz?b7e?nye2 zyvuwnsBrza%DXL`iN8nQmF=J>Ugcc!uF8jam9yks##q7_|GVYgml&sbf!e=8-fj9D z4D47FZY@@U^I|> z+54uY`whyy$QkF7dut{4mfhK-+^aa_ZCuLFJ3di)n2;v*i| zNxp=T40K&D^{x1U!M>~cExRNB2m7a?7b!G{wC({PkUzRdeEo;`p7oPQ;0af;w^zew zr?P)!cRUQ<-pKQO{?D-fM_WF88$J1_{{pWge?{dI5L_kTY3yL+A2(t*dZwP1zB#;} z4H;K;O3-UaKPCQTHa?5;<&v$^Mw_y07Gu|x4fA{0GKKex?XmlX_lx=jY?ab;-hp0F zcFMVYL|f#iG7njLIv@R?Oda7EWPGR zGiKfb?5K4?9cV55^fP9hrQ1wq+?KwS{#AE3yqW5ZVJx43Yh<64jN1TQJ?TiLUkcZY z7P5!_7CNzze1Dd`GNoraac7uJyA;2(d(D zULeX$6*$q zdUU9X=pGZ%HIC&hjYCg)3Fm4j{C@@eq#wU`du}|fy>uz~d>pz5M>{EBhdot#+Z(_!Cy>#0NsbE}(==N>;QUX#(-F6!tGmR~aGt&Fo6ng1=mLvqp15<+lJ2xXW|{R-@K;=R93B_PMdvfdL2Hb?+=b~kF~j;PQ&ITUO{6u*cWf}&cQPW z{qcM4N`ABU2f$Tr^~jxXgFi1p53mzlqVq78eN@k$a&b=j^86`2>VG5SQtpIt!1FG6 zSLHterUVN)J-BEwt5zku0j1T!wtqJ%~u})=t;0rsB@Co=&Jr(qyT3NLc|0(%L z>G=t4jF$gYu+Cxj@r&qwr0+>Y=Q5T(vLF)MI68@X4)R`53H1=kQ`om;NARA9#5L@+gFw?7MvABN6hOss*+> zU|Z$HcLm*pVEsh@}*o>j#E68^iB_#ab-exm-$eEzQ(tM|*!@|UuM-`hD4oigTZ zWXveyds!dZRi}h}rLb39zEW}j9G!hNXRH_fias2R2=Fi=zQgjD`po>r+*_adbTIx> zMfUnDm8ZBE`qt?$1)ZGBM|{T-2l+4U*dIInrQ$7rsiWZ6{WIh7l?wO*Nq@h9I*wT( z{e5NCmhth`iOi35_o4Z;e5Gay4+eaJ#8cFQQ&i8F94PN%-bYhsI%|+dSxb+8OMJEJ zboxq>GvNPH_wMmgR@eUjerABoB;gX05D3^zf@l(?id;fkXePnh5D*19y=dDc&`Uy4 z8(Xauk%ZWq5VVYn+8zS*g3?-n)?RGu1nc)C#2W~hAei6#^E@-j zBwW;f&-uPyzdz6w%+{Sg9KPF-?r=RqR4e%+CZTR%)cbCq7F5P^?r6JW6<3MxE0!#J`~vWM1pw z<~bWL=n9N$GI){R;owC!^V){`%bjsv20ZwCdP;!p;hcxL&)Ko}iT_K7X$#{;ILxMO zJ?$@#l*g{E@+a{zWZSrj?TeABjhQe2H_FK|gVYztOv?2^y?|H>`s48CH9l|9M@TdP zZyEs{Bj6W`jgm}PY*a}12PRg{k?fIg*eE`VvI)dTB~bp&Qto3xu8+e1t2)v{ZlT;i zpn>T4C|7iR6mZ+|QLJ^vM@bhUc~Z+2E(dlWdBC5C25H-li&I>b?9+>=r?{vqh>Hr4 zGvCMO3h*Z$Yp~;v@|Yg!Ac~6;FOxp%TkF72j(GIAk=T9l3lkgVqkIOjQ5n?P1-~|o zAsu~VDtyS4kb4!M@*|98D&=)2T0F2GaYe;O0pEbwC}>&yRlImWY!t9f1;$Fz=C|=v zg=3?BO4(4jyd4)6E+?D{zh}io(Vu+ATY$3zygbh5!E?n$F_+@eH-*i4|&z#F_tR(%}$-<#|w zMaOUP9se;CjGJi%=U1D6^cTeotbynHpo1gmkX^_<$sWb+vcIwQ&)31H_AZK5cmtd3 z>%}8()(8Qbg5p=f9hn{B8@!lloSBYrYjI2*UhqQ=!Sc6>$e-&{JYBT?o zXhH8q3-6alNcURFuj>K#GYxUR(39?N)7Uy#qe-PEIF9-0Ag71&di1cjPvbstjqM#^ zoBm3EFnyvwn2LVmA}5n%m5r-A{SS~QuCmZw+mQKQ?^C%c{vO58m$`^((Hceu%O~YU z9{=@p?{;g;UBU5DZTy$;9d4tHHf~tP8He|JpH_YGeU0rxxs$ld^+5D|y~dcdcHiJT zF(Zqboe|7Vj z-t9U&_DD&>e)pV#hgn!e=aPI{^JC-oY~qJug!-I=1T-o+&rkis4sv zD<0-2!wb6gyaV0)Wo#0%Q}cg$OG14^A$8-EYa8MjQ!IQ$XEh`C1^FMN+g%DB#a3B? z1=PWxve=Wv*%P-nJ1)sv?@fxYUtq66$6inX@0G1UvR-=v>0WzzHWGThg3sW+0RNX? z%l@R1z4rp(sz~^5Lu`Vrvn}@|;Jf6v+FEY66>I0O(|$)jrfd1gMsYZ>@RZICMEAKC z8t-p&T|=b)GGwXhUT(t@+jRuo^lE=X{bKAQ*)|My4V}zq74rj~at=@5PJEwl2r>Wm ze|PKqt&LuH;(=bbv2(;c!oIzmx%t>>@~_1}gUF?1?xpG6YXZvWkw9pK@@u z^E^a+_8!h&X)mETaCrAd<+6DQ{E8M0bQl_0HOCW&&Nh+QefVk#{InS!Tn2BQNxAk4 z?u0d|`#YAog8PPzsh8gQGG|gUh@IQVIWnDRodGPT=}%`d)o!gjsXpZ<6HH~@o<*k$yqVu>U*H$OzL{cC%KW24;rtc|4inpmi{;0>vE~R zwo_XEOsy7XvmpXq(70eGd0bN~Z)owDEk$86~V^Q+0%1`N}YyH)HdYu(;@D}D8V z_I^32J;j&oJJb90?^!px-$>_9_C$^K7W8dJ)bO;EV-(w}(6M#dbe zzweTV8n!a#XTjge@R)V(SoiGQh7D8WZVHdPnQ=e;6@PFG>`dZ2@`tDXIf zU;B#=CK)qYaZy}tg2_|>ib^=C%M4WM4P3T z_P6=DbF>-Uv)OL5D%@rrZK|zKcV^3sf6LiC{-&JGnh)6^wt$D%fVYgcgUruy#>G7h zGd0K0UHL$RKMb4pVcE2!{qOv#jSVki`#3UfUBlOjnNZmh*Su56^(Cy&3+B&z8$IwD z&go0uYmZ+$EXmfVowb?RlF4|qHvdc+j|bX;kBWyzVmR#lNAOkeby@YE>&}khh&4_O zN1Qo#498r2;IgMUF&s4?IEKTIzE=V+{6nhd`1I|mV&B7eJiH?Qs&1WuQEb-v;FK*v zF(%RQEr4H6;UnHDUM{$<13vNJ1<*?tdvL{=T+?O(*BL9I_tCK?AEnM3_-rKBq)PCN z3d5NchI4GyoOx|lz=m}~)to|~?s#!zo9D{44H4hB-uoD%XYu6vqU*Bj=OY6bAR84& z`53U2=soqjh&RYeh^y}+-rzC5^ADi5v{TTrxUO1-^@4VPO%dxF&m zY_Hkv#n-<^dld=s7j6%nU$8yK{Gr;@++7Gha5=cWihTBld^DfNns+K6yQO5-nN_oTkZ z?tq6?ZM`a3%^l=p!tZB9z2C?C;CpKhiD%5jUe@WJ(UJvko561{wzF7lXK5C>On+L} zAm3HyPuDeUU}2f)n?}t#Gkv((e5W6YIyO9 zx`yBro9yR1p4iy1k^gFAH*KVZ+lYy3qeHxzHfpK+EaeS4K`e4Cvd@l%7aHb5_P6EO z;Ut@V`j7psEW`9j1~o}F2) zVuswK`*fSR8II1Py+9`VjTif*^qIY!C0xyfBvbl)Q z$gq9VUYpqJWTSf>o}x33I{#3@XA7SKKC(mBuzt1w)EUYO?2`-NS9)HA9WruWLv_%Z z`p#?k7-z^`HAm+wUyCz6kMsVu6!a$W5vr-S?Ta;B2)<)?W@^9mVIT)ZJs(cXds?;=Tsi6)(S{s$tX>H4Sap zAWM1IK2i1_M}PC%{og%Xa_h+D+?UDP+v}8ds^ zL_I%iQ+ADotWS-@&l+vz|24_1SN+E}xt{+E(hW8yzOhf1*yZk?U5|dao^u~J4UHpq zopYV+A3n~yFA3vmIsF}pGd;4^R3JOy3xRbOXWGL3Mr=0nc}BM*{ZR4mE!2C1I&ZQU zkzTpma@8B!_L-_VFIa~CXIeM*H{#DcU2jeLu6?HM=ul$E!{@kjA8Je36c!lB%ockzEAcK1Z{n$JFl$}eNxs-L4IQ!k*^rx6N#n0DJPiNXb3VfZw zmu-!(WB1nrw_@}vfn7G6k3U(Shem`udxtRACQ%-UG+NWO(%*)tQ z7nJB8$sx9#MsfUtU-pjI(C_ZMGH&w}#&9h#y@oz3Th}7y+Q&zDT7(P}997VY>@!?A z)>DaIR0M915`Ue=x9n%4+fcYp#7<+-YgI?K8plo(7e2qnU2*g$JB@vQjrx!Akv=Bf zLb3g#NA)Rsl-*Z$rF-c&%Nkz)+O+k$Uk<;G;{4~I+Kp_2r=X7&z-RK|KYMMy^I7s| zoTYy;XNr5-$2;j?ckta^{B!D9)P+B-LO$#@$OaeZ(XEy>@FF+!bKB{;hjeZ&1wWt8 zBR_MOXR~Ee>RsgDe}#75#I`FNPPHqgel2mCvPI~5C(m`Ry_Dxm?dLiNO0IOCi|5I{ zBmGZz$4dXxK3hC54W4(t^UUR=H;Qjpno)HPXI9Mx?gHS?hv)v%9`^?x5B4T|JopU$ zN5_NSRfj#OZ#?$z|Gn|ZcA@!s`tZs_&D=#XHaU5J^xV94p1I*Z(sRxYXL9=I2LEgw zu}*zsv48*nbS(eFbatV;*Ur>PzjD@)_CJwzbUX7TTSA2H{>(bs!rItsuMO4(>p}CP zIs?}dXU@+#Ut?OZq1*HI%&piAzTyvV!l$x!+V`;sj%{hjukzfd`*pcf=se%Vw(t<= zw%3vi-Y$b(ad%W1>2n?{^|@NB`)QpE&rmt`yX};FI;vcAxSVvT+t8oHPu}l7i}zcb zeYE_4zICV>dLEnbKS;~}kJn`%-~8X=GylW%{DJ4@e}T^oXKqGlJn+g|`2WkuHWzk= z<@}dCco}&h`<~*JCi1P^TU!J3Y};jYnGAU03goD5M@6@i9Lb=L?6UgZJhd*hHXKV< zf*d)Q{D{Ovp-)#>*!JH*Uzj{3|FJgCo9K@3)3>z*U zJ9pW%U+xc1<__5kau?r*uV5*#%jRFUXzXUmyef1H?K3RoeKq>Rx>$5H4V~-dA6TaWAwE67fv70@#>6_#aTIv2EcG0d3Yz+Ik zGd{A9D`UO>^}Rx5w*2X1T7E{I&tE@w^KI9{4~qT4JIH~(^vX^4I#vwf&!g(fPNs3y z_Vhk=d$9>Vc&!P_-(AP2JdQgD_!Pdo=8)k0^t)@GJb_J4u)c!bX&3lAv&y;4`Q&G= z25+APe^+tVU@qtDowEkoOJ{=PD(sD3`VowoG2A5&-r~Y|ivw@iI5)>bC&skRxdyyx zudI7ShI<_U=K>pVp04aGY8ylYD|*&E*@zuqu|_wOE9!UPY#0Br4KKNmww|YrR=%ZY zy^L++UShN=`2RScn|T(A%Ms1}jd8q=T}$uR4|>0qaZ0zZ=2Oc2Nq4&iSnlKV6Z#b_ zj{{2=aZ`dvXXN(LUSyB{ezBtegq}{Jk4Y{lN08{qv2CZqbI%{EbLpwx6vfCSfm1g) zExw1`PUz34FEP^(vwxebJTt^j+_41z6ME1}zKh+~(GzK=M>_rK9JBN1tU=9Z2RW5f zheE5+%cr^LqhQ(t&688_jH1~DtkJ|zq38g^h}B> zUj}WR#D4Fw#yqDn6}q~gzCA*V*rD5@v2ju5C7)zN);%ziJ-#Qu*Wl!Um#u#+`7Oq^ zjC-$l6ZhsV68vLK^8Qo6_!)c$ve|aTn(a@z#?%|uNokbL!$kEV*(R84z1>fbgYKGG zr?$;`vcYeT?T!CstY6uzWxtj$y<@WDJ1F7*X~t3e-TZFd%@NEf2zHQ@v;%+ie`5Fe z*&Y*k<_3Q-aW{K_bnAe8d8PRA{wRAp`EewZ|GuPu-3pehuP1HJh8}&;S4qteXD_cw z>n?G(%~=j^vY{~_^o9+&CAYV*e$_G)_`2d`_^iSA;D+|!PB7a~flKvsD5{^mQT>QN zeAs^8S<1adwEy*G=D;1$m*OjR-P>O0)H?HU!CAfd`|pMcZNQDUw(HB zxKjRBIPpS>^jNT1nlh(bN>>#HKN8Le9gPDA77!hKb(DJ zZCZB-n2rEb1Yb9RE8q`+uLB-Fy{^QriHzkX;%L==VpRJpquLjqK1};#m$A>&955fU z3nk;1a7}xdc~-18_Xb9_Js5V;lI&4A_=4@6Jm4!IxHXq~CbjD@@ysFUbec)pES{*n zRL3A1^}rjAIh#grW9%L7^p+d&KOJUWXl=g28vQ4}fxoeS6u)zv_!P~p`g?~p_ea*{ z9$Q9?Z8=FD$%!im!9Re8!tl@h0`SK!pqVbl;GL4RSv+((baEs- z2GP6demUbVfljo}j!f>KL$#HP4`v4YXTiVEj;9eHxG-Ogr=0f2y>7{K?$7+H8@V(D zc|H_*K8$@ZGJUUOBh|jPpXZLT{fTE*eTs5dQ~s0GyNddAk!J;*t9J#4yxW^{oV;Eq z;Jfdz2N(-~9S3if@65*G0x++XNGK(iCtTX zf74wS-p{3OZi9ZGgMN?1sVsJpFm9fMKH9*u>PK+wqaEQU(MqhJ32xR9b2Jedb%J=g zW$(>BRQlPmo0ooe+~zed%f54JAMGl(KeEsJpgG0bh?C=P%tf)>5n3@Uu|CBzJLDVG zzJ3-to}%CViL>p`Vhih_uge&F8up*9+$*VA0X_e)<9iPJZ6iODaPcg*(wne5J&(=v zxA2So^zk3?i*4}N*Rd5TZ%vvjt}6k&`@o}YN>$Zq-Br~;oL%+p-LtO%hdyxVnN-^# z`_wi*jo1q(A}fE-xq|zsFCBCw^+VwOE&gwas{e-O51gxhYbooUdU=$8zj?MOpJx)g zmV$?mf7Y2}&4qlM8dnK(Dm`mo)Esy4zl`@KyuTA(uQmL2+0()KVR(w{EC0m)GLL=X zJLC&E$(q*uXAtv$9Xf~b{lAUtHP~(67uV4EU|e7R-}p4Zt^679i)-pfa6OrEY5el_ zUubQ9<&3lLFLb|`eJ>4qXv9CFyyfzdd|y5iU_Tqjy{SI>BPv|adh&^s& zAJTBx1U`%2Cm#9fH`fI3WM972-j|PQc{QqDE&5Lxdu@ER0erQ@5-4BPn3grJv0b_s zL$Up8Gar3S?WLi6S@6viSNBt8oC&Hc!1oVtS-v=Sb5T0E6YM*tUY?!K9aDZjil1D- z=Q8e@njdw~)P-Vr%A)Q9a@+UUIr;R&tN#goov-df@OzD;dqolvhdv9oNMa4t50Lq7{7&lI9I#Nn2*8j3Lcl*k^jc;%tf~OaC0HwVsDLg;N)lA z$QAr^tA+;8%ys0ChrO|vJ;XX-&Py;yXH>6i=p_Dl-oJ&8sqZ@MzXq5kuM4g-8?^@w zVsprVA9lcVWxvzCRrdX0=-JXqJ>)~_Kqn5lP2d&i&f@>_g=S-i+rN`|g-QdCI4b}hjgy2l?>f0xkThk^UqPi{Ks{lfNRK}a<6SuiE&zA@ zzX12X4+;0ylXo5Ro>_e;kNr~TJ8PaOF!N4D)6MoU{QDyGa^kK&m=*69O)L5QfBBjZ zPb-^0EX?Tt-ZOVPFu%F_EST>Z46}Sv7r^rq{{qZ6e^{6~XXHKet@FZs!(f>4r(6i; zZ~qH0=YL3;JOA5yB5T^&G<|s()*ybL0lb79#P7#TKJzcYo%kW)_WtdjgY&+&>zH@< z-;b3KIUD|7)|J+zH+K*(;s5*bl1u*u_+O#F55o(~C){)J*~*_E^Zw?*vGNIL!~gp* z{J{}}@IUI-E-x$IF)r0WQ|M$cHZ~g`N zYd$3W${*!Dv+BHS^_DRFeLV4f_;|y=0Q0BmqZav|R%wpji_A^CjdK#jcc-o7o3jvU ztI7X{t|y(nuGt^-Hj`(^u-`)lr$CpOJ?>kGVMu@W0i6X)8*Yx)k@G5B?|cqyhk@yQeP@SZ z_5#EF^72`Nne$S1elFoXx?XG)z65jZkNW4icdm6{aNL%M`KZNC<%M=SCz@c#T>14) z;N#PXb7p_Y8P4s8vDe7nStffHy4s}6&Bi8UX6W~p-p0jwQ_V*IdoeS8%$Lr+>l<6T ztw%;;ndm$4i_3_Y=AC0>CB7P6T)N-Wmzj;x=)JgLrE;q6VJ#?bSa$C^Vy>HqneELZh@CGT!kM-)Et%|V^c#A% zbAt-kQy5D&?Pk5;4`#A&%YzQF`OT~wYPKt0_&8^XGCv1yhMFC-HEv&iuok_?te2i_ zj_zh|bf3KDA&YTm857LAlRKBgFx6nYe+OIq*vql&Osra*{8{3_@l}jrZj*ckD`k^T zcYm+Jg--q1J9{?;FDY0lyLJcgGNy{P>>=b!)p(xj(S4T5#D1AzR=nxC?FJM427CRF z0GD9ecwawE@*CCO0NkwcG4!26--@$P{P%HiG=u)7-?h6Qvir`ZZELc*5B0p% z+vNgA%Q-V5I6q3+H7>=l_3QfG#Rb^4^80jtFLh(7tMTPqb#@;<>akaN!T3f7cEHPI zQ?viKjR^dd|8|T=9`8KTbi4_%AQOpOq|7bYEwuL#eKQaDYyTU0 zR~CNP3=ZT2FbUpzkMZZG&9f@o!K-JzpZtX1=w=UdRQKiV%60#7=-+xb5d(n_%83=B zZ+j0TS^Ymkt6wU*Fs-&H_0uZ9KQyhD7o1J24;NgRR>Ls$(dv`X>Z8zVSwTOomJ|)3 z)z($e>Q{>Xbz1#lKTI~QE(dPWDt)KWcZ3elMXUGGcP-^3Wo%ldo|k%qX|;y3?@O!H zjiqiht=>kx2(88rqSawhw7L&DE?S++v*FNc89a6#cZaxGvez6}poKG2h z)CBN}^mN?rUzt{&RoQOyGTDWP+ObuN4>`p>5bt6q?t#CBuv_M{77O_NF%I6$T|?b5 z@OBsU{R`w3{mN(Ho#3C9wc9Mpn`A0GXj68ocIqhas%(Eg>Q>?J>EL-M{spZm-3Qlf z$n{$O@j%dx%tpSahn{xpn8vMl9`qC0ecE5OuC*wWPMOT8GRVUv z9;@xIo&-K;3JxiD`&{ismx-m#LYsG{w45T=Kstnx&c=Oy(ow{FG}p24rD9-g5<_1O^zdx7|h$ZJnX3zwSn3rse_+oh0e9n$kOl|yYp79?m zvdBLP-j5JdkcU6Tmu>~Kr?`SYq#WlZa^pOX?h=RWTV5U8()Hza2PZ!kJhuNkzdqJA zG<1x9?YPJz@YYEEyewDnKI+>r%$psMkJ$eGm)U_j;JKT3gX5P^+Vt!AH$=mt*DTST zF*EnMkXP8%_Aq92hJ%A+689lv>L{~i2=bQq&B*vy;M2OBr>>VR!moZ~)69(<;^rn%AH~GrJ3*f7K)}~p_d|P%Ew$4hH1s? zDXh=5%>FdS+Ds0kcI5A`s2BU%o%a{zBZrN3bQy3HyFhN7xGs<8JD$8DR_y*Pd@@

`z!BsYsR$JY2p5(iLwhF^-H8G!&wz4Sy81JLksMb#8eYmf{R?0-J_4^0B2d@phccGIMRE`L??^gDD~@q=werPBk~uMT?9@hXp`5GTv?%Mw-} zx{2>8{-#?WpY+>Q?8B9HQ|md8X>K(Mb*Y1Op6Qgmo=+y9_S3yPh|f(qe(ir@c8*r!+FC&eD@x!BJgtDW86q5k_j z@!RKVJ;MJyC+<3iKEFg`k{&1CB3(Bb9pC$J{$Q3ht-E|k_tRs@OMDW4R^pjP&pu?J zr~2!&($2UmMH~BEjxHDRgS6r2y9@Xt&*fK_ju!&NX?luX5cINmM>cNK=Tk{>=ReP<$=VavnQ7p7@0}t3{N-hsDhr})9y=eGO!>8~p zuo^!xOtj@OncZdX?x%d{!ln45p zntFS8*zc=%%~JlaAAQPfyyoL(JUI`$0qebeWT2e+=(v>gsl8UPd9RZ@hM0rEo0GM7 z<$f3Z^^tvRcd-i}$3Xv!bk*1IKyUO{El#JcSNL7!)jpD(c07B##sn?CJD{H?m)W6b zkMmo;!Ou`0dAQTN+FYMk$9_w?8usbPUPfztA|K`Z_#NYa`%nI$6VsL0@(0o5d%fHB zf2!6a_0V~{%4tJw!!zu6((Tla;)eeV*xnJ1A|v2`8w&ix1CnQUEZ;nbzEf70JSkpQ z`$ZFcz_trG=cCoe;Ju%GJyKS>CeGm zu8qGG;?GP=RTzIKh}-T(59r6E6DuS<-VY28ZC@CV7Z1Rr;%$;zCiUTwypdZR`a2Ad z|G@Nj@y5lS7g*O0{S7&r{(KJoz5Le;*cLo`Wtg3FGfI z)_UeB|IRYAFQ?4BkaNWqCh2QaP0|cLd46m)$V>b!UFbbaq%T|ZwBOyfSbOJkp2_B8 z>)Yt!1J1;=r}0QGa^5t(s#f<~wn$Hw?4QA$v2I&bw*&u`^ev1>$OI=Q?NwlM_9f2w z*WSHO-UGGK50lG=N#~v2=Yy%nu8m(A_G06< z`)S9fJDq-HUl@G0R%HvZp{OkTF57-9Jy`L=AwDlL9(4HayNE~MN^Ta>v-qr@Yn;Ea zzwO-hHg1c-Z7n)aBwjHBdoj4o2bY3fZ6DT0b&Z)WTt;jIIy)QjiG&!RAG<&gdRc2B z@XsBB-W`V@D4say;pmtn&^1S*-;E-N#E?MZb^c(x_M^t^C|m2#W&U##nfF@sY|jwW z^L=!lcfolN@z72VPsKzJL$1fzKD{z@AUHaDkjr@iR5Zd6-w z{jjz(uY$D`+}nHA^o&3R&UwH|Zq1c;ANh#``v6|$1n9i{>^=(Uqsn9772hLYwDvCQ zBMNuh(!Vz;kij|U}-?Ys$N64A+8v%R8y1JQHpspZnX{s^X=_{71!(I}z~_56 zCg-gAX&W7I(U#`NcPb{QWGiQo7@N*SbutHrcyHy?h-EK)L~)wrddW!VIpv$Wo%Vv) zTL(UC%v)oZeLT?l$}sYym<_o#qwPEVdN@1N+3N}(VSbJf-x;CxCxNHwWK7PVz}ZtZ z{f0N-;Ni9vEG8V5r0&o(nGV&#zwP$dM2_b7pT$4sC4TXmvj&IZPbKTLo>g z;r(4w%hx_>Hhzq@h_BeGc1*Rm1-_poU3)t9%D&ONDTn9c$C7hj;JjNte`EyYKD6jhKSogek1u7$Se10>KXR0+A}WTcZjxue=&U6zPmCMhb^CcNG0s^ z%Q8%E^j^Qa_(o{_hQ9s2p$&_+?gw@swns;|BnLQlWP6RU@BRz#3^uiB8GheKP14fK zP12=&4ucyH_BPoTuex~P|Bv&3aNQx)ZK2+JKIgKXCNCg|88O?9+||gOEZK-$v%q)R z^3qv_#KWWy;r=M{ipYPH41SSI*sBt48hC07u)54l*+h2PxyP{WaPIVYj1|N-yv@92 z1@ND3SmsNTO?SiHZHd@Spds=xtzxXgfnA=pB^p{e(b2bM+YmlP6VbMSh%HmHc!#ZD zs7$hLU;95_7Y>tJ9;e-Qcu79<9OSq30SC_>yWHRGa)~Wld8ae25q(0w*bs8E8ahia zv2D;B?lz+X!+`tOO-TVac}nE_6yBw;-Jd1?gMLZh+ zKyEMg-`??NXRqSAvCXyDaEBuK<pAxM9i|t=d z`&q1`%;9EH5wK#PuJl%~ORd9y*IVNv24g6EVi>$T1|IG~xA5YNa0T*^`Mco_zN)s_ z=~bNbxyQ6#PyJ~gvlCuk`3Ursbus6U!9nH(;?uC3XzqkV`IB{*x^VeT=0x+T`75J- zrlGz8NB6MC?l!H7Rc7TEp*^j056`8aVso}-rJkvLW+v_X{C4iQCj9W;dyBg>Gl?sj z^2sdbq4GGkuQhzX&UYs9VVTI=4D#0%UV+^C1$P=CU#1P^|Gs=XzP_Eap!^!w2-}zHp`3C)-JCIE^S+(_pbL2669=bfnye|8 zSy`F0@CBz6$Am658JTezeb+6zYUTQWyK1G6vYF&~OHB6ne4QAmWb&(K@qRk*XYxLU z@`LdxJ|{fNwiUtSBpZ*8Evqbym(V@=HV!j|yU&|o;u3c-34D&Z+pP4`?>wGI%IMC6 z;hDs>U4|W>GVzo-vuYl5UdY^k3L3Z?xy}7^HI7Yw3FRZO&3m_Zhwe@C2K>)>i7`Z1 z-06uoJ4gCV?g(P%1drzKHOgdiPDE?X?~4h{CHJaB3m)twUd9uP?iq&;I=toSkC~0H zW6$ft&ZPY4o!FQ}Cmk9)>soX3#@oF+zE7Ltdz&sXNm=*~HP*a2rm`0L%fpYTxJ|`k zT!U>sFUwTY_maFRrjndRONg2(E{z?Bcm+Cz}z&7YjFjZ5| zOTAcNj-%}rv|UTvp7iG$VMT8ika+t|H-Onpa=M{g9EMm)3*#^zR$h((}tMJ zbaJh~9X>~C+gRm0;eQ@7O!V1%soB~7fOuwNOAgOu>*~0actY0UyZA>V&pVcJM(z<; z@O#+7B%_m3{Ij|_-`@D1yYd9Gp=YGo=>t!-sY9+8Us*vcq9@Tz*Peqo8pU-~?jB9t z$|LM);F+HEl)!4nHXfXOF3IGqi8DuEBVSut40)#Ty&dMa`esgv$w7VqoBpTs-$k8| zg#T+FZ~x}`8roBQAhg$WTIbGzQ9jTT_RO^@ZL{!e=ICs-@Oj)de*Y%kpJohod=s~N ze-X68eLFU-lrx`t_n`jg2dY7 z2-lHkSMe+qYi!zsh7NWD+hk~H1%0lEKFFmZ8VXdKWcDcV*P?;;7%B=Qp+#^o~g0LSl}5?9-7K?QUmJk_o*?j!y=z1QlXV`0L%h>SUcvmn!J4#KXX&A_tZfsxhx+W5-^!|FLGkw6KzD@XBWwP+GiywKAADU|$ zHpUulld{|NT`|CK-+|v=`W}9q`@i8r?r?|9KI!bxZ`labQ;u&hGr?o$mQakM=%vhs zFI>J{bU)+I3mjlPK6KME{DB?lnI+V*I9niHWkF@{CY7hXfS3Q}cUi%*yG+oAB`WSf zb0-@>4KySfYmbFEoDSq3YwMi;`$-3SH$~#HBJ(s0SQNjJf$c@S*>BSD*P>5W_NFke zM?2ls4Z@9bcO2&VZ#Va*Sey+jpwD#5gxsS7?Q=&4zW-BXWOxo7x=MR7w0Ah?3YkZL zY~VkR^`@x)Nd-HuC#20Ne?!QL?qJ+^mPQ1{HY&$R+y-P)V7hq6DV>{7n}gYUQZ z=J#~`EFXQy(fM(Wz$& z4~;)_-66p+el>H=KDT49W$U0FF$LHJh{xcLnU2pu6ZoT5PIBb$e(4hvT9#r<_$qDL zF&fye9)Cgb$S#`PQVbqL5BPiLKBQ;ZJuK#gxe7I)M@7+y+N_1<6kBrSyUI7}^mAlB zIfQ|c__{^K7ok&7Zg4DM#7~?FJ(h*{OrrT}XuF;NYoTq)z6jkZH{kQa`%zw|8#DM2I zS1@s`eEt1+8wM>&UTF*u=7;yY^ySQdV#|Y)-Hf9bJiWyGX#c*}Xpp|=(f2(1E~jtB zJG8@3Jir|k9Q3Par94Y~p&%H+)xyGczeyYgJnH|nQ7v*O@_8NDX zy*}LJqz@rq=b4z9E0C$BobR59&gJDZkG$ZD8Lb88E^w|G%R=>!PB>&-(YO5crS_re z06DpiDz55A+VBxGng6P>V}unC=_BqkD#q|wm0%3VHD(j1SZI0oEB13Kv7g!HWwVOW z`_t*OgIr&d1$w8uE$w&20Q>M4z0 zZ@!86%Hf=EQQZnYYS&Aw*L-9|EFZ;{H3P5OEv3DTa9iorSN!E=)L&1mr-iO07*+mR z>aQW@Lh%)f8;!=7nXqL*tZWndR1x?pB8D{9TU5W@-a}O#RGh5jvUrJ~ej@SOe%g%S zw-Eda#z(1B8^-x^o;|{UUw@sxxX&Wq$>wO=@JcSWZ747K%|^$j=luT@|D$ye*<*G? zo9F_$dC+D%@WK-hN@twsA-4Wr>D@sIbtjku`Whv{jF~R(_jD17}@!Ttj=We7- z6KiS(G2QyzM!PGB>(*}r-&jFA`VC*T*Z2ypabmn1p~H-Faos~Wci>*1akFdvq?@hvm)!hi*6G!(mmg2~_k}it7%aiHO92Ym60)v4S-@ z-#h=TF^Vs0tW~VBNX$F)+P99EgBS6S!MI_5&U)4o#%0Aha9Ke-_*rd0ql2H7M8P50 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

(&fn_name, &unjustified_axioms, &unjustified_calls), + ); + + diag = diag.with_note(reachability_str(&fn_name, tcx, &func)); + + for axiom in unjustified_axioms { + diag = extend_diag_axiom::

(diag, axiom); + } + + for calls in unjustified_calls { + diag = extend_diag_calls(diag, tcx, calls); + } + + diag.emit() +} + +fn extend_diag_axiom(diag: Diag, axiom: Spanned) -> Diag { + // TODO: add notes about the known requirements + diag.with_span_note(axiom.span, format!("{} here", axiom.node)) +} + +fn extend_diag_calls<'tcx>( + diag: Diag<'tcx>, + tcx: TyCtxt<'tcx>, + calls: CallsWObligations, +) -> Diag<'tcx> { + let call_to = tcx.def_path_str(calls.call_to); + diag.with_span_note(calls.from_spans, format!("{call_to} is called here")) +} + +fn reachability_str(fn_name: &str, tcx: TyCtxt, reachable: &LocallyReachable) -> String { + let reachability_str = reachable + .through + .iter() + .map(|def| { + let name = tcx.def_path_str(def.0); + let s = tcx + .sess + .source_map() + .span_to_string(def.1, rustc_span::FileNameDisplayPreference::Local); + let colon = s.find(": ").expect("should have a colon"); + format!("{name} ({})", &s[..colon]) + }) + .chain(std::iter::once(format!("*{fn_name}*"))) + .join(" -> "); + + format!("reachable from [{reachability_str}]") +} + +mod summary { + use itertools::Itertools; + use rustc_span::source_map::Spanned; + + use crate::properties::{Axiom, Property}; + use crate::reachability::CallsWObligations; + + pub fn summary_string( + fn_name: &str, + axioms: &[Spanned], + calls: &[CallsWObligations], + ) -> String { + let axiom_summary = axiom_summary::

(axioms); + let call_summary = call_summary::

(calls); + let issue_summary = [axiom_summary, call_summary] + .into_iter() + .flatten() + .join(" and "); + + let kind = P::name(); + format!("function {fn_name} directly contains {issue_summary}, but is not annotated {kind}") + } + + fn call_summary(calls: &[CallsWObligations]) -> Option { + let count: usize = calls.iter().map(|call| call.from_spans.len()).sum(); + let kind = P::name(); + let s = match count { + 1 => "", + x if x > 1 => "s", + _ => return None, + }; + Some(format!( + "{count} unjustified call{s} to annotated {kind} functions" + )) + } + + fn axiom_summary(axioms: &[Spanned]) -> Option { + let count = axioms.len(); + let kind = P::name(); + let s = match count { + 1 => "", + x if x > 1 => "s", + _ => return None, + }; + Some(format!("{count} unjustified {kind} axiom{s}")) + } +} diff --git a/crates/sniff-test/src/check/mod.rs b/crates/sniff-test/src/check/mod.rs index aa55454..38bbb91 100644 --- a/crates/sniff-test/src/check/mod.rs +++ b/crates/sniff-test/src/check/mod.rs @@ -11,6 +11,7 @@ use crate::{ utils::SniffTestDiagnostic, }; +mod err; mod expr; /// Checks that all local functions in the crate are properly annotated. @@ -19,14 +20,16 @@ pub fn check_properly_annotated(tcx: TyCtxt) -> Result<(), ErrorGuaranteed> { // Debug print all our entries and where they are in the src // (this isn't actually needed for analysis) - let entries = entry - .iter() - .map(|local| { - let span = tcx.optimized_mir(local.to_def_id()).span; - (local, span) - }) - .collect::>(); - log::debug!("entry is {entries:#?}"); + { + let entries = entry + .iter() + .map(|local| { + let span = tcx.optimized_mir(local.to_def_id()).span; + (local, span) + }) + .collect::>(); + log::debug!("entry is {entries:#?}"); + } let reachable = reachability::locally_reachable_from(tcx, entry).collect::>(); @@ -63,18 +66,25 @@ fn check_function_properties( log::debug!("fn {:?} has obligations {:?}", func.reach, annotation); // Find all calls that have obligations. - let bad_calls = reachability::find_calls_w_obligations(tcx, &func, property) + let unjustified_calls = reachability::find_calls_w_obligations(tcx, &func, property) // Filter those with only callsites that haven't been justified. .filter_map(only_unjustified_callsites(tcx, func.reach, property)) .collect::>(); // If we have obligations, we've dismissed them - // todo!() - if bad_calls.is_empty() { + if unjustified_calls.is_empty() && axioms.is_empty() { + // Nothing to report, all good! Ok(()) } else { - Err(tcx.dcx().struct_err("sniff test failed!").emit()) + // Unjustified issues, report them!! + Err(err::report_errors( + tcx, + func, + property, + axioms, + unjustified_calls, + )) } } @@ -111,81 +121,6 @@ fn only_unjustified_callsites( } } -// struct FunctionIssues(Vec>, Vec); - -// pub fn check_function( -// tcx: TyCtxt, -// fn_def: LocallyReachable, -// ) -> Result<(), FunctionIssues> { -// // Check that this function: -// // a) contains no axiomatic bad things. -// // b) contains no calls to bad functions. - -// todo!() -// } - -// fn needs_annotation( -// dcx: DiagCtxtHandle, -// tcx: TyCtxt, -// reachable: &LocallyReachable, -// bc_of_isses: FunctionIssues, -// ) -> ErrorGuaranteed { -// let def_span = tcx.def_span(reachable.reach); -// let fn_name = tcx.def_path_str(reachable.reach.to_def_id()); - -// let mut diag = dcx.struct_span_err(def_span, summary::summary_string(&fn_name, &bc_of_isses)); - -// diag = diag.with_note(reachability_str(&fn_name, tcx, reachable)); - -// for axiom in bc_of_isses.0 { -// diag = diag_handle_axiom(diag, axiom); -// } - -// for bad_call in bc_of_isses.1 { -// diag = diag_handle_bad_call(diag, tcx, bad_call); -// } - -// diag.emit() -// } - -// fn diag_handle_bad_call<'d>(mut diag: Diag<'d>, tcx: TyCtxt, bad_call: CallsToBad) -> Diag<'d> { -// // let times = if bad_call.from_spans.len() > 1 { -// // format!("{} times ", bad_call.from_spans.len()) -// // } else { -// // String::new() -// // }; -// let call_to = tcx.def_path_str(bad_call.def_id); -// diag = diag.with_span_note(bad_call.from_spans, format!("{call_to} is called here")); - -// diag -// } - -// #[allow(clippy::needless_pass_by_value)] -// fn diag_handle_axiom(mut diag: Diag<'_>, axiom: Spanned) -> Diag<'_> { -// diag = diag.with_span_note(axiom.span, format!("{} here", axiom.node)); -// match axiom.node.known_requirements() { -// None => (), -// Some(AxiomaticBadness::Conditional(known_reqs)) => { -// // We know the conditional requirements, so display them -// let intro_string = "this axiom has known requirements:".to_string(); - -// let known_req_strs = known_reqs -// .into_iter() -// .enumerate() -// .map(|(i, req)| format!("\t{}. {}", i + 1, req.description())); - -// diag = diag.with_help( -// std::iter::once(intro_string) -// .chain(known_req_strs) -// .join("\n"), -// ); -// } -// Some(AxiomaticBadness::Unconditional) => todo!(), -// } - -// diag -// } - fn reachability_str(fn_name: &str, tcx: TyCtxt, reachable: &LocallyReachable) -> String { let reachability_str = reachable .through @@ -204,46 +139,3 @@ fn reachability_str(fn_name: &str, tcx: TyCtxt, reachable: &LocallyReachable) -> format!("reachable from [{reachability_str}]") } - -// mod summary { -// use itertools::Itertools; -// use rustc_span::source_map::Spanned; - -// use crate::check::FunctionIssues; -// use crate::properties::Axiom; -// use crate::reachability::CallsToBad; - -// pub fn summary_string(fn_name: &str, issues: &FunctionIssues) -> String { -// let axiom_summary = axiom_summary(&issues.0); -// let call_summary = call_summary::(&issues.1); -// let issue_summary = [axiom_summary, call_summary] -// .into_iter() -// .flatten() -// .join(" and "); - -// let kind = A::axiom_kind_name(); -// format!("function {fn_name} directly contains {issue_summary}, but is not annotated {kind}") -// } - -// fn call_summary(calls: &[CallsToBad]) -> Option { -// let count: usize = calls.iter().map(|call| call.from_spans.len()).sum(); -// let kind = A::axiom_kind_name(); -// let s = match count { -// 1 => "", -// x if x > 1 => "s", -// _ => return None, -// }; -// Some(format!("{count} unjustified call{s} to {kind} functions")) -// } - -// fn axiom_summary(axioms: &[Spanned]) -> Option { -// let count = axioms.len(); -// let kind = A::axiom_kind_name(); -// let s = match count { -// 1 => "", -// x if x > 1 => "s", -// _ => return None, -// }; -// Some(format!("{count} unjustified {kind} axiom{s}")) -// } -// } diff --git a/crates/sniff-test/src/properties/safety.rs b/crates/sniff-test/src/properties/safety.rs index 5e51f58..d4912a4 100644 --- a/crates/sniff-test/src/properties/safety.rs +++ b/crates/sniff-test/src/properties/safety.rs @@ -19,7 +19,7 @@ pub struct SafetyProperty; impl Property for SafetyProperty { type Axiom = SafetyAxiom; fn name() -> &'static str { - "safety" + "unsafe" } fn fn_def_regex(&self) -> Regex { diff --git a/tests/unsafe/example_crate/src/main.rs b/tests/unsafe/example_crate/src/main.rs index 8076684..fb6d5eb 100644 --- a/tests/unsafe/example_crate/src/main.rs +++ b/tests/unsafe/example_crate/src/main.rs @@ -7,6 +7,7 @@ fn foo(ptr: *const i32) -> i32 { a + 2 } +/// # Safety fn baz(ptr: *const i32) -> i32 { unsafe { *ptr } } From e4a2555fc6e574129720f2b6e8195c9dfb5054c5 Mon Sep 17 00:00:00 2001 From: Yash Agrawal Date: Tue, 11 Nov 2025 14:38:45 -0500 Subject: [PATCH 31/40] cleanup toml module --- crates/sniff-test/src/annotations/toml.rs | 62 ++++++++++------------- 1 file changed, 28 insertions(+), 34 deletions(-) diff --git a/crates/sniff-test/src/annotations/toml.rs b/crates/sniff-test/src/annotations/toml.rs index 4dee514..46253b6 100644 --- a/crates/sniff-test/src/annotations/toml.rs +++ b/crates/sniff-test/src/annotations/toml.rs @@ -1,3 +1,14 @@ +//! Module for parsing annotations from TOML files. +//! Each top-level TOML table key is a function name with a `requirements` string. +//! ```toml +//! [function_name] +//! requirements = """ +//! # Safety +//! * 'requirement 1': Description of requirement 1 +//! * 'requirement 2': Description of requirement 2 +//! """ +//! ``` + use std::collections::HashMap; use rustc_span::{ @@ -13,7 +24,7 @@ pub struct TomlAnnotation { function_to_requirements: HashMap>>, } -// Errors that can occur when parsing TOML annotations. +/// Errors that can occur when parsing TOML annotations. #[derive(Debug)] pub enum TomlParseError { Io(std::io::Error), @@ -44,30 +55,20 @@ impl TomlAnnotation { /// Parses a TOML annotation file and returns a TomlAnnotation struct. /// Fails on any errors, never returning partial results. /// If the file does not exist, returns an empty TomlAnnotation. + /// TODO: Use real spans if possible. pub fn from_file>(path: P) -> Result { // Get the contents of the TOML file - let text = match std::fs::read_to_string(path) { - Ok(t) => t, - Err(e) if e.kind() == std::io::ErrorKind::NotFound => { - println!("TOML annotation file not found, proceeding without it."); - return Ok(TomlAnnotation::default()); - } - Err(e) => return Err(TomlParseError::Io(e)), - }; + let text = std::fs::read_to_string(path)?; // Parse the TOML file into a map from function names to requirement strings - // The expected schema is: - // [function_name] - // requirements = """ - // - Requirement 1 - // - Requirement 2 - // """ let value: toml::Value = toml::from_str(&text)?; let Some(table) = value.as_table() else { return Err(TomlParseError::Schema( "Expected a TOML table at the top level".to_string(), )); }; + + // Parse each function's requirements let mut function_to_requirements: HashMap>> = HashMap::new(); for (function_name, value) in table { @@ -76,31 +77,23 @@ impl TomlAnnotation { "Expected a TOML table for function {function_name}" ))); }; - - if inner_table.len() != 1 || !inner_table.contains_key("requirements") { + let Some(requirements_value) = inner_table.get("requirements") else { return Err(TomlParseError::Schema(format!( - "Expected a single 'requirements' entry for function {function_name}" + "Expected a 'requirements' string for function {function_name}" ))); - } - - let Some(requirements_string) = inner_table["requirements"].as_str() else { + }; + let Some(requirements_string) = requirements_value.as_str() else { return Err(TomlParseError::Schema(format!( - "Expected a 'requirements' string for function {function_name}" + "Expected 'requirements' to be a string for function {function_name}" ))); }; - match Requirement::parse_bullets_from_string(requirements_string) { - Ok(requirements) => { - let spanned_requirements: Vec> = requirements - .into_iter() - .map(|(req, _range)| respan(DUMMY_SP, req)) - .collect(); - function_to_requirements.insert(function_name.clone(), spanned_requirements); - } - Err(parse_error) => { - return Err(TomlParseError::Parse(parse_error)); - } - } + let requirements = Requirement::parse_bullets_from_string(requirements_string)?; + let spanned_requirements: Vec> = requirements + .into_iter() + .map(|(req, _range)| respan(DUMMY_SP, req)) + .collect(); + function_to_requirements.insert(function_name.clone(), spanned_requirements); } // Return the parsed annotations @@ -109,6 +102,7 @@ impl TomlAnnotation { }) } + /// Retrieves the requirements for a given function name, if any. pub fn get_requirements_for_function( &self, function_name: &str, From f2203fd4ada94f62bcf1b8027a39e970f829d82c Mon Sep 17 00:00:00 2001 From: AlexanderPortland Date: Tue, 11 Nov 2025 14:50:46 -0500 Subject: [PATCH 32/40] support for crate root attrs --- crates/sniff-test/src/check/mod.rs | 9 ++-- crates/sniff-test/src/lib.rs | 2 +- crates/sniff-test/src/properties/mod.rs | 6 +-- crates/sniff-test/src/properties/panic.rs | 2 +- crates/sniff-test/src/properties/safety.rs | 1 + crates/sniff-test/src/reachability/attr.rs | 50 +++++++++++++-------- crates/sniff-test/src/reachability/entry.rs | 42 ++++++++++------- tests/unsafe/example_crate/src/main.rs | 3 +- 8 files changed, 67 insertions(+), 48 deletions(-) diff --git a/crates/sniff-test/src/check/mod.rs b/crates/sniff-test/src/check/mod.rs index 38bbb91..99907c0 100644 --- a/crates/sniff-test/src/check/mod.rs +++ b/crates/sniff-test/src/check/mod.rs @@ -15,8 +15,11 @@ mod err; mod expr; /// Checks that all local functions in the crate are properly annotated. -pub fn check_properly_annotated(tcx: TyCtxt) -> Result<(), ErrorGuaranteed> { - let entry = reachability::local_entry_points(tcx).collect::>(); +pub fn check_properly_annotated( + tcx: TyCtxt, + property: P, +) -> Result<(), ErrorGuaranteed> { + let entry = reachability::local_entry_points::

(tcx); // Debug print all our entries and where they are in the src // (this isn't actually needed for analysis) @@ -37,7 +40,7 @@ pub fn check_properly_annotated(tcx: TyCtxt) -> Result<(), ErrorGuaranteed> { // For all reachable local function definitions, ensure their axioms align with their annotations. for func in reachable { - check_function_properties(tcx, func, properties::SafetyProperty)?; + check_function_properties(tcx, func, property)?; } Ok(()) diff --git a/crates/sniff-test/src/lib.rs b/crates/sniff-test/src/lib.rs index a105aae..be8e13c 100644 --- a/crates/sniff-test/src/lib.rs +++ b/crates/sniff-test/src/lib.rs @@ -169,7 +169,7 @@ impl rustc_driver::Callbacks for PrintAllItemsCallbacks { let crate_name = tcx.crate_name(LOCAL_CRATE); log::debug!("checking crate {crate_name}"); - let Ok(()) = check_properly_annotated(tcx) else { + let Ok(()) = check_properly_annotated(tcx, properties::SafetyProperty) else { return rustc_driver::Compilation::Stop; }; diff --git a/crates/sniff-test/src/properties/mod.rs b/crates/sniff-test/src/properties/mod.rs index 24b1e3c..6f8b7e3 100644 --- a/crates/sniff-test/src/properties/mod.rs +++ b/crates/sniff-test/src/properties/mod.rs @@ -2,7 +2,7 @@ use crate::{ annotations::{self, PropertyViolation}, - reachability::LocallyReachable, + reachability::{LocallyReachable, attr::SniffToolAttr}, }; use regex::Regex; use rustc_hir::intravisit::{self, Visitor}; @@ -20,10 +20,6 @@ mod safety; pub use panic::PanicProperty; pub use safety::SafetyProperty; -// pub fn all_properties() -> Arc>> { -// Arc::new(vec![Box::new(SafetyProperty)]) -// } - pub trait Property: Debug + 'static + Copy { type Axiom: Axiom; fn name() -> &'static str; diff --git a/crates/sniff-test/src/properties/panic.rs b/crates/sniff-test/src/properties/panic.rs index 89861d0..90dacff 100644 --- a/crates/sniff-test/src/properties/panic.rs +++ b/crates/sniff-test/src/properties/panic.rs @@ -5,7 +5,7 @@ use rustc_span::source_map::{Spanned, respan}; use std::fmt::Display; use super::Axiom; -use crate::{annotations::PropertyViolation, properties::Property}; +use crate::{annotations::PropertyViolation, properties::Property, reachability::attr}; #[derive(Debug, Clone)] pub enum PanicAxiom { diff --git a/crates/sniff-test/src/properties/safety.rs b/crates/sniff-test/src/properties/safety.rs index d4912a4..fcd0b25 100644 --- a/crates/sniff-test/src/properties/safety.rs +++ b/crates/sniff-test/src/properties/safety.rs @@ -11,6 +11,7 @@ use super::Axiom; use crate::{ annotations::{self, PropertyViolation}, properties::Property, + reachability::attr, }; #[derive(Debug, Clone, Copy)] diff --git a/crates/sniff-test/src/reachability/attr.rs b/crates/sniff-test/src/reachability/attr.rs index 161ffe4..ff71710 100644 --- a/crates/sniff-test/src/reachability/attr.rs +++ b/crates/sniff-test/src/reachability/attr.rs @@ -1,53 +1,65 @@ //! Utilities for parsing our own `sniff_test_attr` annotation attributes. +use std::any::{Any, TypeId}; + use rustc_hir::{Attribute, def_id::DefId}; use rustc_middle::ty::TyCtxt; -pub fn attrs_for(def_id: DefId, tcx: TyCtxt) -> Option { - get_sniff_tool_attr(tcx.get_all_attrs(def_id)) +use crate::properties::{self, Property}; + +pub fn attrs_for(def_id: DefId, tcx: TyCtxt) -> Vec { + get_sniff_tool_attrs(tcx.get_all_attrs(def_id)) } -#[derive(Debug)] +#[derive(Debug, PartialEq, Eq, Clone, Copy)] pub enum SniffToolAttr { CheckUnsafe, + CheckPanics, } impl SniffToolAttr { fn try_from_string(string: &str) -> Option { + println!("parsing from string {string:?}"); match string { "check_unsafe" => Some(Self::CheckUnsafe), + "check_panics" => Some(Self::CheckPanics), _ => None, } } + + pub fn matches_property(self) -> bool { + TypeId::of::

() == self.property() + } + + pub fn property(self) -> TypeId { + match self { + Self::CheckPanics => properties::PanicProperty.type_id(), + Self::CheckUnsafe => properties::SafetyProperty.type_id(), + } + } } -fn get_sniff_tool_attr(attrs: &[Attribute]) -> Option { - let sniff_tool = attrs +pub fn get_sniff_tool_attrs(attrs: &[Attribute]) -> Vec { + attrs .iter() .filter_map(|attr| { let Attribute::Unparsed(box item) = attr else { return None; }; - // TODO: this might be hacky bc we're comparing strings... - match item + let str_segs = item .path .segments .iter() .map(rustc_span::Ident::as_str) - .collect::>() - { - box ["sniff_tool", b] => Some(b), + .collect::>(); + + // TODO: this might be hacky bc we're comparing strings... + // No actually it seems to work fine. + match str_segs { + box ["sniff_tool", b] => SniffToolAttr::try_from_string(b), _ => None, } }) - .collect::>(); - - match sniff_tool { - box [] => None, - box [attr_name] => SniffToolAttr::try_from_string(attr_name), - box [_first, _second, ..] => { - panic!("multiple sniff test attrs on the same jawn {sniff_tool:?}") - } - } + .collect::>() } diff --git a/crates/sniff-test/src/reachability/entry.rs b/crates/sniff-test/src/reachability/entry.rs index 4991479..77a752f 100644 --- a/crates/sniff-test/src/reachability/entry.rs +++ b/crates/sniff-test/src/reachability/entry.rs @@ -1,31 +1,39 @@ use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::ty::TyCtxt; -use crate::reachability::attr::{self, SniffToolAttr}; +use crate::{ + properties::Property, + reachability::attr::{self, SniffToolAttr}, +}; -pub fn local_entry_points(tcx: TyCtxt) -> impl Iterator { - // global_annotations(tcx); - if false { - todo!() +pub fn local_entry_points(tcx: TyCtxt) -> Vec { + let globally_annotated = attr::get_sniff_tool_attrs(tcx.hir_krate_attrs()) + .into_iter() + .any(SniffToolAttr::matches_property::

); + + if globally_annotated { + println!("GLOBALLY ANNOTATED FOR {}", P::name()); + let a = all_local_defs(tcx).collect(); + println!("all local defs {a:?}"); + a } else { - annotated_local_entry_points(tcx) + println!("locally annotated for {}", P::name()); + todo!(); + annotated_local_defs::

(tcx).collect() } } -pub fn global_annotations(tcx: TyCtxt) -> bool { - for attr in tcx.hir_krate_attrs() { - println!("attr is {attr:?}"); - } - todo!() +fn all_local_defs(tcx: TyCtxt) -> impl Iterator { + tcx.hir_body_owners() } -fn annotated_local_entry_points(tcx: TyCtxt) -> impl Iterator { +fn annotated_local_defs(tcx: TyCtxt) -> impl Iterator { tcx.hir_body_owners() - .filter(move |item| is_entry_point(tcx, item.to_def_id())) + .filter(move |item| is_entry_point::

(tcx, item.to_def_id())) } -fn is_entry_point(tcx: TyCtxt, item: DefId) -> bool { - attr::attrs_for(item, tcx).is_some_and(|attr| match attr { - SniffToolAttr::CheckUnsafe => true, - }) +fn is_entry_point(tcx: TyCtxt, item: DefId) -> bool { + attr::attrs_for(item, tcx) + .into_iter() + .any(SniffToolAttr::matches_property::

) } diff --git a/tests/unsafe/example_crate/src/main.rs b/tests/unsafe/example_crate/src/main.rs index fb6d5eb..09aaf6e 100644 --- a/tests/unsafe/example_crate/src/main.rs +++ b/tests/unsafe/example_crate/src/main.rs @@ -1,4 +1,4 @@ -// #![sniff_tool::check_unsafe] +#![sniff_tool::check_unsafe] /// # Safety /// - non-null: ptr must be non-null @@ -7,7 +7,6 @@ fn foo(ptr: *const i32) -> i32 { a + 2 } -/// # Safety fn baz(ptr: *const i32) -> i32 { unsafe { *ptr } } From f0bebd3be42d1a70f17f3e0f86d6a5dce9f0bbe1 Mon Sep 17 00:00:00 2001 From: AlexanderPortland Date: Tue, 11 Nov 2025 15:32:19 -0500 Subject: [PATCH 33/40] more documentation on sniff-test-attrs --- crates/sniff-test-attrs/src/lib.rs | 31 +++-------- crates/sniff-test/src/check/mod.rs | 2 +- crates/sniff-test/src/reachability/attr.rs | 25 +++++++-- crates/sniff-test/src/reachability/entry.rs | 60 ++++++++++++++++----- crates/sniff-test/src/reachability/mod.rs | 2 +- tests/unsafe/example_crate/src/main.rs | 6 +-- 6 files changed, 77 insertions(+), 49 deletions(-) diff --git a/crates/sniff-test-attrs/src/lib.rs b/crates/sniff-test-attrs/src/lib.rs index dc59a0e..3974811 100644 --- a/crates/sniff-test-attrs/src/lib.rs +++ b/crates/sniff-test-attrs/src/lib.rs @@ -13,15 +13,15 @@ macro_rules! define_sniff_tool_annotation { let rustflags = std::env::var("RUSTFLAGS") .map(|rust_flags| rust_flags.contains("-Zcrate-attr=register_tool(sniff_tool)")) .unwrap_or(false); - if rustflags || std::env::var("PLUGIN_ARGS").is_ok() - { + + let use_sniff_tool = rustflags || std::env::var("PLUGIN_ARGS").is_ok(); + if use_sniff_tool { t.extend(TokenStream::from(quote!( #[sniff_tool::$name] ))); } t.extend(item); - // panic!("{t}"); t } }; @@ -29,25 +29,6 @@ macro_rules! define_sniff_tool_annotation { define_sniff_tool_annotation!(check_unsafe); -// #[proc_macro_attribute] -// pub fn test(_attr: TokenStream, item: TokenStream) -> TokenStream { -// let mut t = TokenStream::new(); - -// for i in item { - -// } - -// // If we're registering the sniff-test tool, add the actual attribute to check unsafe. -// let rustflags = std::env::var("RUSTFLAGS") -// .map(|rust_flags| rust_flags.contains("-Zcrate-attr=register_tool(sniff_tool)")) -// .unwrap_or(false); -// if rustflags || std::env::var("PLUGIN_ARGS").is_ok() { -// t.extend(TokenStream::from(quote!( -// #![sniff_tool::check_unsafe] -// ))); -// } - -// t.extend(item); -// panic!("{t}"); -// t -// } +// TODO: could be useful to have a macro for checking unsafe public functions in the future, +// but for now, not worth the effort. Turns out we'd need the sniff tool attr to be after all +// the prelude import stuff and with just a token tree its very hard to handle that. diff --git a/crates/sniff-test/src/check/mod.rs b/crates/sniff-test/src/check/mod.rs index 99907c0..f66385a 100644 --- a/crates/sniff-test/src/check/mod.rs +++ b/crates/sniff-test/src/check/mod.rs @@ -19,7 +19,7 @@ pub fn check_properly_annotated( tcx: TyCtxt, property: P, ) -> Result<(), ErrorGuaranteed> { - let entry = reachability::local_entry_points::

(tcx); + let entry = reachability::analysis_entry_points::

(tcx); // Debug print all our entries and where they are in the src // (this isn't actually needed for analysis) diff --git a/crates/sniff-test/src/reachability/attr.rs b/crates/sniff-test/src/reachability/attr.rs index ff71710..d943ea1 100644 --- a/crates/sniff-test/src/reachability/attr.rs +++ b/crates/sniff-test/src/reachability/attr.rs @@ -8,9 +8,10 @@ use rustc_middle::ty::TyCtxt; use crate::properties::{self, Property}; pub fn attrs_for(def_id: DefId, tcx: TyCtxt) -> Vec { - get_sniff_tool_attrs(tcx.get_all_attrs(def_id)) + get_sniff_tool_attrs(tcx.get_all_attrs(def_id), &SniffToolAttr::try_from_string) } +// TODO: make this all a macro #[derive(Debug, PartialEq, Eq, Clone, Copy)] pub enum SniffToolAttr { CheckUnsafe, @@ -18,8 +19,7 @@ pub enum SniffToolAttr { } impl SniffToolAttr { - fn try_from_string(string: &str) -> Option { - println!("parsing from string {string:?}"); + pub fn try_from_string(string: &str) -> Option { match string { "check_unsafe" => Some(Self::CheckUnsafe), "check_panics" => Some(Self::CheckPanics), @@ -27,6 +27,18 @@ impl SniffToolAttr { } } + pub fn try_from_string_pub(string: &str) -> Option<(Self, bool)> { + if let Some(no_suffix) = Self::try_from_string(string) { + Some((no_suffix, false)) + } else if let Some(pub_suffix) = Self::try_from_string(&string[..string.len() - 4]) + && let "_pub" = &string[string.len() - 4..] + { + Some((pub_suffix, true)) + } else { + None + } + } + pub fn matches_property(self) -> bool { TypeId::of::

() == self.property() } @@ -39,7 +51,10 @@ impl SniffToolAttr { } } -pub fn get_sniff_tool_attrs(attrs: &[Attribute]) -> Vec { +pub fn get_sniff_tool_attrs( + attrs: &[Attribute], + from_str: &impl Fn(&str) -> Option, +) -> Vec { attrs .iter() .filter_map(|attr| { @@ -57,7 +72,7 @@ pub fn get_sniff_tool_attrs(attrs: &[Attribute]) -> Vec { // TODO: this might be hacky bc we're comparing strings... // No actually it seems to work fine. match str_segs { - box ["sniff_tool", b] => SniffToolAttr::try_from_string(b), + box ["sniff_tool", b] => from_str(b), _ => None, } }) diff --git a/crates/sniff-test/src/reachability/entry.rs b/crates/sniff-test/src/reachability/entry.rs index 77a752f..c8d352e 100644 --- a/crates/sniff-test/src/reachability/entry.rs +++ b/crates/sniff-test/src/reachability/entry.rs @@ -1,3 +1,5 @@ +use std::collections::{BTreeSet, HashSet}; + use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::ty::TyCtxt; @@ -6,27 +8,57 @@ use crate::{ reachability::attr::{self, SniffToolAttr}, }; -pub fn local_entry_points(tcx: TyCtxt) -> Vec { - let globally_annotated = attr::get_sniff_tool_attrs(tcx.hir_krate_attrs()) - .into_iter() - .any(SniffToolAttr::matches_property::

); - - if globally_annotated { - println!("GLOBALLY ANNOTATED FOR {}", P::name()); - let a = all_local_defs(tcx).collect(); - println!("all local defs {a:?}"); - a - } else { - println!("locally annotated for {}", P::name()); - todo!(); - annotated_local_defs::

(tcx).collect() +pub fn analysis_entry_points(tcx: TyCtxt) -> Vec { + // TODO: should use a btree rather than a hash set here so that we'll have a consistent order + // but local def ids aren't ord so this will likely require an upstream changes. + let mut entry_points = HashSet::new(); + + if let Some(global_annotation) = find_global_annotation::

(tcx) { + if global_annotation.just_check_pub { + // A `_pub` annotation can also be used in conjunction with other non-pub functions, + // so we have to continue looking for annotated local defs. + entry_points.extend(all_pub_local_defs(tcx)); + } else { + // This is everything we can possibly analyzing the local crate, so just return that. + return all_local_defs(tcx).collect(); + } + } + + entry_points.extend(annotated_local_defs::

(tcx)); + entry_points.into_iter().collect() +} + +fn find_global_annotation(tcx: TyCtxt) -> Option { + let property_annots = + attr::get_sniff_tool_attrs(tcx.hir_krate_attrs(), &SniffToolAttr::try_from_string_pub) + .into_iter() + .filter(|(attr, _)| SniffToolAttr::matches_property::

(*attr)) + .collect::>(); + + if property_annots.is_empty() { + return None; } + + // TODO: render error here if we have conflicting annotations... + let box [(_attr, just_check_pub)] = property_annots.into_boxed_slice() else { + panic!("conflicting global for the {:?} property", P::name()); + }; + Some(GlobalAnnotation { just_check_pub }) +} + +struct GlobalAnnotation { + just_check_pub: bool, } fn all_local_defs(tcx: TyCtxt) -> impl Iterator { tcx.hir_body_owners() } +fn all_pub_local_defs(tcx: TyCtxt) -> impl Iterator { + tcx.hir_body_owners() + .filter(move |owner| tcx.visibility(*owner).is_public()) +} + fn annotated_local_defs(tcx: TyCtxt) -> impl Iterator { tcx.hir_body_owners() .filter(move |item| is_entry_point::

(tcx, item.to_def_id())) diff --git a/crates/sniff-test/src/reachability/mod.rs b/crates/sniff-test/src/reachability/mod.rs index edb0b8c..19f9c32 100644 --- a/crates/sniff-test/src/reachability/mod.rs +++ b/crates/sniff-test/src/reachability/mod.rs @@ -5,5 +5,5 @@ mod err; mod walk; pub use bad::{CallsWObligations, find_calls_w_obligations}; -pub use entry::local_entry_points; +pub use entry::analysis_entry_points; pub use walk::{LocallyReachable, locally_reachable_from}; diff --git a/tests/unsafe/example_crate/src/main.rs b/tests/unsafe/example_crate/src/main.rs index 09aaf6e..35eac7c 100644 --- a/tests/unsafe/example_crate/src/main.rs +++ b/tests/unsafe/example_crate/src/main.rs @@ -1,4 +1,4 @@ -#![sniff_tool::check_unsafe] +#![sniff_test_attrs::check_unsafe_pub] /// # Safety /// - non-null: ptr must be non-null @@ -7,10 +7,11 @@ fn foo(ptr: *const i32) -> i32 { a + 2 } -fn baz(ptr: *const i32) -> i32 { +pub fn baz(ptr: *const i32) -> i32 { unsafe { *ptr } } +#[sniff_test_attrs::check_unsafe] fn bar(ptr: *const i32) -> i32 { /// SAFETY: /// - non-null: i checked to make sure this is nn @@ -20,7 +21,6 @@ fn bar(ptr: *const i32) -> i32 { // } } -#[sniff_test_attrs::check_unsafe] fn main() { let a = Some(3).unwrap(); let x = 1; From af655048cae46c0ed4a2a3a9af13de653d4f5c23 Mon Sep 17 00:00:00 2001 From: AlexanderPortland Date: Tue, 11 Nov 2025 21:01:04 -0500 Subject: [PATCH 34/40] code refactor and support for all pub fns --- crates/sniff-test/src/annotations/check.rs | 42 -- crates/sniff-test/src/annotations/err.rs | 384 ------------------ crates/sniff-test/src/annotations/mod.rs | 44 +- crates/sniff-test/src/annotations/types.rs | 109 ----- crates/sniff-test/src/check/err.rs | 6 +- crates/sniff-test/src/properties/mod.rs | 10 +- crates/sniff-test/src/properties/panic.rs | 14 +- crates/sniff-test/src/properties/safety.rs | 16 +- .../src/reachability/{attr.rs => attrs.rs} | 0 .../src/reachability/{bad.rs => calls.rs} | 0 crates/sniff-test/src/reachability/entry.rs | 11 +- crates/sniff-test/src/reachability/err.rs | 14 - crates/sniff-test/src/reachability/mod.rs | 11 +- .../src/reachability/{walk.rs => reach.rs} | 0 tests/unsafe/example_crate/src/main.rs | 15 +- 15 files changed, 62 insertions(+), 614 deletions(-) delete mode 100644 crates/sniff-test/src/annotations/check.rs delete mode 100644 crates/sniff-test/src/annotations/err.rs delete mode 100644 crates/sniff-test/src/annotations/types.rs rename crates/sniff-test/src/reachability/{attr.rs => attrs.rs} (100%) rename crates/sniff-test/src/reachability/{bad.rs => calls.rs} (100%) delete mode 100644 crates/sniff-test/src/reachability/err.rs rename crates/sniff-test/src/reachability/{walk.rs => reach.rs} (100%) diff --git a/crates/sniff-test/src/annotations/check.rs b/crates/sniff-test/src/annotations/check.rs deleted file mode 100644 index 0ef2d31..0000000 --- a/crates/sniff-test/src/annotations/check.rs +++ /dev/null @@ -1,42 +0,0 @@ -use rustc_span::source_map::Spanned; - -use crate::annotations::{Justification, Requirement, types::ConditionName}; - -pub struct ConsistencyIssue<'r> { - missing_cond: &'r Spanned, -} - -pub fn check_consistency<'r>( - justifications: &[Spanned], - for_requirements: &'r [Spanned], -) -> Result<(), ConsistencyIssue<'r>> { - // println!("does {justifications:?} satisfy {for_requirements:?}??"); - for req in for_requirements { - let sat = justifications - .iter() - .any(|just| just.node.name().as_str() == req.node.name().as_str()); - if !sat { - return Err(ConsistencyIssue { missing_cond: req }); - } - } - - Ok(()) -} - -mod error { - use rustc_errors::{Diag, DiagCtxtHandle}; - - use crate::annotations::check::ConsistencyIssue; - - impl ConsistencyIssue<'_> { - pub fn diag<'tcx>(&self, dcx: DiagCtxtHandle<'tcx>) -> Diag<'tcx> { - dcx.struct_span_err( - self.missing_cond.span, - format!( - "no justification for requirement {}", - self.missing_cond.node.name().as_str() - ), - ) - } - } -} diff --git a/crates/sniff-test/src/annotations/err.rs b/crates/sniff-test/src/annotations/err.rs deleted file mode 100644 index c5444ca..0000000 --- a/crates/sniff-test/src/annotations/err.rs +++ /dev/null @@ -1,384 +0,0 @@ -//! Error handling and pretty printing using rustc's diagnostics. - -use crate::annotations::err::span::{span_all_comments, span_some_comments}; -use crate::annotations::{Attributeable, types::InvalidConditionNameReason}; -use crate::utils::SniffTestDiagnostic; -use rustc_errors::{Diag, DiagCtxtHandle}; -use rustc_hir::Attribute; -use rustc_middle::ty::TyCtxt; -use rustc_span::def_id::DefId; -use rustc_span::{DUMMY_SP, Span}; -use std::ops::Range; - -#[derive(PartialEq, Eq, Debug)] -pub enum ParsingIssue { - /// The `FnDef` in question doesn't have a `#[doc(..)]` attribute. - NoDocString, - /// No marker patterns were found. - NoMarkerPattern, - /// Multiple marker patters were found. - MultipleMarkerPatterns(Vec>), - /// No colon delimiter was found after the condition name. - /// - /// This probably should just default in an empty description but, for now, is an error. - NoColon(Range, usize), - /// A marker was found, but it had no requirements. - EmptyMarker, - /// The name of a condition was invalid. - InvalidConditionName { - reason: InvalidConditionNameReason, - chars: Range, - name: String, - }, - /// The bullet types found were non-matching. - NonMatchingBullets(Vec<(Range, String)>), -} - -/// A full parsing error that has extra debug info (e.g. the offending [`Span`]). -#[derive(Debug)] -pub struct ParsingError<'a> { - issue: ParsingIssue, - loc_name: String, - span: Span, - doc_comments: &'a [Attribute], -} - -impl ParsingError<'_> { - #[allow(clippy::must_use_candidate)] - pub fn issue(&self) -> &ParsingIssue { - &self.issue - } - - pub fn update_span(&mut self, span: Span) { - self.span = span; - } -} - -impl ParsingIssue { - pub fn at_fn_def(self, def_id: rustc_span::def_id::DefId, tcx: TyCtxt<'_>) -> ParsingError<'_> { - ParsingError { - issue: self, - loc_name: format!("function definition {}", tcx.def_path_debug_str(def_id)), - span: def_id.as_local().map_or(DUMMY_SP, |local| { - tcx.hir_span(tcx.local_def_id_to_hir_id(local)) - }), - doc_comments: def_id.get_attrs(tcx), - } - } - - pub fn at_callsite<'a>( - self, - calling_expr: &rustc_hir::Expr<'_>, - callee_def_id: DefId, - tcx: TyCtxt<'a>, - ) -> ParsingError<'a> { - ParsingError { - issue: self, - loc_name: format!("function call of {}", tcx.def_path_debug_str(callee_def_id)), - span: calling_expr.span, - doc_comments: calling_expr.get_attrs(tcx), - } - } -} - -impl SniffTestDiagnostic for ParsingError<'_> { - fn diag<'s, 'a: 's>(&'s self, dcx: DiagCtxtHandle<'a>) -> Diag<'a> { - let base_diag = match &self.issue { - ParsingIssue::InvalidConditionName { reason, .. } => { - self.build_invalid_condition_diag(dcx, reason) - } - ParsingIssue::EmptyMarker => self.build_empty_marker_diag(dcx), - ParsingIssue::NoDocString => self.build_no_doc_string_diag(dcx), - ParsingIssue::MultipleMarkerPatterns(marker_ranges) => { - self.build_multiple_markers_diag(dcx, marker_ranges) - } - ParsingIssue::NoColon(bullet_range, first_word_len) => { - self.build_no_colon_diag(dcx, bullet_range, *first_word_len) - } - ParsingIssue::NoMarkerPattern => self.build_no_marker_diag(dcx), - ParsingIssue::NonMatchingBullets(bullet_ranges) => { - self.build_non_matching_bullets_diag(dcx, bullet_ranges) - } - }; - - base_diag.with_span_label(self.span, "here") - } -} - -impl ParsingError<'_> { - fn build_invalid_condition_diag<'a>( - &self, - dcx: DiagCtxtHandle<'a>, - reason: &InvalidConditionNameReason, - ) -> Diag<'a> { - match reason { - InvalidConditionNameReason::TrailingWhitespace => { - self.build_trailing_whitespace_diag(dcx) - } - InvalidConditionNameReason::MultipleWords => self.build_multiple_words_diag(dcx), - } - } - - fn build_trailing_whitespace_diag<'a>(&self, dcx: DiagCtxtHandle<'a>) -> Diag<'a> { - if let ParsingIssue::InvalidConditionName { chars, name, .. } = &self.issue { - let invalid_index = name - .find(super::types::INVALID_WHITESPACE) - .expect("we found there to be invalid whitespace here..."); - - let span = - span_some_comments(self.doc_comments, (chars.start + invalid_index)..chars.end); - let first = *span.first().expect("should have a first span"); - - dcx.struct_err(format!( - "trailing white space found on condition name {name:?} for {}", - self.loc_name - )) - .with_span(span) - .with_span_suggestion_verbose( - first, - "try removing it", - "", - rustc_errors::Applicability::MaybeIncorrect, - ) - } else { - unreachable!("build_trailing_whitespace_diag called with wrong issue type") - } - } - - fn build_multiple_words_diag<'a>(&self, dcx: DiagCtxtHandle<'a>) -> Diag<'a> { - if let ParsingIssue::InvalidConditionName { chars, name, .. } = &self.issue { - let span = span_some_comments(self.doc_comments, chars); - let first = *span.first().unwrap(); - - dcx.struct_err(format!( - "multi-word condition name found for {}", - self.loc_name - )) - .with_span(span) - .with_span_suggestion_verbose( - first, - "try using a kebab case name instead", - name.replace(super::types::INVALID_WHITESPACE, "-"), - rustc_errors::Applicability::MaybeIncorrect, - ) - } else { - unreachable!("build_multiple_words_diag called with wrong issue type") - } - } - - fn build_empty_marker_diag<'a>(&self, dcx: DiagCtxtHandle<'a>) -> Diag<'a> { - let span = span_all_comments(self.doc_comments); - let first = *span.first().unwrap(); - - dcx.struct_err(format!( - "safety section for {} exists but is empty", - self.loc_name - )) - .with_span(span) - .with_span_suggestion_verbose( - first.shrink_to_hi(), - "try adding preconditions", - "\n/// - cond1: /* condition that must hold for UB-freedom */", - rustc_errors::Applicability::HasPlaceholders, - ) - } - - fn build_no_doc_string_diag<'a>(&self, dcx: DiagCtxtHandle<'a>) -> Diag<'a> { - dcx.struct_err(format!("no doc comments found for {}", self.loc_name)) - .with_span(self.span) - } - - fn build_multiple_markers_diag<'a>( - &self, - dcx: DiagCtxtHandle<'a>, - marker_char_ranges: &[Range], - ) -> Diag<'a> { - let spans = marker_char_ranges - .iter() - .flat_map(|range| span_some_comments(self.doc_comments, range)) - .collect::>(); - - dcx.struct_err(format!( - "multiple marker patterns found in doc comments on {}", - self.loc_name - )) - .with_span(spans) - } - - fn build_no_colon_diag<'a>( - &self, - dcx: DiagCtxtHandle<'a>, - bullet_range: &Range, - first_word_len: usize, - ) -> Diag<'a> { - let bullet_span = span_some_comments(self.doc_comments, bullet_range); - let name_span = span_some_comments( - self.doc_comments, - (bullet_range.start + first_word_len)..(bullet_range.start + first_word_len + 1), - ); - - dcx.struct_err( - "bullet has no colon delimiter to separate out the condition name and description", - ) - .with_span(bullet_span) - .with_span_suggestion_verbose( - name_span[0], - "try adding a colon after the condition name", - ": ", - rustc_errors::Applicability::MaybeIncorrect, - ) - } - - fn build_no_marker_diag<'a>(&self, dcx: DiagCtxtHandle<'a>) -> Diag<'a> { - dcx.struct_err(format!( - "no unsafe markers found in doc comments for {}", - self.loc_name - )) - .with_span(span_all_comments(self.doc_comments)) - } - - fn build_non_matching_bullets_diag<'a>( - &self, - dcx: DiagCtxtHandle<'a>, - bullet_ranges: &[(Range, String)], - ) -> Diag<'a> { - let mut diag = dcx.struct_err(format!( - "non-matching bullet types found in doc comments on {}", - self.loc_name - )); - let mut err_spans = Vec::new(); - - let suggested = bullet_ranges.first().unwrap().1.clone(); - for (i, (range, _string)) in bullet_ranges.iter().enumerate() { - let this_span = span_some_comments(self.doc_comments, range); - - if i != 0 { - diag = diag.with_span_suggestion_verbose( - *this_span.first().unwrap(), - "try replacing them for consistency", - &suggested[(suggested.len() - 1)..], - rustc_errors::Applicability::MachineApplicable, - ); - } - - err_spans.extend(this_span); - } - err_spans.reverse(); - diag.with_span(err_spans) - } -} - -// Utilities for converting character ranges of a doc string into spans that can be -// used to reference specific source code when displaying error messages. -pub mod span { - use rustc_hir::Attribute; - use rustc_span::BytePos; - use rustc_span::Span; - use std::borrow::Borrow; - use std::ops::Range; - - /// The length of each doc comment line before you reach the start of the actual doc comment. - /// Currently 3 because of the three backslashes before each line, telling us to factor those in - /// when converting from a doc string to a span which will have those extra characters each line. - const DOC_COMMENT_PREFIX_LEN: u32 = 3; - - /// Returns the set of spans relevant for a certain range of characters distributed throughout a - /// set of doc comments. - /// - /// For example, if the `chars` array goes from halfway through the first comment to halfway - /// through the second, this will return the second half of the first doc comment's span and - /// the first half of the second doc comment's span. - pub fn span_some_comments( - doc_comments: &[Attribute], - chars: impl Borrow>, - ) -> Vec { - let chars: &Range = chars.borrow(); - - let doc_comments = doc_comments - .iter() - .filter_map(|attr| Some((attr.span(), attr.doc_str().map(|a| a.as_str().to_owned())?))) - .collect::>(); - - let mut final_spans = vec![]; - let mut line_start_char_no = 0; - for (mut span, comment) in doc_comments { - let wanted_char_start = u32::try_from((chars.start).saturating_sub(line_start_char_no)).expect("it would be crazy if the doc string length was greater than the max val for a u32 i would be very impressed"); - let wanted_char_end = u32::try_from(usize::min( - (chars.end).saturating_sub(line_start_char_no), - comment.len(), - )) - .expect("same here..."); - - let wanted_span_start: BytePos = if wanted_char_start == 0 { - span.lo() - } else { - span.lo() + BytePos(wanted_char_start + DOC_COMMENT_PREFIX_LEN) - }; - let wanted_span_end = if wanted_char_end == 0 { - span.lo() - } else { - span.lo() + BytePos(wanted_char_end + DOC_COMMENT_PREFIX_LEN) - }; - - line_start_char_no += comment.len() + 1; - - if wanted_span_start > span.lo() { - span = span.with_lo(wanted_span_start); - } - if wanted_span_end < span.hi() { - span = span.with_hi(wanted_span_end); - } - - // trim all the spans we don't want to include - if span.hi() != span.lo() { - final_spans.push(span); - } - } - - final_spans.merge_adjacent() - } - - /// Returns the span for all `doc_comments`. - pub fn span_all_comments(doc_comments: &[Attribute]) -> Vec { - doc_comments - .iter() - .enumerate() - .filter_map(|attr| { - if let rustc_hir::Attribute::Parsed(kind) = attr.1 - && let rustc_hir::attrs::AttributeKind::DocComment { span, .. } = kind - { - Some(span) - } else { - None - } - }) - .merge_adjacent() - } - - /// Adaptor trait to call this function as a method. - trait Mergeable { - fn merge_adjacent(self) -> Vec; - } - - impl<'a, T> Mergeable for T - where - T: IntoIterator, - { - /// Merges spans that are adjacent in the iterator and correspond to adjacent regions of code. - fn merge_adjacent(self) -> Vec { - self.into_iter() - .fold(Vec::new(), |mut base: Vec, span: &Span| { - if let Some(last) = base.last_mut() - && last.hi() + BytePos(1) == span.lo() - { - // Merge the line spans if they're adjacent - *last = last.to(*span); - } else { - base.push(*span); - } - - base - }) - } - } -} diff --git a/crates/sniff-test/src/annotations/mod.rs b/crates/sniff-test/src/annotations/mod.rs index 844c7b7..566b2ea 100644 --- a/crates/sniff-test/src/annotations/mod.rs +++ b/crates/sniff-test/src/annotations/mod.rs @@ -3,7 +3,6 @@ use crate::{ annotations::doc::{Attributeable, DocStr, get_doc_str}, properties::Property, }; -// use parsing::ParseBulletsFromString; use regex::Regex; use rustc_ast::Item; use rustc_middle::ty::TyCtxt; @@ -19,23 +18,19 @@ use std::{any::TypeId, borrow::Borrow, collections::HashMap, fmt::Debug, hash::H mod doc; mod span; -// pub mod check; -// mod err; -// pub mod parsing; -// mod types; #[derive(Debug)] pub enum PropertyViolation { /// This property will always be violated. Unconditional, - // ConditionallyBad(Vec>), + // Conditionally(Vec>), /// This property will never be violated. Never, } #[derive(Debug)] pub enum AnnotationSource { - DocComment, + DocComment(Span), TomlOverride, } @@ -45,10 +40,10 @@ pub struct DefAnnotation { pub property_name: &'static str, /// The user's annotation for whether the given property is violated locally within this function. pub local_violation_annotation: PropertyViolation, + // TODO: add text + pub text: String, /// Where this obligation has come from. pub source: AnnotationSource, - - pub span: Span, } #[derive(Debug)] @@ -75,12 +70,14 @@ pub fn parse_fn_def( fn_def: impl Into, property: P, ) -> Option { + // TODO: add yash's logic here for checking the override toml file first. + // 1. get the doc string let fn_def: rustc_span::def_id::DefId = fn_def.into(); let doc_str = get_doc_str(fn_def, tcx)?; // 2. parse the doc string based on the property - simple_parse_fn_def(doc_str, property, AnnotationSource::DocComment) + parse_fn_def_src(doc_str, property) } fn parent_block_expr<'tcx>( @@ -103,48 +100,39 @@ pub fn parse_expr<'tcx, P: Property>( property: P, ) -> Option { // 1. get the doc string directly - let direct_annotation = get_doc_str(call_expr, tcx) - .and_then(|doc_str| simple_parse_callsite(doc_str, property, AnnotationSource::DocComment)); + let direct_annotation = + get_doc_str(call_expr, tcx).and_then(|doc_str| parse_expr_src(doc_str, property)); if let Some(direct) = direct_annotation { return Some(direct); } // 1. if we don't have it directly, trying getting it from a parent block... - simple_parse_callsite( + parse_expr_src( get_doc_str(parent_block_expr(tcx, call_expr)?, tcx)?, property, - AnnotationSource::DocComment, ) } -fn simple_parse_callsite( - doc_str: DocStr, - property: P, - source: AnnotationSource, -) -> Option { +fn parse_expr_src(doc_str: DocStr, property: P) -> Option { property .callsite_regex() .find(doc_str.str()) .map(|found| ExpressionAnnotation { - property_name: P::name(), + property_name: P::property_name(), text: doc_str.str()[found.end()..].to_string(), span: doc_str.span_of_chars(found.range()), }) } /// Simple check if the obligation regex is contained anywhere in the doc string, otherwise no obligations. -fn simple_parse_fn_def( - doc_str: DocStr, - property: P, - source: AnnotationSource, -) -> Option { +fn parse_fn_def_src(doc_str: DocStr, property: P) -> Option { property .fn_def_regex() .find(doc_str.str()) .map(|found| DefAnnotation { - property_name: P::name(), + property_name: P::property_name(), local_violation_annotation: PropertyViolation::Unconditional, - source, - span: doc_str.span_of_chars(found.range()), + text: doc_str.str()[found.end()..].to_string(), + source: AnnotationSource::DocComment(doc_str.span_of_chars(found.range())), }) } diff --git a/crates/sniff-test/src/annotations/types.rs b/crates/sniff-test/src/annotations/types.rs deleted file mode 100644 index dd646b3..0000000 --- a/crates/sniff-test/src/annotations/types.rs +++ /dev/null @@ -1,109 +0,0 @@ -//! Core annotation types. - -use std::borrow::Borrow; - -use serde::{Deserialize, Serialize}; - -#[derive(PartialEq, Eq, Debug, Serialize, Deserialize)] -/// A condition that must hold such that a given function call will not cause UB. -pub struct Requirement { - name: ConditionName, - description: String, -} - -impl Requirement { - pub fn new(name: ConditionName, description: impl Borrow) -> Self { - Requirement { - name, - description: description.borrow().to_string(), - } - } - - pub fn name(&self) -> &ConditionName { - &self.name - } - - pub fn description(&self) -> &str { - &self.description - } - - pub fn construct, B: Borrow>( - iter: impl IntoIterator, - ) -> Vec { - iter.into_iter() - .map(|(name, desc)| { - Requirement::new( - ConditionName::try_new(name) - .expect("construct should only be called with valid condition names"), - desc, - ) - }) - .collect() - } -} - -#[derive(PartialEq, Eq, Debug)] -/// The justification for why a given condition has been satisfied. -pub struct Justification { - name: ConditionName, - explanation: String, -} - -impl Justification { - pub fn new(name: ConditionName, explanation: impl Borrow) -> Self { - Justification { - name, - explanation: explanation.borrow().to_string(), - } - } - - pub fn name(&self) -> &ConditionName { - &self.name - } - - pub fn description(&self) -> &str { - &self.explanation - } -} - -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] -pub struct ConditionName(String); - -impl ConditionName { - /// Construct a new condition name, checking all invariants to ensure it is valid. - pub fn try_new>(name: T) -> Result { - // For now, just check that it's a single word with no extra white space. - Ok(ConditionName(check_single_word(name)?)) - } - - pub fn as_str(&self) -> &str { - &self.0 - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum InvalidConditionNameReason { - TrailingWhitespace, - MultipleWords, -} - -pub const INVALID_WHITESPACE: [char; 3] = [' ', '\n', '\t']; - -fn check_single_word>(name: T) -> Result { - let name = name.borrow(); - // Valid requirement names shouldn't contain whitespace. - if name.contains(INVALID_WHITESPACE) { - if name - .split(INVALID_WHITESPACE) - .filter(|word| !word.is_empty()) - .count() - == 1 - { - // no other words, just invalid whitespace - return Err(InvalidConditionNameReason::TrailingWhitespace); - } - // contains other words - return Err(InvalidConditionNameReason::MultipleWords); - } - Ok(name.to_string()) -} diff --git a/crates/sniff-test/src/check/err.rs b/crates/sniff-test/src/check/err.rs index affd016..c42d1d1 100644 --- a/crates/sniff-test/src/check/err.rs +++ b/crates/sniff-test/src/check/err.rs @@ -89,13 +89,13 @@ mod summary { .flatten() .join(" and "); - let kind = P::name(); + let kind = P::property_name(); format!("function {fn_name} directly contains {issue_summary}, but is not annotated {kind}") } fn call_summary(calls: &[CallsWObligations]) -> Option { let count: usize = calls.iter().map(|call| call.from_spans.len()).sum(); - let kind = P::name(); + let kind = P::property_name(); let s = match count { 1 => "", x if x > 1 => "s", @@ -108,7 +108,7 @@ mod summary { fn axiom_summary(axioms: &[Spanned]) -> Option { let count = axioms.len(); - let kind = P::name(); + let kind = P::property_name(); let s = match count { 1 => "", x if x > 1 => "s", diff --git a/crates/sniff-test/src/properties/mod.rs b/crates/sniff-test/src/properties/mod.rs index 6f8b7e3..4c167af 100644 --- a/crates/sniff-test/src/properties/mod.rs +++ b/crates/sniff-test/src/properties/mod.rs @@ -2,7 +2,7 @@ use crate::{ annotations::{self, PropertyViolation}, - reachability::{LocallyReachable, attr::SniffToolAttr}, + reachability::{LocallyReachable, attrs::SniffToolAttr}, }; use regex::Regex; use rustc_hir::intravisit::{self, Visitor}; @@ -20,9 +20,9 @@ mod safety; pub use panic::PanicProperty; pub use safety::SafetyProperty; -pub trait Property: Debug + 'static + Copy { +pub trait Property: Debug + Copy + 'static { type Axiom: Axiom; - fn name() -> &'static str; + fn property_name() -> &'static str; /// The regex marker (to be placed within function definition doc comments) /// which will register the function's body as having this property. @@ -44,7 +44,9 @@ pub trait Axiom: Display + Debug { type Property: Property; /// The name for this kind of axiom (e.g. `I found a {name} axiom in your code`) - fn axiom_kind_name() -> &'static str; + fn property_name() -> &'static str { + Self::Property::property_name() + } /// The requirements that this axiom has, if known. fn known_requirements(&self) -> Option { diff --git a/crates/sniff-test/src/properties/panic.rs b/crates/sniff-test/src/properties/panic.rs index 90dacff..e82bb9f 100644 --- a/crates/sniff-test/src/properties/panic.rs +++ b/crates/sniff-test/src/properties/panic.rs @@ -5,7 +5,7 @@ use rustc_span::source_map::{Spanned, respan}; use std::fmt::Display; use super::Axiom; -use crate::{annotations::PropertyViolation, properties::Property, reachability::attr}; +use crate::{annotations::PropertyViolation, properties::Property, reachability::attrs}; #[derive(Debug, Clone)] pub enum PanicAxiom { @@ -17,7 +17,7 @@ pub struct PanicProperty; impl Property for PanicProperty { type Axiom = PanicAxiom; - fn name() -> &'static str { + fn property_name() -> &'static str { "panicking" } @@ -57,9 +57,6 @@ impl Property for PanicProperty { impl Axiom for PanicAxiom { type Property = PanicProperty; - fn axiom_kind_name() -> &'static str { - "panicking" - } fn known_requirements(&self) -> Option { match self { @@ -70,8 +67,9 @@ impl Axiom for PanicAxiom { impl Display for PanicAxiom { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Self::ExplicitPanic => f.write_str("explicit panic"), - } + let name = match self { + Self::ExplicitPanic => "explicit panic", + }; + f.write_str(name) } } diff --git a/crates/sniff-test/src/properties/safety.rs b/crates/sniff-test/src/properties/safety.rs index fcd0b25..014cab5 100644 --- a/crates/sniff-test/src/properties/safety.rs +++ b/crates/sniff-test/src/properties/safety.rs @@ -11,15 +11,17 @@ use super::Axiom; use crate::{ annotations::{self, PropertyViolation}, properties::Property, - reachability::attr, + reachability::attrs, }; #[derive(Debug, Clone, Copy)] pub struct SafetyProperty; +// TODO: add some sort of additional checks function here that lets you do additional checks +// in this case, ensuring that all annotated unsafe functions have the unsafe keyword. impl Property for SafetyProperty { type Axiom = SafetyAxiom; - fn name() -> &'static str { + fn property_name() -> &'static str { "unsafe" } @@ -57,9 +59,6 @@ pub enum SafetyAxiom { impl Axiom for SafetyAxiom { type Property = SafetyProperty; - fn axiom_kind_name() -> &'static str { - "unsafe" - } fn known_requirements(&self) -> Option { todo!() @@ -76,8 +75,9 @@ impl Axiom for SafetyAxiom { impl Display for SafetyAxiom { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Self::RawPtrDeref => f.write_str("raw pointer derefence"), - } + let name = match self { + Self::RawPtrDeref => "raw pointer derefence", + }; + f.write_str(name) } } diff --git a/crates/sniff-test/src/reachability/attr.rs b/crates/sniff-test/src/reachability/attrs.rs similarity index 100% rename from crates/sniff-test/src/reachability/attr.rs rename to crates/sniff-test/src/reachability/attrs.rs diff --git a/crates/sniff-test/src/reachability/bad.rs b/crates/sniff-test/src/reachability/calls.rs similarity index 100% rename from crates/sniff-test/src/reachability/bad.rs rename to crates/sniff-test/src/reachability/calls.rs diff --git a/crates/sniff-test/src/reachability/entry.rs b/crates/sniff-test/src/reachability/entry.rs index c8d352e..7c9ced6 100644 --- a/crates/sniff-test/src/reachability/entry.rs +++ b/crates/sniff-test/src/reachability/entry.rs @@ -5,7 +5,7 @@ use rustc_middle::ty::TyCtxt; use crate::{ properties::Property, - reachability::attr::{self, SniffToolAttr}, + reachability::attrs::{self, SniffToolAttr}, }; pub fn analysis_entry_points(tcx: TyCtxt) -> Vec { @@ -30,7 +30,7 @@ pub fn analysis_entry_points(tcx: TyCtxt) -> Vec { fn find_global_annotation(tcx: TyCtxt) -> Option { let property_annots = - attr::get_sniff_tool_attrs(tcx.hir_krate_attrs(), &SniffToolAttr::try_from_string_pub) + attrs::get_sniff_tool_attrs(tcx.hir_krate_attrs(), &SniffToolAttr::try_from_string_pub) .into_iter() .filter(|(attr, _)| SniffToolAttr::matches_property::

(*attr)) .collect::>(); @@ -41,7 +41,10 @@ fn find_global_annotation(tcx: TyCtxt) -> Option // TODO: render error here if we have conflicting annotations... let box [(_attr, just_check_pub)] = property_annots.into_boxed_slice() else { - panic!("conflicting global for the {:?} property", P::name()); + panic!( + "conflicting global for the {:?} property", + P::property_name() + ); }; Some(GlobalAnnotation { just_check_pub }) } @@ -65,7 +68,7 @@ fn annotated_local_defs(tcx: TyCtxt) -> impl Iterator(tcx: TyCtxt, item: DefId) -> bool { - attr::attrs_for(item, tcx) + attrs::attrs_for(item, tcx) .into_iter() .any(SniffToolAttr::matches_property::

) } diff --git a/crates/sniff-test/src/reachability/err.rs b/crates/sniff-test/src/reachability/err.rs deleted file mode 100644 index c430451..0000000 --- a/crates/sniff-test/src/reachability/err.rs +++ /dev/null @@ -1,14 +0,0 @@ -use rustc_span::Span; - -// use crate::annotations::Justification; - -// #[derive(Debug)] -// pub enum ConsistencyIssue { -// UnsatisfiedJustification(Justification), -// } - -// #[derive(Debug)] -// pub struct ConsistencyError { -// call_at: Span, -// issue: ConsistencyIssue, -// } diff --git a/crates/sniff-test/src/reachability/mod.rs b/crates/sniff-test/src/reachability/mod.rs index 19f9c32..997d5d6 100644 --- a/crates/sniff-test/src/reachability/mod.rs +++ b/crates/sniff-test/src/reachability/mod.rs @@ -1,9 +1,8 @@ -pub mod attr; -mod bad; +pub mod attrs; +mod calls; mod entry; -mod err; -mod walk; +mod reach; -pub use bad::{CallsWObligations, find_calls_w_obligations}; +pub use calls::{CallsWObligations, find_calls_w_obligations}; pub use entry::analysis_entry_points; -pub use walk::{LocallyReachable, locally_reachable_from}; +pub use reach::{LocallyReachable, locally_reachable_from}; diff --git a/crates/sniff-test/src/reachability/walk.rs b/crates/sniff-test/src/reachability/reach.rs similarity index 100% rename from crates/sniff-test/src/reachability/walk.rs rename to crates/sniff-test/src/reachability/reach.rs diff --git a/tests/unsafe/example_crate/src/main.rs b/tests/unsafe/example_crate/src/main.rs index 35eac7c..6d45b1c 100644 --- a/tests/unsafe/example_crate/src/main.rs +++ b/tests/unsafe/example_crate/src/main.rs @@ -1,18 +1,25 @@ -#![sniff_test_attrs::check_unsafe_pub] +#![sniff_tool::check_unsafe_pub] /// # Safety -/// - non-null: ptr must be non-null +/// fn foo(ptr: *const i32) -> i32 { - let a = baz(ptr); - a + 2 + 0 } +/// # Safety +/// I've checked ptr is non-null and aligned pub fn baz(ptr: *const i32) -> i32 { + if !ptr.is_aligned() {return 0;} + // I've checked unsafe { *ptr } } #[sniff_test_attrs::check_unsafe] fn bar(ptr: *const i32) -> i32 { + + unsafe { + baz(ptr); + } /// SAFETY: /// - non-null: i checked to make sure this is nn // if !ptr.is_null() { From 3f97d9d93d01fe3455f2f4415e7e7af0478265db Mon Sep 17 00:00:00 2001 From: AlexanderPortland Date: Tue, 11 Nov 2025 21:20:12 -0500 Subject: [PATCH 35/40] allow justifications directly on axioms --- crates/sniff-test-attrs/src/lib.rs | 2 +- crates/sniff-test/src/annotations/mod.rs | 2 +- crates/sniff-test/src/check/err.rs | 20 ++++++++++------- crates/sniff-test/src/check/mod.rs | 13 +++++++++-- crates/sniff-test/src/properties/mod.rs | 25 ++++++++++++++-------- crates/sniff-test/src/properties/panic.rs | 21 ++++++++++++------ crates/sniff-test/src/properties/safety.rs | 17 +++++++++------ tests/unsafe/example_crate/src/main.rs | 5 ++--- 8 files changed, 67 insertions(+), 38 deletions(-) diff --git a/crates/sniff-test-attrs/src/lib.rs b/crates/sniff-test-attrs/src/lib.rs index 3974811..8cea7e4 100644 --- a/crates/sniff-test-attrs/src/lib.rs +++ b/crates/sniff-test-attrs/src/lib.rs @@ -29,6 +29,6 @@ macro_rules! define_sniff_tool_annotation { define_sniff_tool_annotation!(check_unsafe); -// TODO: could be useful to have a macro for checking unsafe public functions in the future, +// TODO: could be useful to have a macro for calling sniff_tool::[..]_pub in the future, // but for now, not worth the effort. Turns out we'd need the sniff tool attr to be after all // the prelude import stuff and with just a token tree its very hard to handle that. diff --git a/crates/sniff-test/src/annotations/mod.rs b/crates/sniff-test/src/annotations/mod.rs index 566b2ea..57ad0a5 100644 --- a/crates/sniff-test/src/annotations/mod.rs +++ b/crates/sniff-test/src/annotations/mod.rs @@ -40,7 +40,7 @@ pub struct DefAnnotation { pub property_name: &'static str, /// The user's annotation for whether the given property is violated locally within this function. pub local_violation_annotation: PropertyViolation, - // TODO: add text + // The textual content of this annotation. pub text: String, /// Where this obligation has come from. pub source: AnnotationSource, diff --git a/crates/sniff-test/src/check/err.rs b/crates/sniff-test/src/check/err.rs index c42d1d1..3432d6d 100644 --- a/crates/sniff-test/src/check/err.rs +++ b/crates/sniff-test/src/check/err.rs @@ -1,3 +1,4 @@ +use crate::properties::FoundAxiom; use itertools::Itertools; use rustc_errors::Diag; use rustc_middle::ty::TyCtxt; @@ -8,11 +9,11 @@ use crate::{ reachability::{CallsWObligations, LocallyReachable}, }; -pub fn report_errors( - tcx: TyCtxt, +pub fn report_errors<'tcx, P: Property>( + tcx: TyCtxt<'tcx>, func: LocallyReachable, property: P, - unjustified_axioms: Vec>, + unjustified_axioms: Vec>, unjustified_calls: Vec, ) -> ErrorGuaranteed { let dcx = tcx.dcx(); @@ -37,9 +38,12 @@ pub fn report_errors( diag.emit() } -fn extend_diag_axiom(diag: Diag, axiom: Spanned) -> Diag { +fn extend_diag_axiom<'tcx, P: Property>( + diag: Diag<'tcx>, + axiom: FoundAxiom<'tcx, P::Axiom>, +) -> Diag<'tcx> { // TODO: add notes about the known requirements - diag.with_span_note(axiom.span, format!("{} here", axiom.node)) + diag.with_span_note(axiom.span, format!("{} here", axiom.axiom)) } fn extend_diag_calls<'tcx>( @@ -74,12 +78,12 @@ mod summary { use itertools::Itertools; use rustc_span::source_map::Spanned; - use crate::properties::{Axiom, Property}; + use crate::properties::{Axiom, FoundAxiom, Property}; use crate::reachability::CallsWObligations; pub fn summary_string( fn_name: &str, - axioms: &[Spanned], + axioms: &[FoundAxiom<'_, P::Axiom>], calls: &[CallsWObligations], ) -> String { let axiom_summary = axiom_summary::

(axioms); @@ -106,7 +110,7 @@ mod summary { )) } - fn axiom_summary(axioms: &[Spanned]) -> Option { + fn axiom_summary(axioms: &[FoundAxiom<'_, P::Axiom>]) -> Option { let count = axioms.len(); let kind = P::property_name(); let s = match count { diff --git a/crates/sniff-test/src/check/mod.rs b/crates/sniff-test/src/check/mod.rs index f66385a..32c950f 100644 --- a/crates/sniff-test/src/check/mod.rs +++ b/crates/sniff-test/src/check/mod.rs @@ -6,7 +6,7 @@ use rustc_span::{ErrorGuaranteed, source_map::Spanned, sym::todo_macro}; use crate::{ annotations::{self, parse_expr}, - properties::{self, Axiom, Property}, + properties::{self, Axiom, FoundAxiom, Property}, reachability::{self, CallsWObligations, LocallyReachable}, utils::SniffTestDiagnostic, }; @@ -63,7 +63,9 @@ fn check_function_properties( } // Look for all axioms within this function - let axioms = properties::find_axioms(tcx, &func, property); + let axioms = properties::find_axioms(tcx, &func, property) + .filter(only_unjustified_axioms(tcx, property)) + .collect::>(); log::debug!("fn {:?} has axioms {:?}", func.reach, axioms); log::debug!("fn {:?} has obligations {:?}", func.reach, annotation); @@ -91,6 +93,13 @@ fn check_function_properties( } } +fn only_unjustified_axioms<'tcx, P: Property>( + tcx: TyCtxt<'tcx>, + property: P, +) -> impl Fn(&FoundAxiom<'tcx, P::Axiom>) -> bool { + move |axiom| parse_expr(tcx, *axiom.found_in, property).is_none() +} + /// Filter a set of calls to a function for only those which are not property justified. fn only_unjustified_callsites( tcx: TyCtxt, diff --git a/crates/sniff-test/src/properties/mod.rs b/crates/sniff-test/src/properties/mod.rs index 4c167af..0a6f300 100644 --- a/crates/sniff-test/src/properties/mod.rs +++ b/crates/sniff-test/src/properties/mod.rs @@ -32,12 +32,12 @@ pub trait Property: Debug + Copy + 'static { /// that indicates obligations have been discharged. fn callsite_regex(&self) -> Regex; - fn find_axioms_in_expr( + fn find_axioms_in_expr<'tcx>( &mut self, - tcx: TyCtxt, + tcx: TyCtxt<'tcx>, tyck: &TypeckResults, - expr: &rustc_hir::Expr, - ) -> Vec>; + expr: &'tcx rustc_hir::Expr, + ) -> Vec>; } pub trait Axiom: Display + Debug { @@ -54,18 +54,25 @@ pub trait Axiom: Display + Debug { } } +#[derive(Debug, Clone)] +pub struct FoundAxiom<'tcx, A: Axiom> { + pub axiom: A, + pub found_in: &'tcx rustc_hir::Expr<'tcx>, + pub span: rustc_span::Span, +} + struct FinderWrapper<'tcx, T: Property> { tcx: TyCtxt<'tcx>, property: T, tychck: &'tcx TypeckResults<'tcx>, - axioms: Vec>, + axioms: Vec>, } -pub fn find_axioms( - tcx: TyCtxt, +pub fn find_axioms<'tcx, T: Property>( + tcx: TyCtxt<'tcx>, locally_reachable: &LocallyReachable, property: T, -) -> Vec> { +) -> impl Iterator> { let body = tcx.hir_body_owned_by(locally_reachable.reach).id(); let tychck = tcx.typeck_body(body); @@ -78,7 +85,7 @@ pub fn find_axioms( finder.visit_nested_body(body); - finder.axioms + finder.axioms.into_iter() } impl<'tcx, T: Property> Visitor<'tcx> for FinderWrapper<'tcx, T> { diff --git a/crates/sniff-test/src/properties/panic.rs b/crates/sniff-test/src/properties/panic.rs index e82bb9f..eff436e 100644 --- a/crates/sniff-test/src/properties/panic.rs +++ b/crates/sniff-test/src/properties/panic.rs @@ -5,7 +5,11 @@ use rustc_span::source_map::{Spanned, respan}; use std::fmt::Display; use super::Axiom; -use crate::{annotations::PropertyViolation, properties::Property, reachability::attrs}; +use crate::{ + annotations::PropertyViolation, + properties::{FoundAxiom, Property}, + reachability::attrs, +}; #[derive(Debug, Clone)] pub enum PanicAxiom { @@ -29,12 +33,12 @@ impl Property for PanicProperty { Regex::new("(\n|^)(\\s*)[#]+ (Panics|PANICS)(\n|$)").unwrap() } - fn find_axioms_in_expr( + fn find_axioms_in_expr<'tcx>( &mut self, - tcx: TyCtxt, + tcx: TyCtxt<'tcx>, tyck: &rustc_middle::ty::TypeckResults, - expr: &rustc_hir::Expr, - ) -> Vec> { + expr: &'tcx rustc_hir::Expr<'tcx>, + ) -> Vec> { if let ExprKind::Call(func, _) = expr.kind && let Some(def_id) = tyck.type_dependent_def_id(func.hir_id) { @@ -46,8 +50,11 @@ impl Property for PanicProperty { || Some(def_id) == lang_items.begin_panic_fn() || Some(def_id) == lang_items.panic_impl() { - let value = respan(expr.span, PanicAxiom::ExplicitPanic); - return vec![value]; + return vec![FoundAxiom { + axiom: PanicAxiom::ExplicitPanic, + span: expr.span, + found_in: expr, + }]; } } diff --git a/crates/sniff-test/src/properties/safety.rs b/crates/sniff-test/src/properties/safety.rs index 014cab5..234381f 100644 --- a/crates/sniff-test/src/properties/safety.rs +++ b/crates/sniff-test/src/properties/safety.rs @@ -10,7 +10,7 @@ use rustc_type_ir::TyKind; use super::Axiom; use crate::{ annotations::{self, PropertyViolation}, - properties::Property, + properties::{FoundAxiom, Property}, reachability::attrs, }; @@ -33,18 +33,21 @@ impl Property for SafetyProperty { Regex::new("(\n|^)(\\s*)(Safety|SAFETY):").unwrap() } - fn find_axioms_in_expr( + fn find_axioms_in_expr<'tcx>( &mut self, - tcx: TyCtxt, + tcx: TyCtxt<'tcx>, tyck: &rustc_middle::ty::TypeckResults, - expr: &rustc_hir::Expr, - ) -> Vec> { + expr: &'tcx rustc_hir::Expr<'tcx>, + ) -> Vec> { if let ExprKind::Unary(UnOp::Deref, expr) = expr.kind { let inner_ty = tyck.expr_ty(expr); if let TyKind::RawPtr(_ty, _mut) = inner_ty.kind() { - let value = respan(expr.span, SafetyAxiom::RawPtrDeref); - return vec![value]; + return vec![FoundAxiom { + axiom: SafetyAxiom::RawPtrDeref, + span: expr.span, + found_in: expr, + }]; } } diff --git a/tests/unsafe/example_crate/src/main.rs b/tests/unsafe/example_crate/src/main.rs index 6d45b1c..7569f82 100644 --- a/tests/unsafe/example_crate/src/main.rs +++ b/tests/unsafe/example_crate/src/main.rs @@ -6,11 +6,10 @@ fn foo(ptr: *const i32) -> i32 { 0 } -/// # Safety +/// # Saety /// I've checked ptr is non-null and aligned pub fn baz(ptr: *const i32) -> i32 { - if !ptr.is_aligned() {return 0;} - // I've checked + /// SAFETY: ptr is non null I've checked unsafe { *ptr } } From 3588a19fcd35bdd2d66a64e0114b23ed037a2374 Mon Sep 17 00:00:00 2001 From: Yash Agrawal Date: Wed, 12 Nov 2025 14:41:11 -0500 Subject: [PATCH 36/40] temporary toml solution without proper string parsing --- crates/sniff-test/src/annotations/toml.rs | 30 ++++++++++---------- crates/sniff-test/src/check/mod.rs | 34 ----------------------- 2 files changed, 14 insertions(+), 50 deletions(-) diff --git a/crates/sniff-test/src/annotations/toml.rs b/crates/sniff-test/src/annotations/toml.rs index 46253b6..04e3a5c 100644 --- a/crates/sniff-test/src/annotations/toml.rs +++ b/crates/sniff-test/src/annotations/toml.rs @@ -16,12 +16,12 @@ use rustc_span::{ source_map::{Spanned, respan}, }; -use crate::annotations::{ParsingIssue, Requirement, parsing::ParseBulletsFromString}; +use crate::annotations::DefAnnotation; /// Struct encapsulating annotations parsed from a TOML file. #[derive(Default)] pub struct TomlAnnotation { - function_to_requirements: HashMap>>, + function_to_requirements: HashMap>, } /// Errors that can occur when parsing TOML annotations. @@ -30,7 +30,6 @@ pub enum TomlParseError { Io(std::io::Error), Toml(toml::de::Error), Schema(String), - Parse(ParsingIssue), } impl From for TomlParseError { @@ -45,10 +44,14 @@ impl From for TomlParseError { } } -impl From for TomlParseError { - fn from(err: ParsingIssue) -> Self { - TomlParseError::Parse(err) - } +// Temporary filler function for string -> DefAnnotation conversion. +fn temp_parse_requirement_string(requirement_str: &str) -> Vec { + vec![DefAnnotation { + property_name: "temp_property", + local_violation_annotation: crate::annotations::PropertyViolation::Unconditional, + text: requirement_str.to_string(), + source: crate::annotations::AnnotationSource::TomlOverride, + }] } impl TomlAnnotation { @@ -69,8 +72,7 @@ impl TomlAnnotation { }; // Parse each function's requirements - let mut function_to_requirements: HashMap>> = - HashMap::new(); + let mut function_to_requirements: HashMap> = HashMap::new(); for (function_name, value) in table { let Some(inner_table) = value.as_table() else { return Err(TomlParseError::Schema(format!( @@ -88,12 +90,8 @@ impl TomlAnnotation { ))); }; - let requirements = Requirement::parse_bullets_from_string(requirements_string)?; - let spanned_requirements: Vec> = requirements - .into_iter() - .map(|(req, _range)| respan(DUMMY_SP, req)) - .collect(); - function_to_requirements.insert(function_name.clone(), spanned_requirements); + let def_annotation = temp_parse_requirement_string(requirements_string); + function_to_requirements.insert(function_name.clone(), def_annotation); } // Return the parsed annotations @@ -106,7 +104,7 @@ impl TomlAnnotation { pub fn get_requirements_for_function( &self, function_name: &str, - ) -> Option<&Vec>> { + ) -> Option<&Vec> { self.function_to_requirements.get(function_name) } } diff --git a/crates/sniff-test/src/check/mod.rs b/crates/sniff-test/src/check/mod.rs index 3045718..95d69c9 100644 --- a/crates/sniff-test/src/check/mod.rs +++ b/crates/sniff-test/src/check/mod.rs @@ -11,7 +11,6 @@ use rustc_span::{ use crate::{ annotations::{ self, parse_expr, - parsing::ParseBulletsFromString, toml::{TomlAnnotation, TomlParseError}, }, properties::{self, Axiom, FoundAxiom, Property}, @@ -22,39 +21,6 @@ use crate::{ mod err; mod expr; -// Note, I don't really get and didn't fully implement the correct error handling for toml fallback. -fn get_requirements( - tcx: TyCtxt, - def_id: DefId, - toml_annotations: &TomlAnnotation, -) -> Option>> { - // First, try to parse from code annotations - if let Some(in_code) = annotations::Requirement::try_parse(tcx, def_id) { - match in_code { - Ok(reqs) => { - println!( - "Parsed requirements from code for {}: {:?}", - tcx.def_path_str(def_id), - reqs - ); - return Some(reqs); - } - Err(e) => { - e.emit(tcx.dcx()); - return None; - } - } - } - - // Next, try to parse from external doc strings - let fn_name = tcx.def_path_str(def_id); - if let Some(reqs) = toml_annotations.get_requirements_for_function(&fn_name) { - return Some(reqs.clone()); - } - - None -} - /// Checks that all local functions in the crate are properly annotated. pub fn check_properly_annotated( tcx: TyCtxt, From 641459d51d6a24aa600551abd02d2561efbbb4d4 Mon Sep 17 00:00:00 2001 From: Yash Agrawal Date: Wed, 12 Nov 2025 20:33:40 -0500 Subject: [PATCH 37/40] parsing seems to not work --- crates/sniff-test/src/annotations/mod.rs | 44 +++++++++++++++++---- crates/sniff-test/src/annotations/toml.rs | 36 +++++++---------- crates/sniff-test/src/check/mod.rs | 15 +++---- crates/sniff-test/src/reachability/calls.rs | 9 +++-- 4 files changed, 64 insertions(+), 40 deletions(-) diff --git a/crates/sniff-test/src/annotations/mod.rs b/crates/sniff-test/src/annotations/mod.rs index 39ea69c..5e1bb1f 100644 --- a/crates/sniff-test/src/annotations/mod.rs +++ b/crates/sniff-test/src/annotations/mod.rs @@ -1,6 +1,9 @@ //! The utilities needed to find and parse code annotations. use crate::{ - annotations::doc::{Attributeable, DocStr, get_doc_str}, + annotations::{ + doc::{Attributeable, DocStr, get_doc_str}, + toml::TomlAnnotation, + }, properties::Property, }; use regex::Regex; @@ -68,17 +71,22 @@ impl DefAnnotation { /// annotated. pub fn parse_fn_def( tcx: TyCtxt<'_>, + toml_annotation: &TomlAnnotation, fn_def: impl Into, property: P, ) -> Option { - // TODO: add yash's logic here for checking the override toml file first. - - // 1. get the doc string + // 1. Get the DefId let fn_def: rustc_span::def_id::DefId = fn_def.into(); - let doc_str = get_doc_str(fn_def, tcx)?; - // 2. parse the doc string based on the property - parse_fn_def_src(doc_str, property) + // 2. Check if we have a TOML override for this function + if let Some(toml_str) = toml_annotation.get_requirements_string(&tcx.def_path_str(fn_def)) { + parse_fn_def_toml(toml_str, property) + } else { + // 3. No TOML override found, get the doc string from source code + let doc_str = get_doc_str(fn_def, tcx)?; + // 4. parse the doc string based on the property + parse_fn_def_src(doc_str, property) + } } fn parent_block_expr<'tcx>( @@ -127,7 +135,7 @@ fn parse_expr_src(doc_str: DocStr, property: P) -> Option(doc_str: DocStr, property: P) -> Option { - property + let out = property .fn_def_regex() .find(doc_str.str()) .map(|found| DefAnnotation { @@ -135,5 +143,25 @@ fn parse_fn_def_src(doc_str: DocStr, property: P) -> Option(toml_str: &str, property: P) -> Option { + property + .fn_def_regex() + .find(toml_str) + .map(|found| DefAnnotation { + property_name: P::property_name(), + local_violation_annotation: PropertyViolation::Unconditional, + text: toml_str[found.end()..].to_string(), + source: AnnotationSource::TomlOverride, }) } diff --git a/crates/sniff-test/src/annotations/toml.rs b/crates/sniff-test/src/annotations/toml.rs index 04e3a5c..e4d68b8 100644 --- a/crates/sniff-test/src/annotations/toml.rs +++ b/crates/sniff-test/src/annotations/toml.rs @@ -21,7 +21,7 @@ use crate::annotations::DefAnnotation; /// Struct encapsulating annotations parsed from a TOML file. #[derive(Default)] pub struct TomlAnnotation { - function_to_requirements: HashMap>, + function_to_requirements_string: HashMap, } /// Errors that can occur when parsing TOML annotations. @@ -44,16 +44,6 @@ impl From for TomlParseError { } } -// Temporary filler function for string -> DefAnnotation conversion. -fn temp_parse_requirement_string(requirement_str: &str) -> Vec { - vec![DefAnnotation { - property_name: "temp_property", - local_violation_annotation: crate::annotations::PropertyViolation::Unconditional, - text: requirement_str.to_string(), - source: crate::annotations::AnnotationSource::TomlOverride, - }] -} - impl TomlAnnotation { /// Parses a TOML annotation file and returns a TomlAnnotation struct. /// Fails on any errors, never returning partial results. @@ -61,7 +51,14 @@ impl TomlAnnotation { /// TODO: Use real spans if possible. pub fn from_file>(path: P) -> Result { // Get the contents of the TOML file - let text = std::fs::read_to_string(path)?; + let text = match std::fs::read_to_string(path) { + Ok(text) => text, + Err(e) if e.kind() == std::io::ErrorKind::NotFound => { + // File does not exist, return empty annotations + return Ok(TomlAnnotation::default()); + } + Err(e) => return Err(TomlParseError::Io(e)), + }; // Parse the TOML file into a map from function names to requirement strings let value: toml::Value = toml::from_str(&text)?; @@ -72,7 +69,7 @@ impl TomlAnnotation { }; // Parse each function's requirements - let mut function_to_requirements: HashMap> = HashMap::new(); + let mut function_to_requirements_string: HashMap = HashMap::new(); for (function_name, value) in table { let Some(inner_table) = value.as_table() else { return Err(TomlParseError::Schema(format!( @@ -90,21 +87,18 @@ impl TomlAnnotation { ))); }; - let def_annotation = temp_parse_requirement_string(requirements_string); - function_to_requirements.insert(function_name.clone(), def_annotation); + function_to_requirements_string + .insert(function_name.clone(), requirements_string.to_string()); } // Return the parsed annotations Ok(TomlAnnotation { - function_to_requirements, + function_to_requirements_string: function_to_requirements_string, }) } /// Retrieves the requirements for a given function name, if any. - pub fn get_requirements_for_function( - &self, - function_name: &str, - ) -> Option<&Vec> { - self.function_to_requirements.get(function_name) + pub fn get_requirements_string(&self, function_name: &str) -> Option<&String> { + self.function_to_requirements_string.get(function_name) } } diff --git a/crates/sniff-test/src/check/mod.rs b/crates/sniff-test/src/check/mod.rs index 95d69c9..f71d288 100644 --- a/crates/sniff-test/src/check/mod.rs +++ b/crates/sniff-test/src/check/mod.rs @@ -26,7 +26,6 @@ pub fn check_properly_annotated( tcx: TyCtxt, property: P, ) -> Result<(), ErrorGuaranteed> { - // Parse TOML annotations from file let toml_path = "sniff-test.toml"; let toml_annotations = match TomlAnnotation::from_file(toml_path) { @@ -62,7 +61,7 @@ pub fn check_properly_annotated( // For all reachable local function definitions, ensure their axioms align with their annotations. for func in reachable { - check_function_properties(tcx, func, property)?; + check_function_properties(tcx, &toml_annotations, func, property)?; } Ok(()) @@ -70,11 +69,12 @@ pub fn check_properly_annotated( fn check_function_properties( tcx: TyCtxt, + toml_annotations: &TomlAnnotation, func: LocallyReachable, property: P, ) -> Result<(), ErrorGuaranteed> { // Look for the local annotation - let annotation = annotations::parse_fn_def(tcx, func.reach, property); + let annotation = annotations::parse_fn_def(tcx, toml_annotations, func.reach, property); // If the function we're analyzing is directly annotated, we trust the user's annotation // and don't need to analyze its body locally. Vitally, we'll still explore functions it calls @@ -93,10 +93,11 @@ fn check_function_properties( log::debug!("fn {:?} has obligations {:?}", func.reach, annotation); // Find all calls that have obligations. - let unjustified_calls = reachability::find_calls_w_obligations(tcx, &func, property) - // Filter those with only callsites that haven't been justified. - .filter_map(only_unjustified_callsites(tcx, func.reach, property)) - .collect::>(); + let unjustified_calls = + reachability::find_calls_w_obligations(tcx, toml_annotations, &func, property) + // Filter those with only callsites that haven't been justified. + .filter_map(only_unjustified_callsites(tcx, func.reach, property)) + .collect::>(); // If we have obligations, we've dismissed them diff --git a/crates/sniff-test/src/reachability/calls.rs b/crates/sniff-test/src/reachability/calls.rs index 2e27890..a1c7f21 100644 --- a/crates/sniff-test/src/reachability/calls.rs +++ b/crates/sniff-test/src/reachability/calls.rs @@ -1,6 +1,6 @@ //! Finds the 'bad' functions that should be annotated -use crate::annotations::{self, DefAnnotation, parse_fn_def}; +use crate::annotations::{self, DefAnnotation, parse_fn_def, toml::TomlAnnotation}; use crate::properties::Property; use crate::reachability::LocallyReachable; use std::collections::HashMap; @@ -23,11 +23,11 @@ pub struct CallsWObligations { fn call_has_obligations( tcx: TyCtxt, + toml_annotations: &TomlAnnotation, property: P, ) -> impl Fn((&DefId, &Vec)) -> Option { move |(to_def_id, from_spans)| { - let annotation = parse_fn_def(tcx, *to_def_id, property)?; - + let annotation = parse_fn_def(tcx, toml_annotations, *to_def_id, property)?; if annotation.creates_obligation() { Some(CallsWObligations { call_to: *to_def_id, @@ -42,11 +42,12 @@ fn call_has_obligations( pub fn find_calls_w_obligations( tcx: TyCtxt, + toml_annotations: &TomlAnnotation, locally_reachable: &LocallyReachable, property: P, ) -> impl Iterator { locally_reachable .calls_to .iter() - .filter_map(call_has_obligations(tcx, property)) + .filter_map(call_has_obligations(tcx, toml_annotations, property)) } From fbf92ee2d309b6b70a0c35559100907aa9b61521 Mon Sep 17 00:00:00 2001 From: Yash Agrawal Date: Wed, 12 Nov 2025 22:59:59 -0500 Subject: [PATCH 38/40] toml is working --- crates/sniff-test/src/annotations/mod.rs | 12 ++----- crates/sniff-test/src/properties/safety.rs | 2 +- tests/toml/fail_external/Cargo.lock | 41 ++++++++++++++++++++++ tests/toml/fail_external/Cargo.toml | 9 +++++ tests/toml/fail_external/pass_simple.snap | 8 +++++ tests/toml/fail_external/sniff-test.toml | 5 +++ tests/toml/fail_external/src/main.rs | 7 ++++ 7 files changed, 73 insertions(+), 11 deletions(-) create mode 100644 tests/toml/fail_external/Cargo.lock create mode 100644 tests/toml/fail_external/Cargo.toml create mode 100644 tests/toml/fail_external/pass_simple.snap create mode 100644 tests/toml/fail_external/sniff-test.toml create mode 100644 tests/toml/fail_external/src/main.rs diff --git a/crates/sniff-test/src/annotations/mod.rs b/crates/sniff-test/src/annotations/mod.rs index 5e1bb1f..e351667 100644 --- a/crates/sniff-test/src/annotations/mod.rs +++ b/crates/sniff-test/src/annotations/mod.rs @@ -135,7 +135,7 @@ fn parse_expr_src(doc_str: DocStr, property: P) -> Option(doc_str: DocStr, property: P) -> Option { - let out = property + property .fn_def_regex() .find(doc_str.str()) .map(|found| DefAnnotation { @@ -143,15 +143,7 @@ fn parse_fn_def_src(doc_str: DocStr, property: P) -> Option(toml_str: &str, property: P) -> Option { diff --git a/crates/sniff-test/src/properties/safety.rs b/crates/sniff-test/src/properties/safety.rs index 234381f..c9e77af 100644 --- a/crates/sniff-test/src/properties/safety.rs +++ b/crates/sniff-test/src/properties/safety.rs @@ -26,7 +26,7 @@ impl Property for SafetyProperty { } fn fn_def_regex(&self) -> Regex { - Regex::new("(\n|^)(\\s*)[#]+ (Safety|SAFETY)(\n|$)").unwrap() + Regex::new("(\n|^)(\\s*)[#]+ (Unsafe|UNSAFE)(\n|$)").unwrap() } fn callsite_regex(&self) -> Regex { diff --git a/tests/toml/fail_external/Cargo.lock b/tests/toml/fail_external/Cargo.lock new file mode 100644 index 0000000..9a2d460 --- /dev/null +++ b/tests/toml/fail_external/Cargo.lock @@ -0,0 +1,41 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "invalid_simple" +version = "0.1.0" +dependencies = [ + "sniff-test-attrs", +] + +[[package]] +name = "proc-macro2" +version = "1.0.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "sniff-test-attrs" +version = "0.1.0" +dependencies = [ + "quote", +] + +[[package]] +name = "unicode-ident" +version = "1.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" diff --git a/tests/toml/fail_external/Cargo.toml b/tests/toml/fail_external/Cargo.toml new file mode 100644 index 0000000..6f3b543 --- /dev/null +++ b/tests/toml/fail_external/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "invalid_simple" +version = "0.1.0" +edition = "2024" + +[dependencies] +sniff-test-attrs = { path = "../../../crates/sniff-test-attrs" } + +[workspace] \ No newline at end of file diff --git a/tests/toml/fail_external/pass_simple.snap b/tests/toml/fail_external/pass_simple.snap new file mode 100644 index 0000000..685329e --- /dev/null +++ b/tests/toml/fail_external/pass_simple.snap @@ -0,0 +1,8 @@ +--- +source: tests/lib.rs +--- +exit_code = 0 +stdout = ''' +compilation successful!! +''' +stderr = '' diff --git a/tests/toml/fail_external/sniff-test.toml b/tests/toml/fail_external/sniff-test.toml new file mode 100644 index 0000000..4fd1e1b --- /dev/null +++ b/tests/toml/fail_external/sniff-test.toml @@ -0,0 +1,5 @@ +["std::thread::sleep"] +requirements = """ +# Unsafe +- non-blocking: Function must not be called in a routine which cannot block. +""" \ No newline at end of file diff --git a/tests/toml/fail_external/src/main.rs b/tests/toml/fail_external/src/main.rs new file mode 100644 index 0000000..6556825 --- /dev/null +++ b/tests/toml/fail_external/src/main.rs @@ -0,0 +1,7 @@ +use std::thread; +use std::time::Duration; + +#[sniff_test_attrs::check_unsafe] +fn main() { + thread::sleep(Duration::from_millis(100)); +} From fd53659750565204067a5d5e27ced548796b2ab2 Mon Sep 17 00:00:00 2001 From: Yash Agrawal Date: Wed, 12 Nov 2025 23:02:25 -0500 Subject: [PATCH 39/40] added a test for toml --- tests/toml/pass_external/Cargo.lock | 41 +++++++++++++++++++++++ tests/toml/pass_external/Cargo.toml | 9 +++++ tests/toml/pass_external/pass_simple.snap | 8 +++++ tests/toml/pass_external/sniff-test.toml | 5 +++ tests/toml/pass_external/src/main.rs | 9 +++++ 5 files changed, 72 insertions(+) create mode 100644 tests/toml/pass_external/Cargo.lock create mode 100644 tests/toml/pass_external/Cargo.toml create mode 100644 tests/toml/pass_external/pass_simple.snap create mode 100644 tests/toml/pass_external/sniff-test.toml create mode 100644 tests/toml/pass_external/src/main.rs diff --git a/tests/toml/pass_external/Cargo.lock b/tests/toml/pass_external/Cargo.lock new file mode 100644 index 0000000..9a2d460 --- /dev/null +++ b/tests/toml/pass_external/Cargo.lock @@ -0,0 +1,41 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "invalid_simple" +version = "0.1.0" +dependencies = [ + "sniff-test-attrs", +] + +[[package]] +name = "proc-macro2" +version = "1.0.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "sniff-test-attrs" +version = "0.1.0" +dependencies = [ + "quote", +] + +[[package]] +name = "unicode-ident" +version = "1.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" diff --git a/tests/toml/pass_external/Cargo.toml b/tests/toml/pass_external/Cargo.toml new file mode 100644 index 0000000..6f3b543 --- /dev/null +++ b/tests/toml/pass_external/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "invalid_simple" +version = "0.1.0" +edition = "2024" + +[dependencies] +sniff-test-attrs = { path = "../../../crates/sniff-test-attrs" } + +[workspace] \ No newline at end of file diff --git a/tests/toml/pass_external/pass_simple.snap b/tests/toml/pass_external/pass_simple.snap new file mode 100644 index 0000000..685329e --- /dev/null +++ b/tests/toml/pass_external/pass_simple.snap @@ -0,0 +1,8 @@ +--- +source: tests/lib.rs +--- +exit_code = 0 +stdout = ''' +compilation successful!! +''' +stderr = '' diff --git a/tests/toml/pass_external/sniff-test.toml b/tests/toml/pass_external/sniff-test.toml new file mode 100644 index 0000000..4fd1e1b --- /dev/null +++ b/tests/toml/pass_external/sniff-test.toml @@ -0,0 +1,5 @@ +["std::thread::sleep"] +requirements = """ +# Unsafe +- non-blocking: Function must not be called in a routine which cannot block. +""" \ No newline at end of file diff --git a/tests/toml/pass_external/src/main.rs b/tests/toml/pass_external/src/main.rs new file mode 100644 index 0000000..b8815cd --- /dev/null +++ b/tests/toml/pass_external/src/main.rs @@ -0,0 +1,9 @@ +use std::thread; +use std::time::Duration; + +#[sniff_test_attrs::check_unsafe] +fn main() { + /// Safety: + /// - non-blocking: this function can block + thread::sleep(Duration::from_millis(100)); +} From 6e23aef6b6bba1924e5adce8a4a00ef42d544ba5 Mon Sep 17 00:00:00 2001 From: Yash Agrawal Date: Thu, 13 Nov 2025 12:59:17 -0500 Subject: [PATCH 40/40] fixed function safety documentation --- crates/sniff-test/src/properties/safety.rs | 2 +- tests/toml/fail_external/sniff-test.toml | 4 ++-- tests/toml/pass_external/sniff-test.toml | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/crates/sniff-test/src/properties/safety.rs b/crates/sniff-test/src/properties/safety.rs index c9e77af..234381f 100644 --- a/crates/sniff-test/src/properties/safety.rs +++ b/crates/sniff-test/src/properties/safety.rs @@ -26,7 +26,7 @@ impl Property for SafetyProperty { } fn fn_def_regex(&self) -> Regex { - Regex::new("(\n|^)(\\s*)[#]+ (Unsafe|UNSAFE)(\n|$)").unwrap() + Regex::new("(\n|^)(\\s*)[#]+ (Safety|SAFETY)(\n|$)").unwrap() } fn callsite_regex(&self) -> Regex { diff --git a/tests/toml/fail_external/sniff-test.toml b/tests/toml/fail_external/sniff-test.toml index 4fd1e1b..212eb9e 100644 --- a/tests/toml/fail_external/sniff-test.toml +++ b/tests/toml/fail_external/sniff-test.toml @@ -1,5 +1,5 @@ ["std::thread::sleep"] requirements = """ -# Unsafe -- non-blocking: Function must not be called in a routine which cannot block. +# Safety +* 'non-blocking': Function must not be called in a routine which cannot block. """ \ No newline at end of file diff --git a/tests/toml/pass_external/sniff-test.toml b/tests/toml/pass_external/sniff-test.toml index 4fd1e1b..212eb9e 100644 --- a/tests/toml/pass_external/sniff-test.toml +++ b/tests/toml/pass_external/sniff-test.toml @@ -1,5 +1,5 @@ ["std::thread::sleep"] requirements = """ -# Unsafe -- non-blocking: Function must not be called in a routine which cannot block. +# Safety +* 'non-blocking': Function must not be called in a routine which cannot block. """ \ No newline at end of file

;Ql#`UlY81F5^?a#^txqW85m(Jf87`f|He3e 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 From 47f214ceac71040389cf936cd6c9a04c272d3cab Mon Sep 17 00:00:00 2001 From: AlexanderPortland Date: Fri, 24 Oct 2025 12:28:23 -0400 Subject: [PATCH 20/40] register sniff-tool within the plugin and ignore dead doc comment warnings --- README.md | 2 +- crates/sniff-test/src/lib.rs | 4 ++ tests/lib.rs | 5 --- tests/unsafe/example_crate/Cargo.lock | 41 +++++++++++++++++++ tests/unsafe/example_crate/Cargo.toml | 9 ++++ tests/unsafe/example_crate/example_crate.snap | 24 +++++++++++ tests/unsafe/example_crate/src/main.rs | 19 +++++++++ .../fail_not_annotated.snap | 13 +----- tests/unsafe/pass_simple/pass_simple.snap | 16 +------- 9 files changed, 100 insertions(+), 33 deletions(-) create mode 100644 tests/unsafe/example_crate/Cargo.lock create mode 100644 tests/unsafe/example_crate/Cargo.toml create mode 100644 tests/unsafe/example_crate/example_crate.snap create mode 100644 tests/unsafe/example_crate/src/main.rs diff --git a/README.md b/README.md index 8e45fa5..e30667c 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ cargo build # in this directory cd [PATH_TO_TEST_CRATE] -cargo clean && RUSTFLAGS="-Zcrate-attr=feature(register_tool) -Zcrate-attr=register_tool(sniff_tool)" [PATH_TO_REPO]/sniff-test/target/debug/cargo-sniff-test +cargo clean && [PATH_TO_REPO]/sniff-test/target/debug/cargo-sniff-test ``` We need the extra `RUSTFLAGS` to register our `sniff_tool` tool to allow for our custom attributes. diff --git a/crates/sniff-test/src/lib.rs b/crates/sniff-test/src/lib.rs index 1eb81c3..556f9e2 100644 --- a/crates/sniff-test/src/lib.rs +++ b/crates/sniff-test/src/lib.rs @@ -78,6 +78,10 @@ impl RustcPlugin for PrintAllItemsPlugin { // Pass Cargo arguments (like --feature) from the top-level CLI to Cargo. fn modify_cargo(&self, cargo: &mut Command, args: &Self::Args) { cargo.args(&args.cargo_args); + + // Register the sniff_tool + let existing = std::env::var("RUSTFLAGS").unwrap_or_default(); + cargo.env("RUSTFLAGS", format!("-Zcrate-attr=feature(register_tool) -Zcrate-attr=register_tool(sniff_tool) -Aunused-doc-comments {existing}")); } // In the driver, we use the Rustc API to start a compiler session diff --git a/tests/lib.rs b/tests/lib.rs index 70c9c95..67fb51a 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -214,11 +214,6 @@ fn cargo_sniff(path: &Path) -> anyhow::Result { println!("path is {:?}", CARGO_SNIFF_TEST_PATH.clone().into_string()); let mut cmd = Command::new(&*CARGO_SNIFF_TEST_PATH); - // register the sniff_tool tool - cmd.env( - "RUSTFLAGS", - "-Zcrate-attr=feature(register_tool) -Zcrate-attr=register_tool(sniff_tool)", - ); cmd.env("CARGO_TERM_COLOR", "never"); cmd.current_dir(path); diff --git a/tests/unsafe/example_crate/Cargo.lock b/tests/unsafe/example_crate/Cargo.lock new file mode 100644 index 0000000..2a4eb2b --- /dev/null +++ b/tests/unsafe/example_crate/Cargo.lock @@ -0,0 +1,41 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "example" +version = "0.1.0" +dependencies = [ + "sniff-test-attrs", +] + +[[package]] +name = "proc-macro2" +version = "1.0.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "sniff-test-attrs" +version = "0.1.0" +dependencies = [ + "quote", +] + +[[package]] +name = "unicode-ident" +version = "1.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" diff --git a/tests/unsafe/example_crate/Cargo.toml b/tests/unsafe/example_crate/Cargo.toml new file mode 100644 index 0000000..133758a --- /dev/null +++ b/tests/unsafe/example_crate/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "example" +version = "0.1.0" +edition = "2024" + +[dependencies] +sniff-test-attrs = { path = "../../../crates/sniff-test-attrs" } + +[workspace] \ No newline at end of file diff --git a/tests/unsafe/example_crate/example_crate.snap b/tests/unsafe/example_crate/example_crate.snap new file mode 100644 index 0000000..89f254e --- /dev/null +++ b/tests/unsafe/example_crate/example_crate.snap @@ -0,0 +1,24 @@ +--- +source: tests/lib.rs +--- +exit_code = 101 +stdout = '' +stderr = ''' +error: function foo directly contains 1 unjustified unsafe axiom, but is not annotated unsafe + --> src/main.rs:1:1 + | +1 | fn foo(ptr: *const i32) -> i32 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: reachable from [main (src/main.rs:14:5) -> bar (src/main.rs:7:5) -> *foo*] +note: raw pointer derefence here + --> src/main.rs:2:23 + | +2 | let a = unsafe { *ptr }; + | ^^^ + = help: this axiom has known requirements: + 1. the dereferenced pointer must be non-null + 2. the dereferenced pointer must be aligned + +error: could not compile `example` (bin "example") due to 1 previous error +''' diff --git a/tests/unsafe/example_crate/src/main.rs b/tests/unsafe/example_crate/src/main.rs new file mode 100644 index 0000000..c807657 --- /dev/null +++ b/tests/unsafe/example_crate/src/main.rs @@ -0,0 +1,19 @@ +fn foo(ptr: *const i32) -> i32 { + let a = unsafe { *ptr }; + a + 2 +} + +fn bar(ptr: *const i32) -> i32 { + foo(ptr) +} + +#[sniff_test_attrs::check_unsafe] +fn main() { + let x = 1; + /// Hello + bar(&raw const x); +} + +// Notes from justus +// - instance safety for some traits +// - when it cant be done alwyas deny and just allow specific instances diff --git a/tests/unsafe/fail_not_annotated/fail_not_annotated.snap b/tests/unsafe/fail_not_annotated/fail_not_annotated.snap index 78a82f9..daf003f 100644 --- a/tests/unsafe/fail_not_annotated/fail_not_annotated.snap +++ b/tests/unsafe/fail_not_annotated/fail_not_annotated.snap @@ -4,17 +4,6 @@ source: tests/lib.rs exit_code = 101 stdout = '' stderr = ''' -warning: unused doc comment - --> src/main.rs:13:5 - | -13 | /// Hello - | ^^^^^^^^^ -14 | bar(&raw const x); - | ----------------- rustdoc does not generate documentation for expressions - | - = help: use `//` for a plain comment - = note: `#[warn(unused_doc_comments)]` on by default - error: function foo directly contains 1 unjustified unsafe axiom, but is not annotated unsafe --> src/main.rs:1:1 | @@ -31,5 +20,5 @@ note: raw pointer derefence here 1. the dereferenced pointer must be non-null 2. the dereferenced pointer must be aligned -error: could not compile `fail_not_annotated` (bin "fail_not_annotated") due to 1 previous error; 1 warning emitted +error: could not compile `fail_not_annotated` (bin "fail_not_annotated") due to 1 previous error ''' diff --git a/tests/unsafe/pass_simple/pass_simple.snap b/tests/unsafe/pass_simple/pass_simple.snap index 7b22e1f..685329e 100644 --- a/tests/unsafe/pass_simple/pass_simple.snap +++ b/tests/unsafe/pass_simple/pass_simple.snap @@ -5,18 +5,4 @@ exit_code = 0 stdout = ''' compilation successful!! ''' -stderr = ''' -warning: unused doc comment - --> src/main.rs:13:9 - | -13 | / /// Safety: -14 | | /// * non-null: a pointer that comes from a reference is trivially non-null -15 | | /// * aligned: a pointer that comes from a reference is trivially aligned - | |_________________________________________________________________________________^ -16 | foo(&raw const x); - | ----------------- rustdoc does not generate documentation for expressions - | - = help: use `//` for a plain comment - = note: `#[warn(unused_doc_comments)]` on by default - -''' +stderr = '' From 8741fff2e7d6fb51729d79b5d7ba32761e57e956 Mon Sep 17 00:00:00 2001 From: Yash Agrawal Date: Thu, 6 Nov 2025 12:50:42 -0500 Subject: [PATCH 21/40] ignore vscode settings --- .gitignore | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 8c049ab..c8ca214 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,6 @@ target review.sh .DS_Store notes.md -.snap.new \ No newline at end of file +.snap.new + +.vscode/ \ No newline at end of file From d05c87ebe09838c80871282ee77439cdb6f13077 Mon Sep 17 00:00:00 2001 From: Yash Agrawal Date: Thu, 6 Nov 2025 15:52:16 -0500 Subject: [PATCH 22/40] reads toml file properly --- Cargo.lock | 73 +++++++++++++++++++++++---- crates/sniff-test/Cargo.toml | 3 +- crates/sniff-test/src/check/mod.rs | 81 +++++++++++++++++++++++++++++- 3 files changed, 145 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4d16cdd..8cb8971 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -191,9 +191,9 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "hashbrown" -version = "0.15.5" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" [[package]] name = "heck" @@ -203,9 +203,9 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "indexmap" -version = "2.11.0" +version = "2.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2481980430f9f78649238835720ddccc57e52df14ffce1c6f37391d61b563e9" +checksum = "6717a8d2a5a929a1a2eb43a12812498ed141a0bcfb7e8f7844fbdbe4303bba9f" dependencies = [ "equivalent", "hashbrown", @@ -446,6 +446,15 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_spanned" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e24345aa0fe688594e73770a5f6d1b216508b4f93484c0026d521acd30134392" +dependencies = [ + "serde_core", +] + [[package]] name = "similar" version = "2.7.0" @@ -471,6 +480,7 @@ dependencies = [ "rustc_utils", "serde", "sniff-test-attrs", + "toml 0.9.8", ] [[package]] @@ -527,11 +537,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd79e69d3b627db300ff956027cc6c3798cef26d22526befdfcd12feeb6d2257" dependencies = [ "serde", - "serde_spanned", - "toml_datetime", + "serde_spanned 0.6.9", + "toml_datetime 0.6.11", "toml_edit", ] +[[package]] +name = "toml" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0dc8b1fb61449e27716ec0e1bdf0f6b8f3e8f6b05391e8497b8b6d7804ea6d8" +dependencies = [ + "indexmap", + "serde_core", + "serde_spanned 1.0.3", + "toml_datetime 0.7.3", + "toml_parser", + "toml_writer", + "winnow 0.7.13", +] + [[package]] name = "toml_datetime" version = "0.6.11" @@ -541,6 +566,15 @@ dependencies = [ "serde", ] +[[package]] +name = "toml_datetime" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2cdb639ebbc97961c51720f858597f7f24c4fc295327923af55b74c3c724533" +dependencies = [ + "serde_core", +] + [[package]] name = "toml_edit" version = "0.19.15" @@ -549,11 +583,26 @@ checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ "indexmap", "serde", - "serde_spanned", - "toml_datetime", - "winnow", + "serde_spanned 0.6.9", + "toml_datetime 0.6.11", + "winnow 0.5.40", +] + +[[package]] +name = "toml_parser" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0cbe268d35bdb4bb5a56a2de88d0ad0eb70af5384a99d648cd4b3d04039800e" +dependencies = [ + "winnow 0.7.13", ] +[[package]] +name = "toml_writer" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df8b2b54733674ad286d16267dcfc7a71ed5c776e4ac7aa3c3e2561f7c637bf2" + [[package]] name = "unicode-ident" version = "1.0.18" @@ -746,3 +795,9 @@ checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" dependencies = [ "memchr", ] + +[[package]] +name = "winnow" +version = "0.7.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf" diff --git a/crates/sniff-test/Cargo.toml b/crates/sniff-test/Cargo.toml index 5044caf..569cee2 100644 --- a/crates/sniff-test/Cargo.toml +++ b/crates/sniff-test/Cargo.toml @@ -16,6 +16,7 @@ serde = { version = "1", features = ["derive"] } regex = "1.11.2" anyhow = "1.0.100" itertools = "0.14.0" +toml = "0.9.8" [build-dependencies] -rustc_plugin = "=0.14.3-nightly-2025-08-20" \ No newline at end of file +rustc_plugin = "=0.14.3-nightly-2025-08-20" diff --git a/crates/sniff-test/src/check/mod.rs b/crates/sniff-test/src/check/mod.rs index 8573e8a..d2b95ab 100644 --- a/crates/sniff-test/src/check/mod.rs +++ b/crates/sniff-test/src/check/mod.rs @@ -13,10 +13,81 @@ use crate::{ mod expr; +fn load_external_requirements( + path: &str, +) -> Result, std::io::Error> { + let text = std::fs::read_to_string(path)?; + let value: toml::Value = toml::from_str(&text).map_err(|e| { + std::io::Error::new( + std::io::ErrorKind::InvalidData, + format!("Failed to parse TOML: {}", e), + ) + })?; + + // Each val should be a table with exactly one key, "requirements" + // Requirement's value should be a string + if let Some(table) = value.as_table() { + let mut reqs = std::collections::HashMap::new(); + for (key, val) in table { + if let Some(inner_table) = val.as_table() { + if inner_table.len() == 1 && inner_table.contains_key("requirements") { + if let Some(req_str) = inner_table["requirements"].as_str() { + reqs.insert(key.clone(), req_str.to_string()); + } else { + return Err(std::io::Error::new( + std::io::ErrorKind::InvalidData, + format!("Expected a string for 'requirements' in key '{}'", key), + )); + } + } else { + return Err(std::io::Error::new( + std::io::ErrorKind::InvalidData, + format!("Expected a single key 'requirements' for key '{}'", key), + )); + } + } else { + return Err(std::io::Error::new( + std::io::ErrorKind::InvalidData, + format!("Expected a table for key '{}'", key), + )); + } + } + Ok(reqs) + } else { + Err(std::io::Error::new( + std::io::ErrorKind::InvalidData, + "Expected a TOML table at the top level", + )) + } +} + /// Checks that all local functions in the crate are properly annotated. pub fn check_properly_annotated(tcx: TyCtxt) -> Result<(), ErrorGuaranteed> { let mut res = Ok(()); + // Parse TOML file into map from fully qualified name to docstring (not yet implemented) + let external_requirements = match load_external_requirements("sniff_test_requirements.toml") { + Ok(map) => { + println!("Loaded external requirements: {:?}", map); + map + } + Err(e) => { + match e.kind() { + std::io::ErrorKind::NotFound => { + // File not found, proceed without external requirements + println!("No external requirements file found, proceeding without it."); + std::collections::HashMap::new() + } + _ => { + // Other errors should be reported + tcx.dcx() + .struct_warn(format!("Failed to load external requirements: {}", e)); + std::collections::HashMap::new() + } + } + } + }; + let entry = reachability::annotated_local_entry_points(tcx).collect::>(); // println!("entry is {entry:?}"); @@ -29,8 +100,14 @@ pub fn check_properly_annotated(tcx: TyCtxt) -> Result<(), ErrorGuaranteed> { for reachable in reachable.iter().cloned() { let axioms = axioms::find_axioms(axioms::SafetyFinder, tcx, &reachable); - // Parse the requirements - let my_requirements = annotations::Requirement::try_parse(tcx, reachable.reach.to_def_id()); + // Parse requirements in code + let code_requirements = + annotations::Requirement::try_parse(tcx, reachable.reach.to_def_id()); + + // Combine all requirements (not yet implemented) + + let my_requirements = code_requirements; + // let find_requirements = |def_id| annotations::Requirement::parse(tcx, def_id); // let find_justifications = |def_id| annotations::Justification::parse(tcx, def_id); From 4c19e3c2294f58596cafdfb684fd5a09e8535f5c Mon Sep 17 00:00:00 2001 From: Yash Agrawal Date: Thu, 6 Nov 2025 16:53:09 -0500 Subject: [PATCH 23/40] attempt to actually use parsed toml --- crates/sniff-test/src/check/mod.rs | 55 ++++++++++++++++++++++++------ 1 file changed, 45 insertions(+), 10 deletions(-) diff --git a/crates/sniff-test/src/check/mod.rs b/crates/sniff-test/src/check/mod.rs index d2b95ab..972e0e0 100644 --- a/crates/sniff-test/src/check/mod.rs +++ b/crates/sniff-test/src/check/mod.rs @@ -2,10 +2,14 @@ use itertools::Itertools; use rustc_errors::{Diag, DiagCtxtHandle}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::ty::TyCtxt; -use rustc_span::{ErrorGuaranteed, source_map::Spanned, sym::todo_macro}; +use rustc_span::{ + DUMMY_SP, ErrorGuaranteed, + source_map::{Spanned, respan}, + sym::todo_macro, +}; use crate::{ - annotations::{self, Annotation, ParsingError, Requirement}, + annotations::{self, Annotation, ParsingError, Requirement, parsing::ParseBulletsFromString}, axioms::{self, Axiom, AxiomFinder, AxiomaticBadness}, reachability::{self, CallsToBad, LocallyReachable}, utils::SniffTestDiagnostic, @@ -61,12 +65,47 @@ fn load_external_requirements( } } +// Note, I don't really get and didn't fully implement the correct error handling for toml fallback. +fn get_requirements<'tcx>( + tcx: TyCtxt<'tcx>, + def_id: DefId, + external_doc_strings: &std::collections::HashMap, +) -> Option>, ParsingError<'tcx>>> { + // First, try to parse from in-code annotations + if let Some(in_code) = annotations::Requirement::try_parse(tcx, def_id) { + return Some(in_code); + } + + // Next, try to parse from external doc strings + let fn_name = tcx.def_path_str(def_id); + if let Some(doc_str) = external_doc_strings.get(&fn_name) { + let parsed = match annotations::Requirement::parse_bullets_from_string(doc_str) { + Ok(reqs) => Ok(reqs + .into_iter() + .map(|(req, range)| respan(DUMMY_SP, req)) + .collect()), + Err(e) => { + tcx.dcx() + .struct_warn(format!( + "Invalid external requirements for `{fn_name}`: {e:?}" + )) + .emit(); + return None; + } + }; + return Some(parsed); + } + + // If neither source yielded requirements, return None + None +} + /// Checks that all local functions in the crate are properly annotated. pub fn check_properly_annotated(tcx: TyCtxt) -> Result<(), ErrorGuaranteed> { let mut res = Ok(()); // Parse TOML file into map from fully qualified name to docstring (not yet implemented) - let external_requirements = match load_external_requirements("sniff_test_requirements.toml") { + let external_doc_strings = match load_external_requirements("sniff_test_requirements.toml") { Ok(map) => { println!("Loaded external requirements: {:?}", map); map @@ -100,13 +139,9 @@ pub fn check_properly_annotated(tcx: TyCtxt) -> Result<(), ErrorGuaranteed> { for reachable in reachable.iter().cloned() { let axioms = axioms::find_axioms(axioms::SafetyFinder, tcx, &reachable); - // Parse requirements in code - let code_requirements = - annotations::Requirement::try_parse(tcx, reachable.reach.to_def_id()); - - // Combine all requirements (not yet implemented) - - let my_requirements = code_requirements; + // Try to parse requirements in code, if not found, try to parse from external doc strings + let my_requirements = + get_requirements(tcx, reachable.reach.to_def_id(), &external_doc_strings); // let find_requirements = |def_id| annotations::Requirement::parse(tcx, def_id); // let find_justifications = |def_id| annotations::Justification::parse(tcx, def_id); From 5899cb4a3277527fb21bfff2d0f60fb39dcec626 Mon Sep 17 00:00:00 2001 From: Yash Agrawal Date: Thu, 6 Nov 2025 17:33:36 -0500 Subject: [PATCH 24/40] toml working? --- crates/sniff-test/src/check/mod.rs | 49 ++++++++++++++++++++---------- 1 file changed, 33 insertions(+), 16 deletions(-) diff --git a/crates/sniff-test/src/check/mod.rs b/crates/sniff-test/src/check/mod.rs index 972e0e0..6da8974 100644 --- a/crates/sniff-test/src/check/mod.rs +++ b/crates/sniff-test/src/check/mod.rs @@ -66,37 +66,54 @@ fn load_external_requirements( } // Note, I don't really get and didn't fully implement the correct error handling for toml fallback. -fn get_requirements<'tcx>( - tcx: TyCtxt<'tcx>, +fn get_requirements( + tcx: TyCtxt, def_id: DefId, external_doc_strings: &std::collections::HashMap, -) -> Option>, ParsingError<'tcx>>> { - // First, try to parse from in-code annotations +) -> Option>> { + // First, try to parse from code annotations if let Some(in_code) = annotations::Requirement::try_parse(tcx, def_id) { - return Some(in_code); + match in_code { + Ok(reqs) => { + println!( + "Parsed requirements from code for {}: {:?}", + tcx.def_path_str(def_id), + reqs + ); + return Some(reqs); + } + Err(e) => { + e.emit(tcx.dcx()); + return None; + } + } } // Next, try to parse from external doc strings let fn_name = tcx.def_path_str(def_id); if let Some(doc_str) = external_doc_strings.get(&fn_name) { - let parsed = match annotations::Requirement::parse_bullets_from_string(doc_str) { - Ok(reqs) => Ok(reqs - .into_iter() - .map(|(req, range)| respan(DUMMY_SP, req)) - .collect()), + match Requirement::parse_bullets_from_string(doc_str) { + Ok(reqs) => { + let spanned_reqs = reqs + .into_iter() + .map(|(req, _)| respan(DUMMY_SP, req)) + .collect(); + println!( + "Parsed requirements from external doc string for {}: {:?}", + fn_name, spanned_reqs + ); + return Some(spanned_reqs); + } Err(e) => { tcx.dcx() - .struct_warn(format!( - "Invalid external requirements for `{fn_name}`: {e:?}" - )) + .struct_warn(format!("Failed to parse external requirements for {fn_name} with doc string {doc_str:?}, error: {e:?}")) .emit(); return None; } - }; - return Some(parsed); + } } - // If neither source yielded requirements, return None + println!("No requirements found for {}", fn_name); None } From 801384b80dac856307ddf515f4c51ac85829cb7a Mon Sep 17 00:00:00 2001 From: Yash Agrawal Date: Thu, 6 Nov 2025 17:37:13 -0500 Subject: [PATCH 25/40] added basic test for toml file --- tests/unsafe/pass_toml/Cargo.lock | 41 +++++++++++++++++++ tests/unsafe/pass_toml/Cargo.toml | 9 ++++ tests/unsafe/pass_toml/pass_simple.snap | 8 ++++ .../pass_toml/sniff_test_requirements.toml | 6 +++ tests/unsafe/pass_toml/src/main.rs | 15 +++++++ 5 files changed, 79 insertions(+) create mode 100644 tests/unsafe/pass_toml/Cargo.lock create mode 100644 tests/unsafe/pass_toml/Cargo.toml create mode 100644 tests/unsafe/pass_toml/pass_simple.snap create mode 100644 tests/unsafe/pass_toml/sniff_test_requirements.toml create mode 100644 tests/unsafe/pass_toml/src/main.rs diff --git a/tests/unsafe/pass_toml/Cargo.lock b/tests/unsafe/pass_toml/Cargo.lock new file mode 100644 index 0000000..9a2d460 --- /dev/null +++ b/tests/unsafe/pass_toml/Cargo.lock @@ -0,0 +1,41 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "invalid_simple" +version = "0.1.0" +dependencies = [ + "sniff-test-attrs", +] + +[[package]] +name = "proc-macro2" +version = "1.0.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "sniff-test-attrs" +version = "0.1.0" +dependencies = [ + "quote", +] + +[[package]] +name = "unicode-ident" +version = "1.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" diff --git a/tests/unsafe/pass_toml/Cargo.toml b/tests/unsafe/pass_toml/Cargo.toml new file mode 100644 index 0000000..6f3b543 --- /dev/null +++ b/tests/unsafe/pass_toml/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "invalid_simple" +version = "0.1.0" +edition = "2024" + +[dependencies] +sniff-test-attrs = { path = "../../../crates/sniff-test-attrs" } + +[workspace] \ No newline at end of file diff --git a/tests/unsafe/pass_toml/pass_simple.snap b/tests/unsafe/pass_toml/pass_simple.snap new file mode 100644 index 0000000..685329e --- /dev/null +++ b/tests/unsafe/pass_toml/pass_simple.snap @@ -0,0 +1,8 @@ +--- +source: tests/lib.rs +--- +exit_code = 0 +stdout = ''' +compilation successful!! +''' +stderr = '' diff --git a/tests/unsafe/pass_toml/sniff_test_requirements.toml b/tests/unsafe/pass_toml/sniff_test_requirements.toml new file mode 100644 index 0000000..c8498ee --- /dev/null +++ b/tests/unsafe/pass_toml/sniff_test_requirements.toml @@ -0,0 +1,6 @@ +["foo"] +requirements = """ +# Unsafe +- non-null: ptr must be non-null +- aligned: ptr must be aligned for an i32 +""" \ No newline at end of file diff --git a/tests/unsafe/pass_toml/src/main.rs b/tests/unsafe/pass_toml/src/main.rs new file mode 100644 index 0000000..b047116 --- /dev/null +++ b/tests/unsafe/pass_toml/src/main.rs @@ -0,0 +1,15 @@ +unsafe fn foo(ptr: *const i32) -> i32 { + unsafe { *ptr } +} + +#[sniff_test_attrs::check_unsafe] +fn main() { + let x = 1; + + unsafe { + /// Safety: + /// * non-null: a pointer that comes from a reference is trivially non-null + /// * aligned: a pointer that comes from a reference is trivially aligned + foo(&raw const x); + } +} From 2ebf569e4dcf86baa3d5a2c3a1c6b15bdd57076d Mon Sep 17 00:00:00 2001 From: AlexanderPortland Date: Fri, 7 Nov 2025 12:21:40 -0500 Subject: [PATCH 26/40] logging improvements --- .gitignore | 2 +- Cargo.lock | 58 ++++++++++++++++++- crates/sniff-test/Cargo.toml | 5 +- crates/sniff-test/src/axioms/safety.rs | 1 - crates/sniff-test/src/bin/cargo-sniff-test.rs | 2 +- .../sniff-test/src/bin/sniff-test-driver.rs | 2 +- crates/sniff-test/src/check/mod.rs | 11 +++- crates/sniff-test/src/lib.rs | 55 +++++++++++++++++- tests/unsafe/example_crate/src/main.rs | 14 +++++ 9 files changed, 139 insertions(+), 11 deletions(-) diff --git a/.gitignore b/.gitignore index 8c049ab..5de80f9 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,4 @@ target review.sh .DS_Store notes.md -.snap.new \ No newline at end of file +*.snap.new \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 4d16cdd..217888d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -174,12 +174,26 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" +[[package]] +name = "env_filter" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bf3c259d255ca70051b30e2e95b5446cdb8949ac4cd22c0d7fd634d89f568e2" +dependencies = [ + "log", + "regex", +] + [[package]] name = "env_logger" -version = "0.10.2" +version = "0.11.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cd405aab171cb85d6735e5c8d9db038c17d3ca007a4d2c25f337935c3d90580" +checksum = "13c863f0904021b108aa8b2f55046443e6b1ebde8fd4a15c399893aae4fa069f" dependencies = [ + "anstream", + "anstyle", + "env_filter", + "jiff", "log", ] @@ -255,6 +269,30 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" +[[package]] +name = "jiff" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be1f93b8b1eb69c77f24bbb0afdf66f54b632ee39af40ca21c4365a1d7347e49" +dependencies = [ + "jiff-static", + "log", + "portable-atomic", + "portable-atomic-util", + "serde", +] + +[[package]] +name = "jiff-static" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03343451ff899767262ec32146f6d559dd759fdadf42ff0e227c7c48f72594b4" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "lazy_static" version = "1.5.0" @@ -291,6 +329,21 @@ version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" +[[package]] +name = "portable-atomic" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" + +[[package]] +name = "portable-atomic-util" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507" +dependencies = [ + "portable-atomic", +] + [[package]] name = "proc-macro2" version = "1.0.101" @@ -466,6 +519,7 @@ dependencies = [ "clap", "env_logger", "itertools", + "log", "regex", "rustc_plugin", "rustc_utils", diff --git a/crates/sniff-test/Cargo.toml b/crates/sniff-test/Cargo.toml index 5044caf..dfe9a24 100644 --- a/crates/sniff-test/Cargo.toml +++ b/crates/sniff-test/Cargo.toml @@ -10,12 +10,13 @@ rustc_private = true rustc_plugin = "=0.14.3-nightly-2025-08-20" rustc_utils = "=0.14.3-nightly-2025-08-20" sniff-test-attrs ={ path = "../sniff-test-attrs" } -env_logger = { version = "0.10", default-features = false } +env_logger = "0.11" clap = { version = "4.4", features = ["derive"] } serde = { version = "1", features = ["derive"] } regex = "1.11.2" anyhow = "1.0.100" itertools = "0.14.0" +log = "0.4.28" [build-dependencies] -rustc_plugin = "=0.14.3-nightly-2025-08-20" \ No newline at end of file +rustc_plugin = "=0.14.3-nightly-2025-08-20" diff --git a/crates/sniff-test/src/axioms/safety.rs b/crates/sniff-test/src/axioms/safety.rs index 8bdcf62..5b61072 100644 --- a/crates/sniff-test/src/axioms/safety.rs +++ b/crates/sniff-test/src/axioms/safety.rs @@ -56,7 +56,6 @@ impl AxiomFinder for SafetyFinder { tyck: &rustc_middle::ty::TypeckResults, expr: &rustc_hir::Expr, ) -> Vec> { - // println!("looking at {}", expr.to_debug_str(_tcx)); if let ExprKind::Unary(UnOp::Deref, expr) = expr.kind { let inner_ty = tyck.expr_ty(expr); diff --git a/crates/sniff-test/src/bin/cargo-sniff-test.rs b/crates/sniff-test/src/bin/cargo-sniff-test.rs index 24fc500..8c011d3 100644 --- a/crates/sniff-test/src/bin/cargo-sniff-test.rs +++ b/crates/sniff-test/src/bin/cargo-sniff-test.rs @@ -1,6 +1,6 @@ #![feature(rustc_private)] fn main() { - env_logger::init(); + sniff_test::env_logger_init(false); rustc_plugin::cli_main(sniff_test::PrintAllItemsPlugin); } diff --git a/crates/sniff-test/src/bin/sniff-test-driver.rs b/crates/sniff-test/src/bin/sniff-test-driver.rs index a211d39..981d8c8 100644 --- a/crates/sniff-test/src/bin/sniff-test-driver.rs +++ b/crates/sniff-test/src/bin/sniff-test-driver.rs @@ -1,6 +1,6 @@ #![feature(rustc_private)] fn main() { - env_logger::init(); + sniff_test::env_logger_init(true); rustc_plugin::driver_main(sniff_test::PrintAllItemsPlugin); } diff --git a/crates/sniff-test/src/check/mod.rs b/crates/sniff-test/src/check/mod.rs index 8573e8a..607196c 100644 --- a/crates/sniff-test/src/check/mod.rs +++ b/crates/sniff-test/src/check/mod.rs @@ -19,11 +19,18 @@ pub fn check_properly_annotated(tcx: TyCtxt) -> Result<(), ErrorGuaranteed> { let entry = reachability::annotated_local_entry_points(tcx).collect::>(); - // println!("entry is {entry:?}"); + let entries = entry + .iter() + .map(|local| { + let span = tcx.optimized_mir(local.to_def_id()).span; + (local, span) + }) + .collect::>(); + log::debug!("entry is {entries:#?}"); let reachable = reachability::locally_reachable_from(tcx, entry).collect::>(); - // println!("reachable is {reachable:?}"); + log::debug!("reachable is {reachable:#?}"); // For all reachable local function definitions, ensure their axioms align with their annotations. for reachable in reachable.iter().cloned() { diff --git a/crates/sniff-test/src/lib.rs b/crates/sniff-test/src/lib.rs index 556f9e2..e0e4091 100644 --- a/crates/sniff-test/src/lib.rs +++ b/crates/sniff-test/src/lib.rs @@ -34,6 +34,7 @@ pub mod utils; use std::{borrow::Cow, env, process::Command}; use clap::Parser; +use rustc_hir::def_id::LOCAL_CRATE; use rustc_middle::ty::TyCtxt; use rustc_plugin::{CrateFilter, RustcPlugin, RustcPluginArgs, Utf8Path}; use serde::{Deserialize, Serialize}; @@ -51,10 +52,52 @@ pub struct SniffTestArgs { #[arg(short, long)] allcaps: bool, + #[arg(short, long)] + release: bool, + #[clap(last = true)] cargo_args: Vec, } +const TO_FILE: bool = false; + +fn env_logger_init_file(driver: bool) { + use std::fs::OpenOptions; + use std::io::Write; + + let mut log_file_opts = OpenOptions::new(); + log_file_opts.write(true); + + if driver { + log_file_opts.append(true); + } else { + log_file_opts.create(true).truncate(true); + } + + let log_file = log_file_opts + .open("sniff-test.log") + .expect("Failed to open log file"); + + env_logger::Builder::from_default_env() + .format_timestamp(None) + .target(env_logger::Target::Pipe(Box::new(log_file))) + .init() +} + +fn env_logger_init_terminal() { + env_logger::Builder::from_default_env() + .format_timestamp(None) + .init() +} + +pub fn env_logger_init(driver: bool) { + if TO_FILE { + env_logger_init_file(driver); + } else { + env_logger_init_terminal(); + } +} + impl RustcPlugin for PrintAllItemsPlugin { type Args = SniffTestArgs; @@ -79,6 +122,13 @@ impl RustcPlugin for PrintAllItemsPlugin { fn modify_cargo(&self, cargo: &mut Command, args: &Self::Args) { cargo.args(&args.cargo_args); + if args.release { + panic!( + "release can inline some functions, so not sure if we want to allow this yet..." + ); + cargo.args(["--release"]); + } + // Register the sniff_tool let existing = std::env::var("RUSTFLAGS").unwrap_or_default(); cargo.env("RUSTFLAGS", format!("-Zcrate-attr=feature(register_tool) -Zcrate-attr=register_tool(sniff_tool) -Aunused-doc-comments {existing}")); @@ -114,11 +164,14 @@ impl rustc_driver::Callbacks for PrintAllItemsCallbacks { _compiler: &rustc_interface::interface::Compiler, tcx: TyCtxt<'_>, ) -> rustc_driver::Compilation { + let crate_name = tcx.crate_name(LOCAL_CRATE); + + log::debug!("checking crate {crate_name}"); let Ok(()) = check_properly_annotated(tcx) else { return rustc_driver::Compilation::Stop; }; - println!("compilation successful!!"); + println!("compilation of {crate_name} was successful!!"); // Note that you should generally allow compilation to continue. If // your plugin is being invoked on a dependency, then you need to ensure diff --git a/tests/unsafe/example_crate/src/main.rs b/tests/unsafe/example_crate/src/main.rs index c807657..1cf6142 100644 --- a/tests/unsafe/example_crate/src/main.rs +++ b/tests/unsafe/example_crate/src/main.rs @@ -1,19 +1,33 @@ +// /// # Unsafe +// /// - non-null: ptr must be non-null fn foo(ptr: *const i32) -> i32 { let a = unsafe { *ptr }; a + 2 } +fn baz(ptr: *const i32) -> i32 { + unsafe { *ptr } +} + fn bar(ptr: *const i32) -> i32 { + /// SAFETY: + /// - non-null: i checked to make sure this is nn + // if !ptr.is_null() { foo(ptr) + // baz(ptr) + // } } #[sniff_test_attrs::check_unsafe] fn main() { + let a = Some(3).unwrap(); let x = 1; /// Hello bar(&raw const x); } +// - bug to put safety comments on calls to fn without obligations + // Notes from justus // - instance safety for some traits // - when it cant be done alwyas deny and just allow specific instances From c66b82d5e2aeb92593d39f0a13dbc40caa8ae273 Mon Sep 17 00:00:00 2001 From: Yash Agrawal Date: Mon, 10 Nov 2025 12:43:18 -0500 Subject: [PATCH 27/40] added toml module --- crates/sniff-test/src/annotations/mod.rs | 1 + crates/sniff-test/src/annotations/toml.rs | 109 ++++++++++++++++++++++ 2 files changed, 110 insertions(+) create mode 100644 crates/sniff-test/src/annotations/toml.rs diff --git a/crates/sniff-test/src/annotations/mod.rs b/crates/sniff-test/src/annotations/mod.rs index eb31a08..7250202 100644 --- a/crates/sniff-test/src/annotations/mod.rs +++ b/crates/sniff-test/src/annotations/mod.rs @@ -10,6 +10,7 @@ mod attr; pub mod check; mod err; pub mod parsing; +pub mod toml; mod types; pub use err::ParsingError; diff --git a/crates/sniff-test/src/annotations/toml.rs b/crates/sniff-test/src/annotations/toml.rs new file mode 100644 index 0000000..4005b86 --- /dev/null +++ b/crates/sniff-test/src/annotations/toml.rs @@ -0,0 +1,109 @@ +use std::collections::HashMap; + +use rustc_span::{ + DUMMY_SP, + source_map::{Spanned, respan}, +}; + +use crate::annotations::{ParsingIssue, Requirement, parsing::ParseBulletsFromString}; + +/// Struct encapsulating annotations parsed from a TOML file. +#[derive(Default)] +pub struct TomlAnnotation { + function_to_requirements: HashMap>>, +} + +// Errors that can occur when parsing TOML annotations. +#[derive(Debug)] +pub enum TomlParseError { + Io(std::io::Error), + Toml(toml::de::Error), + Schema(String), + Parse(ParsingIssue), +} + +impl From for TomlParseError { + fn from(err: std::io::Error) -> Self { + TomlParseError::Io(err) + } +} + +impl From for TomlParseError { + fn from(err: toml::de::Error) -> Self { + TomlParseError::Toml(err) + } +} + +impl From for TomlParseError { + fn from(err: ParsingIssue) -> Self { + TomlParseError::Parse(err) + } +} + +impl TomlAnnotation { + pub fn from_file>(path: P) -> Result { + // Get the contents of the TOML file + let text = std::fs::read_to_string(path)?; + let value: toml::Value = toml::from_str(&text)?; + + // Parse the TOML file into a map from function names to requirement strings + // The expected schema is: + // [function_name] + // requirements = """ + // - Requirement 1 + // - Requirement 2 + // """ + let Some(table) = value.as_table() else { + return Err(TomlParseError::Schema( + "Expected a TOML table at the top level".to_string(), + )); + }; + let mut function_to_requirements: HashMap>> = + HashMap::new(); + + for (function_name, value) in table { + let Some(inner_table) = value.as_table() else { + return Err(TomlParseError::Schema(format!( + "Expected a TOML table for function {function_name}" + ))); + }; + + if inner_table.len() != 1 || !inner_table.contains_key("requirements") { + return Err(TomlParseError::Schema(format!( + "Expected a single 'requirements' entry for function {function_name}" + ))); + } + + let Some(requirements_string) = inner_table["requirements"].as_str() else { + return Err(TomlParseError::Schema(format!( + "Expected a 'requirements' string for function {function_name}" + ))); + }; + + match Requirement::parse_bullets_from_string(requirements_string) { + Ok(requirements) => { + let spanned_requirements: Vec> = requirements + .into_iter() + .map(|(req, _range)| respan(DUMMY_SP, req)) + .collect(); + function_to_requirements.insert(function_name.clone(), spanned_requirements); + } + Err(parse_error) => { + return Err(TomlParseError::Parse(parse_error)); + } + } + } + + // Return the parsed annotations + Ok(TomlAnnotation { + function_to_requirements, + }) + } + + pub fn get_requirements_for_function( + &self, + function_name: &str, + ) -> Option<&Vec>> { + self.function_to_requirements.get(function_name) + } +} From 44846e18b7f7f51283c97d93467d06fc543419e3 Mon Sep 17 00:00:00 2001 From: Yash Agrawal Date: Mon, 10 Nov 2025 14:29:50 -0500 Subject: [PATCH 28/40] updated toml module and integrated with plugin --- crates/sniff-test/src/annotations/toml.rs | 15 ++- crates/sniff-test/src/annotations/types.rs | 2 +- crates/sniff-test/src/check/mod.rs | 111 +++--------------- .../pass_toml => toml/pass_local}/Cargo.lock | 0 .../pass_toml => toml/pass_local}/Cargo.toml | 0 .../pass_local}/pass_simple.snap | 0 .../pass_local/sniff-test.toml} | 0 .../pass_toml => toml/pass_local}/src/main.rs | 0 8 files changed, 32 insertions(+), 96 deletions(-) rename tests/{unsafe/pass_toml => toml/pass_local}/Cargo.lock (100%) rename tests/{unsafe/pass_toml => toml/pass_local}/Cargo.toml (100%) rename tests/{unsafe/pass_toml => toml/pass_local}/pass_simple.snap (100%) rename tests/{unsafe/pass_toml/sniff_test_requirements.toml => toml/pass_local/sniff-test.toml} (100%) rename tests/{unsafe/pass_toml => toml/pass_local}/src/main.rs (100%) diff --git a/crates/sniff-test/src/annotations/toml.rs b/crates/sniff-test/src/annotations/toml.rs index 4005b86..4dee514 100644 --- a/crates/sniff-test/src/annotations/toml.rs +++ b/crates/sniff-test/src/annotations/toml.rs @@ -41,10 +41,19 @@ impl From for TomlParseError { } impl TomlAnnotation { + /// Parses a TOML annotation file and returns a TomlAnnotation struct. + /// Fails on any errors, never returning partial results. + /// If the file does not exist, returns an empty TomlAnnotation. pub fn from_file>(path: P) -> Result { // Get the contents of the TOML file - let text = std::fs::read_to_string(path)?; - let value: toml::Value = toml::from_str(&text)?; + let text = match std::fs::read_to_string(path) { + Ok(t) => t, + Err(e) if e.kind() == std::io::ErrorKind::NotFound => { + println!("TOML annotation file not found, proceeding without it."); + return Ok(TomlAnnotation::default()); + } + Err(e) => return Err(TomlParseError::Io(e)), + }; // Parse the TOML file into a map from function names to requirement strings // The expected schema is: @@ -53,6 +62,7 @@ impl TomlAnnotation { // - Requirement 1 // - Requirement 2 // """ + let value: toml::Value = toml::from_str(&text)?; let Some(table) = value.as_table() else { return Err(TomlParseError::Schema( "Expected a TOML table at the top level".to_string(), @@ -60,7 +70,6 @@ impl TomlAnnotation { }; let mut function_to_requirements: HashMap>> = HashMap::new(); - for (function_name, value) in table { let Some(inner_table) = value.as_table() else { return Err(TomlParseError::Schema(format!( diff --git a/crates/sniff-test/src/annotations/types.rs b/crates/sniff-test/src/annotations/types.rs index dd646b3..2eda537 100644 --- a/crates/sniff-test/src/annotations/types.rs +++ b/crates/sniff-test/src/annotations/types.rs @@ -4,7 +4,7 @@ use std::borrow::Borrow; use serde::{Deserialize, Serialize}; -#[derive(PartialEq, Eq, Debug, Serialize, Deserialize)] +#[derive(PartialEq, Eq, Debug, Serialize, Deserialize, Clone)] /// A condition that must hold such that a given function call will not cause UB. pub struct Requirement { name: ConditionName, diff --git a/crates/sniff-test/src/check/mod.rs b/crates/sniff-test/src/check/mod.rs index 6da8974..f5d02aa 100644 --- a/crates/sniff-test/src/check/mod.rs +++ b/crates/sniff-test/src/check/mod.rs @@ -9,7 +9,11 @@ use rustc_span::{ }; use crate::{ - annotations::{self, Annotation, ParsingError, Requirement, parsing::ParseBulletsFromString}, + annotations::{ + self, Annotation, ParsingError, Requirement, + parsing::ParseBulletsFromString, + toml::{TomlAnnotation, TomlParseError}, + }, axioms::{self, Axiom, AxiomFinder, AxiomaticBadness}, reachability::{self, CallsToBad, LocallyReachable}, utils::SniffTestDiagnostic, @@ -17,59 +21,11 @@ use crate::{ mod expr; -fn load_external_requirements( - path: &str, -) -> Result, std::io::Error> { - let text = std::fs::read_to_string(path)?; - let value: toml::Value = toml::from_str(&text).map_err(|e| { - std::io::Error::new( - std::io::ErrorKind::InvalidData, - format!("Failed to parse TOML: {}", e), - ) - })?; - - // Each val should be a table with exactly one key, "requirements" - // Requirement's value should be a string - if let Some(table) = value.as_table() { - let mut reqs = std::collections::HashMap::new(); - for (key, val) in table { - if let Some(inner_table) = val.as_table() { - if inner_table.len() == 1 && inner_table.contains_key("requirements") { - if let Some(req_str) = inner_table["requirements"].as_str() { - reqs.insert(key.clone(), req_str.to_string()); - } else { - return Err(std::io::Error::new( - std::io::ErrorKind::InvalidData, - format!("Expected a string for 'requirements' in key '{}'", key), - )); - } - } else { - return Err(std::io::Error::new( - std::io::ErrorKind::InvalidData, - format!("Expected a single key 'requirements' for key '{}'", key), - )); - } - } else { - return Err(std::io::Error::new( - std::io::ErrorKind::InvalidData, - format!("Expected a table for key '{}'", key), - )); - } - } - Ok(reqs) - } else { - Err(std::io::Error::new( - std::io::ErrorKind::InvalidData, - "Expected a TOML table at the top level", - )) - } -} - // Note, I don't really get and didn't fully implement the correct error handling for toml fallback. fn get_requirements( tcx: TyCtxt, def_id: DefId, - external_doc_strings: &std::collections::HashMap, + toml_annotations: &TomlAnnotation, ) -> Option>> { // First, try to parse from code annotations if let Some(in_code) = annotations::Requirement::try_parse(tcx, def_id) { @@ -91,29 +47,10 @@ fn get_requirements( // Next, try to parse from external doc strings let fn_name = tcx.def_path_str(def_id); - if let Some(doc_str) = external_doc_strings.get(&fn_name) { - match Requirement::parse_bullets_from_string(doc_str) { - Ok(reqs) => { - let spanned_reqs = reqs - .into_iter() - .map(|(req, _)| respan(DUMMY_SP, req)) - .collect(); - println!( - "Parsed requirements from external doc string for {}: {:?}", - fn_name, spanned_reqs - ); - return Some(spanned_reqs); - } - Err(e) => { - tcx.dcx() - .struct_warn(format!("Failed to parse external requirements for {fn_name} with doc string {doc_str:?}, error: {e:?}")) - .emit(); - return None; - } - } + if let Some(reqs) = toml_annotations.get_requirements_for_function(&fn_name) { + return Some(reqs.clone()); } - println!("No requirements found for {}", fn_name); None } @@ -121,26 +58,17 @@ fn get_requirements( pub fn check_properly_annotated(tcx: TyCtxt) -> Result<(), ErrorGuaranteed> { let mut res = Ok(()); - // Parse TOML file into map from fully qualified name to docstring (not yet implemented) - let external_doc_strings = match load_external_requirements("sniff_test_requirements.toml") { - Ok(map) => { - println!("Loaded external requirements: {:?}", map); - map - } + // Parse TOML annotations from file + let toml_path = "sniff-test.toml"; + let toml_annotations = match TomlAnnotation::from_file(toml_path) { + Ok(annotations) => annotations, Err(e) => { - match e.kind() { - std::io::ErrorKind::NotFound => { - // File not found, proceed without external requirements - println!("No external requirements file found, proceeding without it."); - std::collections::HashMap::new() - } - _ => { - // Other errors should be reported - tcx.dcx() - .struct_warn(format!("Failed to load external requirements: {}", e)); - std::collections::HashMap::new() - } - } + tcx.dcx() + .struct_warn(format!( + "Failed to parse TOML annotations from {toml_path}: {e:?}" + )) + .emit(); + TomlAnnotation::default() } }; @@ -157,8 +85,7 @@ pub fn check_properly_annotated(tcx: TyCtxt) -> Result<(), ErrorGuaranteed> { let axioms = axioms::find_axioms(axioms::SafetyFinder, tcx, &reachable); // Try to parse requirements in code, if not found, try to parse from external doc strings - let my_requirements = - get_requirements(tcx, reachable.reach.to_def_id(), &external_doc_strings); + let my_requirements = get_requirements(tcx, reachable.reach.to_def_id(), &toml_annotations); // let find_requirements = |def_id| annotations::Requirement::parse(tcx, def_id); // let find_justifications = |def_id| annotations::Justification::parse(tcx, def_id); diff --git a/tests/unsafe/pass_toml/Cargo.lock b/tests/toml/pass_local/Cargo.lock similarity index 100% rename from tests/unsafe/pass_toml/Cargo.lock rename to tests/toml/pass_local/Cargo.lock diff --git a/tests/unsafe/pass_toml/Cargo.toml b/tests/toml/pass_local/Cargo.toml similarity index 100% rename from tests/unsafe/pass_toml/Cargo.toml rename to tests/toml/pass_local/Cargo.toml diff --git a/tests/unsafe/pass_toml/pass_simple.snap b/tests/toml/pass_local/pass_simple.snap similarity index 100% rename from tests/unsafe/pass_toml/pass_simple.snap rename to tests/toml/pass_local/pass_simple.snap diff --git a/tests/unsafe/pass_toml/sniff_test_requirements.toml b/tests/toml/pass_local/sniff-test.toml similarity index 100% rename from tests/unsafe/pass_toml/sniff_test_requirements.toml rename to tests/toml/pass_local/sniff-test.toml diff --git a/tests/unsafe/pass_toml/src/main.rs b/tests/toml/pass_local/src/main.rs similarity index 100% rename from tests/unsafe/pass_toml/src/main.rs rename to tests/toml/pass_local/src/main.rs From 913c37e8d569970f43b111d4f14906bae149cac0 Mon Sep 17 00:00:00 2001 From: AlexanderPortland Date: Mon, 10 Nov 2025 23:31:06 -0500 Subject: [PATCH 29/40] reworked and simplified parsing --- crates/sniff-test-attrs/src/lib.rs | 24 ++ crates/sniff-test/src/annotations/attr.rs | 52 --- crates/sniff-test/src/annotations/doc.rs | 67 ++++ crates/sniff-test/src/annotations/mod.rs | 188 ++++++++--- crates/sniff-test/src/annotations/parsing.rs | 2 +- crates/sniff-test/src/annotations/span.rs | 112 +++++++ crates/sniff-test/src/check/expr.rs | 12 - crates/sniff-test/src/check/mod.rs | 313 +++++++++--------- crates/sniff-test/src/lib.rs | 12 +- .../src/{axioms => properties}/mod.rs | 66 ++-- .../src/{axioms => properties}/panic.rs | 54 +-- .../src/{axioms => properties}/safety.rs | 82 +++-- crates/sniff-test/src/reachability/bad.rs | 113 ++----- crates/sniff-test/src/reachability/entry.rs | 24 +- crates/sniff-test/src/reachability/err.rs | 20 +- crates/sniff-test/src/reachability/mod.rs | 4 +- tests/unsafe/example_crate/src/main.rs | 17 +- 17 files changed, 697 insertions(+), 465 deletions(-) delete mode 100644 crates/sniff-test/src/annotations/attr.rs create mode 100644 crates/sniff-test/src/annotations/doc.rs create mode 100644 crates/sniff-test/src/annotations/span.rs rename crates/sniff-test/src/{axioms => properties}/mod.rs (53%) rename crates/sniff-test/src/{axioms => properties}/panic.rs (69%) rename crates/sniff-test/src/{axioms => properties}/safety.rs (52%) diff --git a/crates/sniff-test-attrs/src/lib.rs b/crates/sniff-test-attrs/src/lib.rs index 95e1f2c..dc59a0e 100644 --- a/crates/sniff-test-attrs/src/lib.rs +++ b/crates/sniff-test-attrs/src/lib.rs @@ -21,9 +21,33 @@ macro_rules! define_sniff_tool_annotation { } t.extend(item); + // panic!("{t}"); t } }; } define_sniff_tool_annotation!(check_unsafe); + +// #[proc_macro_attribute] +// pub fn test(_attr: TokenStream, item: TokenStream) -> TokenStream { +// let mut t = TokenStream::new(); + +// for i in item { + +// } + +// // If we're registering the sniff-test tool, add the actual attribute to check unsafe. +// let rustflags = std::env::var("RUSTFLAGS") +// .map(|rust_flags| rust_flags.contains("-Zcrate-attr=register_tool(sniff_tool)")) +// .unwrap_or(false); +// if rustflags || std::env::var("PLUGIN_ARGS").is_ok() { +// t.extend(TokenStream::from(quote!( +// #![sniff_tool::check_unsafe] +// ))); +// } + +// t.extend(item); +// panic!("{t}"); +// t +// } diff --git a/crates/sniff-test/src/annotations/attr.rs b/crates/sniff-test/src/annotations/attr.rs deleted file mode 100644 index 14fd383..0000000 --- a/crates/sniff-test/src/annotations/attr.rs +++ /dev/null @@ -1,52 +0,0 @@ -//! Utilities for getting attributes from relevant pieces of a program. - -use crate::annotations::{ParsingError, err::ParsingIssue}; -use rustc_middle::ty::TyCtxt; - -impl Attributeable for rustc_span::def_id::DefId { - fn get_attrs<'tcx>(&self, tcx: TyCtxt<'tcx>) -> &'tcx [rustc_hir::Attribute] { - tcx.get_all_attrs(*self) - } - - fn convert_err<'tcx>(&self, tcx: TyCtxt<'tcx>) -> impl Fn(ParsingIssue) -> ParsingError<'tcx> { - move |issue| issue.at_fn_def(*self, tcx) - } -} - -impl Attributeable for rustc_hir::Expr<'_> { - fn get_attrs<'tcx>(&self, tcx: TyCtxt<'tcx>) -> &'tcx [rustc_hir::Attribute] { - tcx.hir_attrs(self.hir_id) - } - - fn convert_err<'tcx>(&self, tcx: TyCtxt<'tcx>) -> impl Fn(ParsingIssue) -> ParsingError<'tcx> { - move |issue| issue.at_callsite(self, self.hir_id.owner.to_def_id(), tcx) - } -} - -/// A trait for items from which you can get a list of HIR attributes from the typing context. -pub trait Attributeable { - /// Get the HIR attributes for this item. - fn get_attrs<'tcx>(&self, tcx: TyCtxt<'tcx>) -> &'tcx [rustc_hir::Attribute]; - - /// Returns a function that can be used to add additional context to [`ParsingIssue`]s, - /// turning them into full [`ParsingError`]s that can be rendered to the user. - fn convert_err<'tcx>(&self, tcx: TyCtxt<'tcx>) -> impl Fn(ParsingIssue) -> ParsingError<'tcx>; - - /// Get the full string of all doc attributes on n item concatenated together. - fn get_doc_str(&self, tcx: TyCtxt<'_>) -> Option { - let all_attrs = self.get_attrs(tcx); - - // Filter for doc comments. - let doc_comments = all_attrs - .iter() - .filter_map(|attr| attr.doc_str().map(|a| a.as_str().to_owned())) - .collect::>(); - - // Return none if no doc comments were found - if doc_comments.is_empty() { - None - } else { - Some(doc_comments.join("\n")) - } - } -} diff --git a/crates/sniff-test/src/annotations/doc.rs b/crates/sniff-test/src/annotations/doc.rs new file mode 100644 index 0000000..380b880 --- /dev/null +++ b/crates/sniff-test/src/annotations/doc.rs @@ -0,0 +1,67 @@ +//! Utilities for getting attributes from relevant pieces of a program. + +use std::ops::Range; + +use super::span::Mergeable; +use rustc_hir::Attribute; +use rustc_middle::ty::TyCtxt; +use rustc_span::Span; + +#[derive(Debug)] +pub struct DocStr<'tcx>(String, &'tcx [Attribute]); + +impl DocStr<'_> { + pub fn str(&self) -> &str { + &self.0 + } + + pub fn span_of_chars(&self, chars: Range) -> Span { + super::span::span_some_comments(self.1, chars) + .merge_adjacent() + .into_iter() + .next() + .expect("should have a span") + } +} + +/// Get the full string of all doc attributes on n item concatenated together. +pub fn get_doc_str(item: T, tcx: TyCtxt) -> Option { + let all_attrs = item.get_attrs(tcx); + + // Filter for doc comments. + let doc_comments = all_attrs + .iter() + .filter_map(|attr| attr.doc_str().map(|a| a.as_str().to_owned())) + .collect::>(); + + // Return none if no doc comments were found + if doc_comments.is_empty() { + None + } else { + Some(DocStr(doc_comments.join("\n"), all_attrs)) + } +} + +/// A trait for items from which you can get a list of HIR attributes from the typing context. +pub trait Attributeable { + /// Get the HIR attributes for this item. + fn get_attrs<'tcx>(&self, tcx: TyCtxt<'tcx>) -> &'tcx [rustc_hir::Attribute]; +} + +impl Attributeable for rustc_span::def_id::DefId { + fn get_attrs<'tcx>(&self, tcx: TyCtxt<'tcx>) -> &'tcx [rustc_hir::Attribute] { + tcx.get_all_attrs(*self) + } +} + +impl Attributeable for rustc_hir::Expr<'_> { + fn get_attrs<'tcx>(&self, tcx: TyCtxt<'tcx>) -> &'tcx [rustc_hir::Attribute] { + tcx.hir_attrs(self.hir_id) + } +} + +impl Attributeable for rustc_hir::Block<'_> { + fn get_attrs<'tcx>(&self, tcx: TyCtxt<'tcx>) -> &'tcx [rustc_hir::Attribute] { + tcx.hir_attrs(tcx.parent_hir_id(self.hir_id)) + } +} diff --git a/crates/sniff-test/src/annotations/mod.rs b/crates/sniff-test/src/annotations/mod.rs index eb31a08..844c7b7 100644 --- a/crates/sniff-test/src/annotations/mod.rs +++ b/crates/sniff-test/src/annotations/mod.rs @@ -1,70 +1,150 @@ //! The utilities needed to find and parse code annotations. - -use crate::annotations::{attr::Attributeable, err::ParsingIssue}; -use parsing::ParseBulletsFromString; +use crate::{ + annotations::doc::{Attributeable, DocStr, get_doc_str}, + properties::Property, +}; +// use parsing::ParseBulletsFromString; +use regex::Regex; +use rustc_ast::Item; use rustc_middle::ty::TyCtxt; -use rustc_span::source_map::{Spanned, respan}; -use std::borrow::Borrow; - -mod attr; -pub mod check; -mod err; -pub mod parsing; -mod types; +use rustc_span::{ + Span, + source_map::{Spanned, respan}, +}; +use std::{ + any::Any, + ops::{FromResidual, Try}, +}; +use std::{any::TypeId, borrow::Borrow, collections::HashMap, fmt::Debug, hash::Hash}; -pub use err::ParsingError; -pub use types::{Justification, Requirement}; +mod doc; +mod span; +// pub mod check; +// mod err; +// pub mod parsing; +// mod types; -impl Annotation<'static> for Requirement { - type Input = rustc_span::def_id::DefId; +#[derive(Debug)] +pub enum PropertyViolation { + /// This property will always be violated. + Unconditional, + // ConditionallyBad(Vec>), + /// This property will never be violated. + Never, } -impl<'a> Annotation<'a> for Justification { - type Input = rustc_hir::Expr<'a>; +#[derive(Debug)] +pub enum AnnotationSource { + DocComment, + TomlOverride, } -/// A type that can be parsed from a given [`Input`](Annotation::Input) within the [`TyCtxt`]. -pub trait Annotation<'a>: ParseBulletsFromString { - type Input: Attributeable; +#[derive(Debug)] +pub struct DefAnnotation { + /// The name of the property this obligation refers to. + pub property_name: &'static str, + /// The user's annotation for whether the given property is violated locally within this function. + pub local_violation_annotation: PropertyViolation, + /// Where this obligation has come from. + pub source: AnnotationSource, - /// Parse the given [`Input`](Annotation::Input). - #[allow(clippy::missing_errors_doc)] - fn parse( - tcx: TyCtxt, - input: impl Borrow, - ) -> Result>, ParsingError> { - let input: &Self::Input = input.borrow(); - let attrs = input.get_attrs(tcx); - let doc_str: Result = - input.get_doc_str(tcx).ok_or(ParsingIssue::NoDocString); + pub span: Span, +} - // println!("doc string is {doc_str:?}"); +#[derive(Debug)] +pub struct ExpressionAnnotation { + pub property_name: &'static str, + pub text: String, + pub span: Span, +} - Ok(doc_str - .and_then(|doc_str| Self::parse_bullets_from_string(&doc_str)) - .map_err(input.convert_err(tcx))? - .into_iter() - .map(|(req, range)| { - respan( - *err::span::span_some_comments(attrs, range).first().unwrap(), - req, - ) - }) - .collect()) +impl DefAnnotation { + /// Whether this function's annotation creates an obligation that it's callers must uphold. + pub fn creates_obligation(&self) -> bool { + match self.local_violation_annotation { + PropertyViolation::Unconditional => true, + PropertyViolation::Never => false, + } } +} - /// Try to parse the given [`Input`](Annotation::Input), returning `None` if - /// there was an error, but the error was recoverable. - fn try_parse( - tcx: TyCtxt, - input: impl Borrow, - ) -> Option>, ParsingError>> { - let res = Self::parse(tcx, input); +/// Parses the given function definition for a certain property, returning none if it is not +/// annotated. +pub fn parse_fn_def( + tcx: TyCtxt<'_>, + fn_def: impl Into, + property: P, +) -> Option { + // 1. get the doc string + let fn_def: rustc_span::def_id::DefId = fn_def.into(); + let doc_str = get_doc_str(fn_def, tcx)?; - // If the error is recoverable, just return none instead. - match res.as_ref().map_err(ParsingError::issue) { - Err(ParsingIssue::NoDocString | ParsingIssue::NoMarkerPattern) => None, - _unrecoverable => Some(res), - } + // 2. parse the doc string based on the property + simple_parse_fn_def(doc_str, property, AnnotationSource::DocComment) +} + +fn parent_block_expr<'tcx>( + tcx: TyCtxt<'tcx>, + call_expr: rustc_hir::Expr<'tcx>, +) -> Option> { + tcx.hir_parent_iter(call_expr.hir_id) + .find_map(|(id, node)| { + if let rustc_hir::Node::Block(b) = &node { + Some(**b) + } else { + None + } + }) +} + +pub fn parse_expr<'tcx, P: Property>( + tcx: TyCtxt<'tcx>, + call_expr: rustc_hir::Expr<'tcx>, + property: P, +) -> Option { + // 1. get the doc string directly + let direct_annotation = get_doc_str(call_expr, tcx) + .and_then(|doc_str| simple_parse_callsite(doc_str, property, AnnotationSource::DocComment)); + if let Some(direct) = direct_annotation { + return Some(direct); } + + // 1. if we don't have it directly, trying getting it from a parent block... + simple_parse_callsite( + get_doc_str(parent_block_expr(tcx, call_expr)?, tcx)?, + property, + AnnotationSource::DocComment, + ) +} + +fn simple_parse_callsite( + doc_str: DocStr, + property: P, + source: AnnotationSource, +) -> Option { + property + .callsite_regex() + .find(doc_str.str()) + .map(|found| ExpressionAnnotation { + property_name: P::name(), + text: doc_str.str()[found.end()..].to_string(), + span: doc_str.span_of_chars(found.range()), + }) +} + +/// Simple check if the obligation regex is contained anywhere in the doc string, otherwise no obligations. +fn simple_parse_fn_def( + doc_str: DocStr, + property: P, + source: AnnotationSource, +) -> Option { + property + .fn_def_regex() + .find(doc_str.str()) + .map(|found| DefAnnotation { + property_name: P::name(), + local_violation_annotation: PropertyViolation::Unconditional, + source, + span: doc_str.span_of_chars(found.range()), + }) } diff --git a/crates/sniff-test/src/annotations/parsing.rs b/crates/sniff-test/src/annotations/parsing.rs index c0500b9..40189d4 100644 --- a/crates/sniff-test/src/annotations/parsing.rs +++ b/crates/sniff-test/src/annotations/parsing.rs @@ -21,7 +21,7 @@ fn subslice_offset_stable(original: &str, inner: &str) -> Option { } /// A trait for parsing structured data from bulleted lists in doc strings. -pub trait ParseBulletsFromString: Sized { +trait ParseBulletsFromString: Sized { /// The delimiter used to separate out two portions of each bullet. /// See [`parse_bullet`](ParseBulletsFromString::parse_bullet) for how it can be used. const BULLET_SEP: &str = ":"; diff --git a/crates/sniff-test/src/annotations/span.rs b/crates/sniff-test/src/annotations/span.rs new file mode 100644 index 0000000..6042638 --- /dev/null +++ b/crates/sniff-test/src/annotations/span.rs @@ -0,0 +1,112 @@ +//! Utilities for converting characters from a doc comment back into the span that created them. + +use rustc_hir::Attribute; +use rustc_span::BytePos; +use rustc_span::Span; +use std::borrow::Borrow; +use std::ops::Range; + +/// The length of each doc comment line before you reach the start of the actual doc comment. +/// Currently 3 because of the three backslashes before each line, telling us to factor those in +/// when converting from a doc string to a span which will have those extra characters each line. +const DOC_COMMENT_PREFIX_LEN: u32 = 3; + +/// Returns the set of spans relevant for a certain range of characters distributed throughout a +/// set of doc comments. +/// +/// For example, if the `chars` array goes from halfway through the first comment to halfway +/// through the second, this will return the second half of the first doc comment's span and +/// the first half of the second doc comment's span. +pub fn span_some_comments( + doc_comments: &[Attribute], + chars: impl Borrow>, +) -> Vec { + let chars: &Range = chars.borrow(); + + let doc_comments = doc_comments + .iter() + .filter_map(|attr| Some((attr.span(), attr.doc_str().map(|a| a.as_str().to_owned())?))) + .collect::>(); + + let mut final_spans = vec![]; + let mut line_start_char_no = 0; + for (mut span, comment) in doc_comments { + let wanted_char_start = u32::try_from((chars.start).saturating_sub(line_start_char_no)).expect("it would be crazy if the doc string length was greater than the max val for a u32 i would be very impressed"); + let wanted_char_end = u32::try_from(usize::min( + (chars.end).saturating_sub(line_start_char_no), + comment.len(), + )) + .expect("same here..."); + + let wanted_span_start: BytePos = if wanted_char_start == 0 { + span.lo() + } else { + span.lo() + BytePos(wanted_char_start + DOC_COMMENT_PREFIX_LEN) + }; + let wanted_span_end = if wanted_char_end == 0 { + span.lo() + } else { + span.lo() + BytePos(wanted_char_end + DOC_COMMENT_PREFIX_LEN) + }; + + line_start_char_no += comment.len() + 1; + + if wanted_span_start > span.lo() { + span = span.with_lo(wanted_span_start); + } + if wanted_span_end < span.hi() { + span = span.with_hi(wanted_span_end); + } + + // trim all the spans we don't want to include + if span.hi() != span.lo() { + final_spans.push(span); + } + } + + final_spans.merge_adjacent() +} + +/// Returns the span for all `doc_comments`. +pub fn span_all_comments(doc_comments: &[Attribute]) -> Vec { + doc_comments + .iter() + .enumerate() + .filter_map(|attr| { + if let rustc_hir::Attribute::Parsed(kind) = attr.1 + && let rustc_hir::attrs::AttributeKind::DocComment { span, .. } = kind + { + Some(*span) + } else { + None + } + }) + .merge_adjacent() +} + +/// Adaptor trait to call this function as a method. +pub trait Mergeable { + fn merge_adjacent(self) -> Vec; +} + +impl Mergeable for T +where + T: IntoIterator, +{ + /// Merges spans that are adjacent in the iterator and correspond to adjacent regions of code. + fn merge_adjacent(self) -> Vec { + self.into_iter() + .fold(Vec::new(), |mut base: Vec, span: Span| { + if let Some(last) = base.last_mut() + && last.hi() + BytePos(1) == span.lo() + { + // Merge the line spans if they're adjacent + *last = last.to(span); + } else { + base.push(span); + } + + base + }) + } +} diff --git a/crates/sniff-test/src/check/expr.rs b/crates/sniff-test/src/check/expr.rs index 134982c..428d824 100644 --- a/crates/sniff-test/src/check/expr.rs +++ b/crates/sniff-test/src/check/expr.rs @@ -12,18 +12,6 @@ use rustc_hir::{ use rustc_middle::ty::TyCtxt; use rustc_span::Span; -// thread_local! { -// static MAPPINGS: RefCell> = Default::default(); -// } - -// fn find_expr_for_call(tcx: TyCtxt, call_to: DefId, call_from: Span) -> Expr { -// // MAPPINGS.with_borrow_mut(move |map| { -// // *map.entry(call_from) -// // .or_insert_with(move || find_expr_for_call_inner(tcx, call_from)) -// // }) -// find_expr_for_call_inner(tcx, call_to, call_from) -// } - pub fn find_expr_for_call( tcx: TyCtxt<'_>, call_to: DefId, diff --git a/crates/sniff-test/src/check/mod.rs b/crates/sniff-test/src/check/mod.rs index 607196c..aa55454 100644 --- a/crates/sniff-test/src/check/mod.rs +++ b/crates/sniff-test/src/check/mod.rs @@ -5,9 +5,9 @@ use rustc_middle::ty::TyCtxt; use rustc_span::{ErrorGuaranteed, source_map::Spanned, sym::todo_macro}; use crate::{ - annotations::{self, Annotation, ParsingError, Requirement}, - axioms::{self, Axiom, AxiomFinder, AxiomaticBadness}, - reachability::{self, CallsToBad, LocallyReachable}, + annotations::{self, parse_expr}, + properties::{self, Axiom, Property}, + reachability::{self, CallsWObligations, LocallyReachable}, utils::SniffTestDiagnostic, }; @@ -15,10 +15,10 @@ mod expr; /// Checks that all local functions in the crate are properly annotated. pub fn check_properly_annotated(tcx: TyCtxt) -> Result<(), ErrorGuaranteed> { - let mut res = Ok(()); - - let entry = reachability::annotated_local_entry_points(tcx).collect::>(); + let entry = reachability::local_entry_points(tcx).collect::>(); + // Debug print all our entries and where they are in the src + // (this isn't actually needed for analysis) let entries = entry .iter() .map(|local| { @@ -33,68 +33,85 @@ pub fn check_properly_annotated(tcx: TyCtxt) -> Result<(), ErrorGuaranteed> { log::debug!("reachable is {reachable:#?}"); // For all reachable local function definitions, ensure their axioms align with their annotations. - for reachable in reachable.iter().cloned() { - let axioms = axioms::find_axioms(axioms::SafetyFinder, tcx, &reachable); - - // Parse the requirements - let my_requirements = annotations::Requirement::try_parse(tcx, reachable.reach.to_def_id()); - // let find_requirements = |def_id| annotations::Requirement::parse(tcx, def_id); - // let find_justifications = |def_id| annotations::Justification::parse(tcx, def_id); - - let bad_calls = reachability::find_bad_calls(tcx, &reachable) - .map_err(|parsing_error| parsing_error.diag(tcx.dcx()).emit())? - // Take only the unjustified call sites - .map(only_unjustified_callsites(tcx, reachable.reach)) - // Filter out everything that no longer has call sites - .filter(|calls| { - !calls - .as_ref() - .is_ok_and(|calls| calls.from_spans.is_empty()) - }) - .collect::, ErrorGuaranteed>>()?; - - // let justifications = annotations::Justification::try_parse(tcx, todo!()); - - // For now, just check that all functions with axioms have some annotations. - if my_requirements.is_none() && (!axioms.is_empty() || !bad_calls.is_empty()) { - res = Err(needs_annotation( - tcx.dcx(), - tcx, - &reachable, - FunctionIssues(axioms, bad_calls), - )); - } + for func in reachable { + check_function_properties(tcx, func, properties::SafetyProperty)?; } - res + Ok(()) } -fn only_unjustified_callsites( +fn check_function_properties( + tcx: TyCtxt, + func: LocallyReachable, + property: P, +) -> Result<(), ErrorGuaranteed> { + // Look for the local annotation + let annotation = annotations::parse_fn_def(tcx, func.reach, property); + + // If the function we're analyzing is directly annotated, we trust the user's annotation + // and don't need to analyze its body locally. Vitally, we'll still explore functions it calls + // due to collecting reachability earlier. + if let Some(annotation) = annotation { + // TODO: in the future, could check to make sure this annotation doesn't create unneeded obligations. + return Ok(()); + } + + // Look for all axioms within this function + let axioms = properties::find_axioms(tcx, &func, property); + + log::debug!("fn {:?} has axioms {:?}", func.reach, axioms); + log::debug!("fn {:?} has obligations {:?}", func.reach, annotation); + + // Find all calls that have obligations. + let bad_calls = reachability::find_calls_w_obligations(tcx, &func, property) + // Filter those with only callsites that haven't been justified. + .filter_map(only_unjustified_callsites(tcx, func.reach, property)) + .collect::>(); + + // If we have obligations, we've dismissed them + + // todo!() + if bad_calls.is_empty() { + Ok(()) + } else { + Err(tcx.dcx().struct_err("sniff test failed!").emit()) + } +} + +/// Filter a set of calls to a function for only those which are not property justified. +fn only_unjustified_callsites( tcx: TyCtxt, in_fn: LocalDefId, -) -> impl Fn(CallsToBad) -> Result { + property: P, +) -> impl Fn(CallsWObligations) -> Option { move |mut calls| { let mut new_spans = Vec::new(); - let requirements = - annotations::Requirement::parse(tcx, calls.def_id).map_err(|e| e.emit(tcx.dcx()))?; + let obligations = &calls.w_annotation; for call_span in calls.from_spans { - let expr = expr::find_expr_for_call(tcx, calls.def_id, in_fn, call_span); - let justs = annotations::Justification::try_parse(tcx, expr); - // println!("justs are {justs:?}"); - match justs { - Some(Err(e)) => return Err(e.emit(tcx.dcx())), - Some(Ok(justs)) => annotations::check::check_consistency(&justs, &requirements) - .map_err(|e| e.diag(tcx.dcx()).emit())?, - None => new_spans.push(call_span), + let call_expr = expr::find_expr_for_call(tcx, calls.call_to, in_fn, call_span); + let callsite_annotation = parse_expr(tcx, *call_expr, property); + + println!("found justification {callsite_annotation:?}"); + + if callsite_annotation.is_none() { + new_spans.push(call_span); } } - calls.from_spans = new_spans; - Ok(calls) + + println!("found spans {new_spans:?}"); + + // If we have no new callsites, just remove this one from the list... + if new_spans.is_empty() { + None + } else { + calls.from_spans = new_spans; + Some(calls) + } } } -struct FunctionIssues(Vec>, Vec); +// struct FunctionIssues(Vec>, Vec); // pub fn check_function( // tcx: TyCtxt, @@ -107,67 +124,67 @@ struct FunctionIssues(Vec>, Vec); // todo!() // } -fn needs_annotation( - dcx: DiagCtxtHandle, - tcx: TyCtxt, - reachable: &LocallyReachable, - bc_of_isses: FunctionIssues, -) -> ErrorGuaranteed { - let def_span = tcx.def_span(reachable.reach); - let fn_name = tcx.def_path_str(reachable.reach.to_def_id()); +// fn needs_annotation( +// dcx: DiagCtxtHandle, +// tcx: TyCtxt, +// reachable: &LocallyReachable, +// bc_of_isses: FunctionIssues, +// ) -> ErrorGuaranteed { +// let def_span = tcx.def_span(reachable.reach); +// let fn_name = tcx.def_path_str(reachable.reach.to_def_id()); - let mut diag = dcx.struct_span_err(def_span, summary::summary_string(&fn_name, &bc_of_isses)); +// let mut diag = dcx.struct_span_err(def_span, summary::summary_string(&fn_name, &bc_of_isses)); - diag = diag.with_note(reachability_str(&fn_name, tcx, reachable)); +// diag = diag.with_note(reachability_str(&fn_name, tcx, reachable)); - for axiom in bc_of_isses.0 { - diag = diag_handle_axiom(diag, axiom); - } +// for axiom in bc_of_isses.0 { +// diag = diag_handle_axiom(diag, axiom); +// } - for bad_call in bc_of_isses.1 { - diag = diag_handle_bad_call(diag, tcx, bad_call); - } - - diag.emit() -} +// for bad_call in bc_of_isses.1 { +// diag = diag_handle_bad_call(diag, tcx, bad_call); +// } -fn diag_handle_bad_call<'d>(mut diag: Diag<'d>, tcx: TyCtxt, bad_call: CallsToBad) -> Diag<'d> { - // let times = if bad_call.from_spans.len() > 1 { - // format!("{} times ", bad_call.from_spans.len()) - // } else { - // String::new() - // }; - let call_to = tcx.def_path_str(bad_call.def_id); - diag = diag.with_span_note(bad_call.from_spans, format!("{call_to} is called here")); +// diag.emit() +// } - diag -} +// fn diag_handle_bad_call<'d>(mut diag: Diag<'d>, tcx: TyCtxt, bad_call: CallsToBad) -> Diag<'d> { +// // let times = if bad_call.from_spans.len() > 1 { +// // format!("{} times ", bad_call.from_spans.len()) +// // } else { +// // String::new() +// // }; +// let call_to = tcx.def_path_str(bad_call.def_id); +// diag = diag.with_span_note(bad_call.from_spans, format!("{call_to} is called here")); -#[allow(clippy::needless_pass_by_value)] -fn diag_handle_axiom(mut diag: Diag<'_>, axiom: Spanned) -> Diag<'_> { - diag = diag.with_span_note(axiom.span, format!("{} here", axiom.node)); - match axiom.node.known_requirements() { - None => (), - Some(AxiomaticBadness::Conditional(known_reqs)) => { - // We know the conditional requirements, so display them - let intro_string = "this axiom has known requirements:".to_string(); - - let known_req_strs = known_reqs - .into_iter() - .enumerate() - .map(|(i, req)| format!("\t{}. {}", i + 1, req.description())); - - diag = diag.with_help( - std::iter::once(intro_string) - .chain(known_req_strs) - .join("\n"), - ); - } - Some(AxiomaticBadness::Unconditional) => todo!(), - } +// diag +// } - diag -} +// #[allow(clippy::needless_pass_by_value)] +// fn diag_handle_axiom(mut diag: Diag<'_>, axiom: Spanned) -> Diag<'_> { +// diag = diag.with_span_note(axiom.span, format!("{} here", axiom.node)); +// match axiom.node.known_requirements() { +// None => (), +// Some(AxiomaticBadness::Conditional(known_reqs)) => { +// // We know the conditional requirements, so display them +// let intro_string = "this axiom has known requirements:".to_string(); + +// let known_req_strs = known_reqs +// .into_iter() +// .enumerate() +// .map(|(i, req)| format!("\t{}. {}", i + 1, req.description())); + +// diag = diag.with_help( +// std::iter::once(intro_string) +// .chain(known_req_strs) +// .join("\n"), +// ); +// } +// Some(AxiomaticBadness::Unconditional) => todo!(), +// } + +// diag +// } fn reachability_str(fn_name: &str, tcx: TyCtxt, reachable: &LocallyReachable) -> String { let reachability_str = reachable @@ -188,45 +205,45 @@ fn reachability_str(fn_name: &str, tcx: TyCtxt, reachable: &LocallyReachable) -> format!("reachable from [{reachability_str}]") } -mod summary { - use itertools::Itertools; - use rustc_span::source_map::Spanned; - - use crate::axioms::Axiom; - use crate::check::FunctionIssues; - use crate::reachability::CallsToBad; - - pub fn summary_string(fn_name: &str, issues: &FunctionIssues) -> String { - let axiom_summary = axiom_summary(&issues.0); - let call_summary = call_summary::(&issues.1); - let issue_summary = [axiom_summary, call_summary] - .into_iter() - .flatten() - .join(" and "); - - let kind = A::axiom_kind_name(); - format!("function {fn_name} directly contains {issue_summary}, but is not annotated {kind}") - } - - fn call_summary(calls: &[CallsToBad]) -> Option { - let count: usize = calls.iter().map(|call| call.from_spans.len()).sum(); - let kind = A::axiom_kind_name(); - let s = match count { - 1 => "", - x if x > 1 => "s", - _ => return None, - }; - Some(format!("{count} unjustified call{s} to {kind} functions")) - } - - fn axiom_summary(axioms: &[Spanned]) -> Option { - let count = axioms.len(); - let kind = A::axiom_kind_name(); - let s = match count { - 1 => "", - x if x > 1 => "s", - _ => return None, - }; - Some(format!("{count} unjustified {kind} axiom{s}")) - } -} +// mod summary { +// use itertools::Itertools; +// use rustc_span::source_map::Spanned; + +// use crate::check::FunctionIssues; +// use crate::properties::Axiom; +// use crate::reachability::CallsToBad; + +// pub fn summary_string(fn_name: &str, issues: &FunctionIssues) -> String { +// let axiom_summary = axiom_summary(&issues.0); +// let call_summary = call_summary::(&issues.1); +// let issue_summary = [axiom_summary, call_summary] +// .into_iter() +// .flatten() +// .join(" and "); + +// let kind = A::axiom_kind_name(); +// format!("function {fn_name} directly contains {issue_summary}, but is not annotated {kind}") +// } + +// fn call_summary(calls: &[CallsToBad]) -> Option { +// let count: usize = calls.iter().map(|call| call.from_spans.len()).sum(); +// let kind = A::axiom_kind_name(); +// let s = match count { +// 1 => "", +// x if x > 1 => "s", +// _ => return None, +// }; +// Some(format!("{count} unjustified call{s} to {kind} functions")) +// } + +// fn axiom_summary(axioms: &[Spanned]) -> Option { +// let count = axioms.len(); +// let kind = A::axiom_kind_name(); +// let s = match count { +// 1 => "", +// x if x > 1 => "s", +// _ => return None, +// }; +// Some(format!("{count} unjustified {kind} axiom{s}")) +// } +// } diff --git a/crates/sniff-test/src/lib.rs b/crates/sniff-test/src/lib.rs index e0e4091..a105aae 100644 --- a/crates/sniff-test/src/lib.rs +++ b/crates/sniff-test/src/lib.rs @@ -2,6 +2,7 @@ #![feature(rustc_private)] #![feature(box_patterns)] +#![feature(try_trait_v2)] #![cfg_attr(test, feature(assert_matches))] #![deny(warnings)] #![warn(clippy::pedantic)] @@ -9,7 +10,8 @@ unused, clippy::must_use_candidate, clippy::missing_panics_doc, // TODO: should remove this, kinda ironic for us to be using it... - clippy::missing_errors_doc + clippy::missing_errors_doc, + clippy::needless_pass_by_value, )] extern crate lazy_static; @@ -26,8 +28,8 @@ extern crate rustc_span; extern crate rustc_type_ir; pub mod annotations; -mod axioms; mod check; +pub mod properties; mod reachability; pub mod utils; @@ -81,13 +83,13 @@ fn env_logger_init_file(driver: bool) { env_logger::Builder::from_default_env() .format_timestamp(None) .target(env_logger::Target::Pipe(Box::new(log_file))) - .init() + .init(); } fn env_logger_init_terminal() { env_logger::Builder::from_default_env() .format_timestamp(None) - .init() + .init(); } pub fn env_logger_init(driver: bool) { @@ -131,7 +133,7 @@ impl RustcPlugin for PrintAllItemsPlugin { // Register the sniff_tool let existing = std::env::var("RUSTFLAGS").unwrap_or_default(); - cargo.env("RUSTFLAGS", format!("-Zcrate-attr=feature(register_tool) -Zcrate-attr=register_tool(sniff_tool) -Aunused-doc-comments {existing}")); + cargo.env("RUSTFLAGS", format!("-Zcrate-attr=feature(register_tool) -Zcrate-attr=register_tool(sniff_tool) -Aunused-doc-comments {existing} -Zcrate-attr=feature(custom_inner_attributes)")); } // In the driver, we use the Rustc API to start a compiler session diff --git a/crates/sniff-test/src/axioms/mod.rs b/crates/sniff-test/src/properties/mod.rs similarity index 53% rename from crates/sniff-test/src/axioms/mod.rs rename to crates/sniff-test/src/properties/mod.rs index ef0f326..24b1e3c 100644 --- a/crates/sniff-test/src/axioms/mod.rs +++ b/crates/sniff-test/src/properties/mod.rs @@ -1,38 +1,42 @@ //! A module for detecting axiomatic program patterns -use crate::{annotations, reachability::LocallyReachable}; +use crate::{ + annotations::{self, PropertyViolation}, + reachability::LocallyReachable, +}; +use regex::Regex; use rustc_hir::intravisit::{self, Visitor}; use rustc_middle::{ hir::nested_filter, ty::{TyCtxt, TypeckResults}, }; use rustc_span::source_map::Spanned; -use std::fmt::Display; +use std::fmt::Debug; +use std::{fmt::Display, sync::Arc}; mod panic; mod safety; -pub use safety::SafetyFinder; +pub use panic::PanicProperty; +pub use safety::SafetyProperty; -pub enum AxiomaticBadness { - Unconditional, - Conditional(Vec), -} +// pub fn all_properties() -> Arc>> { +// Arc::new(vec![Box::new(SafetyProperty)]) +// } -pub trait Axiom: Display { - /// The name for this kind of axiom (e.g. `I found a {name} axiom in your code`) - fn axiom_kind_name() -> &'static str; +pub trait Property: Debug + 'static + Copy { + type Axiom: Axiom; + fn name() -> &'static str; - /// The requirements that this axiom has, if known. - fn known_requirements(&self) -> Option { - None - } -} + /// The regex marker (to be placed within function definition doc comments) + /// which will register the function's body as having this property. + fn fn_def_regex(&self) -> Regex; -pub trait AxiomFinder { - type Axiom: Axiom; + /// The regex marker (to be placed on calls to functions with this property) + /// that indicates obligations have been discharged. + fn callsite_regex(&self) -> Regex; - fn find_in_expr( + fn find_axioms_in_expr( &mut self, tcx: TyCtxt, tyck: &TypeckResults, @@ -40,23 +44,35 @@ pub trait AxiomFinder { ) -> Vec>; } -struct FinderWrapper<'tcx, T: AxiomFinder> { +pub trait Axiom: Display + Debug { + type Property: Property; + + /// The name for this kind of axiom (e.g. `I found a {name} axiom in your code`) + fn axiom_kind_name() -> &'static str; + + /// The requirements that this axiom has, if known. + fn known_requirements(&self) -> Option { + None + } +} + +struct FinderWrapper<'tcx, T: Property> { tcx: TyCtxt<'tcx>, - finder: T, + property: T, tychck: &'tcx TypeckResults<'tcx>, axioms: Vec>, } -pub fn find_axioms( - finder: T, +pub fn find_axioms( tcx: TyCtxt, locally_reachable: &LocallyReachable, + property: T, ) -> Vec> { let body = tcx.hir_body_owned_by(locally_reachable.reach).id(); let tychck = tcx.typeck_body(body); let mut finder = FinderWrapper { - finder, + property, tychck, tcx, axioms: Vec::new(), @@ -67,7 +83,7 @@ pub fn find_axioms( finder.axioms } -impl<'tcx, T: AxiomFinder> Visitor<'tcx> for FinderWrapper<'tcx, T> { +impl<'tcx, T: Property> Visitor<'tcx> for FinderWrapper<'tcx, T> { type NestedFilter = nested_filter::OnlyBodies; type MaybeTyCtxt = TyCtxt<'tcx>; @@ -78,7 +94,7 @@ impl<'tcx, T: AxiomFinder> Visitor<'tcx> for FinderWrapper<'tcx, T> { #[allow(clippy::semicolon_if_nothing_returned)] fn visit_expr(&mut self, ex: &'tcx rustc_hir::Expr<'tcx>) -> Self::Result { self.axioms - .extend(self.finder.find_in_expr(self.tcx, self.tychck, ex)); + .extend(self.property.find_axioms_in_expr(self.tcx, self.tychck, ex)); intravisit::walk_expr(self, ex) } diff --git a/crates/sniff-test/src/axioms/panic.rs b/crates/sniff-test/src/properties/panic.rs similarity index 69% rename from crates/sniff-test/src/axioms/panic.rs rename to crates/sniff-test/src/properties/panic.rs index 0e635c2..89861d0 100644 --- a/crates/sniff-test/src/axioms/panic.rs +++ b/crates/sniff-test/src/properties/panic.rs @@ -1,42 +1,35 @@ +use regex::Regex; use rustc_hir::ExprKind; use rustc_middle::ty::TyCtxt; use rustc_span::source_map::{Spanned, respan}; use std::fmt::Display; use super::Axiom; -use crate::axioms::{AxiomFinder, AxiomaticBadness}; - -pub struct PanicFinder; +use crate::{annotations::PropertyViolation, properties::Property}; #[derive(Debug, Clone)] pub enum PanicAxiom { ExplicitPanic, } -impl Axiom for PanicAxiom { - fn axiom_kind_name() -> &'static str { +#[derive(Debug, Clone, Copy)] +pub struct PanicProperty; + +impl Property for PanicProperty { + type Axiom = PanicAxiom; + fn name() -> &'static str { "panicking" } - fn known_requirements(&self) -> Option { - match self { - Self::ExplicitPanic => Some(AxiomaticBadness::Unconditional), - } + fn callsite_regex(&self) -> Regex { + todo!() } -} -impl Display for PanicAxiom { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Self::ExplicitPanic => f.write_str("explicit panic"), - } + fn fn_def_regex(&self) -> Regex { + Regex::new("(\n|^)(\\s*)[#]+ (Panics|PANICS)(\n|$)").unwrap() } -} - -impl AxiomFinder for PanicFinder { - type Axiom = PanicAxiom; - fn find_in_expr( + fn find_axioms_in_expr( &mut self, tcx: TyCtxt, tyck: &rustc_middle::ty::TypeckResults, @@ -61,3 +54,24 @@ impl AxiomFinder for PanicFinder { vec![] } } + +impl Axiom for PanicAxiom { + type Property = PanicProperty; + fn axiom_kind_name() -> &'static str { + "panicking" + } + + fn known_requirements(&self) -> Option { + match self { + Self::ExplicitPanic => Some(PropertyViolation::Unconditional), + } + } +} + +impl Display for PanicAxiom { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::ExplicitPanic => f.write_str("explicit panic"), + } + } +} diff --git a/crates/sniff-test/src/axioms/safety.rs b/crates/sniff-test/src/properties/safety.rs similarity index 52% rename from crates/sniff-test/src/axioms/safety.rs rename to crates/sniff-test/src/properties/safety.rs index 5b61072..5e51f58 100644 --- a/crates/sniff-test/src/axioms/safety.rs +++ b/crates/sniff-test/src/properties/safety.rs @@ -1,5 +1,6 @@ use std::fmt::Display; +use regex::Regex; use rustc_ast::UnOp; use rustc_hir::ExprKind; use rustc_middle::ty::TyCtxt; @@ -8,51 +9,30 @@ use rustc_type_ir::TyKind; use super::Axiom; use crate::{ - annotations, - axioms::{AxiomFinder, AxiomaticBadness}, + annotations::{self, PropertyViolation}, + properties::Property, }; -/// A finder that looks for axioms that **could cause UB**. -/// -/// Currently just looks for raw pointer dereferences. -pub struct SafetyFinder; +#[derive(Debug, Clone, Copy)] +pub struct SafetyProperty; -#[derive(Debug, Clone)] -pub enum SafetyAxiom { - RawPtrDeref, -} - -impl Axiom for SafetyAxiom { - fn axiom_kind_name() -> &'static str { - "unsafe" +impl Property for SafetyProperty { + type Axiom = SafetyAxiom; + fn name() -> &'static str { + "safety" } - fn known_requirements(&self) -> Option { - match self { - Self::RawPtrDeref => Some(AxiomaticBadness::Conditional( - annotations::Requirement::construct([ - ("ptr-non-null", "the dereferenced pointer must be non-null"), - ("ptr-aligned", "the dereferenced pointer must be aligned"), - ]), - )), - } + fn fn_def_regex(&self) -> Regex { + Regex::new("(\n|^)(\\s*)[#]+ (Safety|SAFETY)(\n|$)").unwrap() } -} -impl Display for SafetyAxiom { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Self::RawPtrDeref => f.write_str("raw pointer derefence"), - } + fn callsite_regex(&self) -> Regex { + Regex::new("(\n|^)(\\s*)(Safety|SAFETY):").unwrap() } -} -impl AxiomFinder for SafetyFinder { - type Axiom = SafetyAxiom; - - fn find_in_expr( + fn find_axioms_in_expr( &mut self, - _tcx: TyCtxt, + tcx: TyCtxt, tyck: &rustc_middle::ty::TypeckResults, expr: &rustc_hir::Expr, ) -> Vec> { @@ -68,3 +48,35 @@ impl AxiomFinder for SafetyFinder { vec![] } } + +#[derive(Debug, Clone)] +pub enum SafetyAxiom { + RawPtrDeref, +} + +impl Axiom for SafetyAxiom { + type Property = SafetyProperty; + fn axiom_kind_name() -> &'static str { + "unsafe" + } + + fn known_requirements(&self) -> Option { + todo!() + // match self { + // Self::RawPtrDeref => Some(Badness::ConditionallyBad( + // annotations::Requirement::construct([ + // ("ptr-non-null", "the dereferenced pointer must be non-null"), + // ("ptr-aligned", "the dereferenced pointer must be aligned"), + // ]), + // )), + // } + } +} + +impl Display for SafetyAxiom { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::RawPtrDeref => f.write_str("raw pointer derefence"), + } + } +} diff --git a/crates/sniff-test/src/reachability/bad.rs b/crates/sniff-test/src/reachability/bad.rs index 5eb2441..2e27890 100644 --- a/crates/sniff-test/src/reachability/bad.rs +++ b/crates/sniff-test/src/reachability/bad.rs @@ -1,8 +1,10 @@ //! Finds the 'bad' functions that should be annotated -use crate::annotations::{self, Annotation, ParsingError, Requirement}; +use crate::annotations::{self, DefAnnotation, parse_fn_def}; +use crate::properties::Property; use crate::reachability::LocallyReachable; use std::collections::HashMap; +use std::ops::Try; use crate::utils::MultiEmittable; use rustc_hir::def_id::{DefId, DefPathHash}; @@ -12,100 +14,39 @@ use rustc_public::ty::FnDef; use rustc_span::source_map::Spanned; use rustc_span::{ErrorGuaranteed, Span}; -// TODO: use this shit instead in all the parsing -enum Annotations { - General, - SpecificConditions(Vec), -} - -type BadMap = HashMap>; - -fn build_bad_map(tcx: TyCtxt) -> Result { - // for a in tcx.hir_crate_items(()).definitions() { - - // } - - todo!() -} - -pub struct CallsToBad { - pub def_id: DefId, - pub requirements: Vec>, +#[derive(Debug)] +pub struct CallsWObligations { + pub call_to: DefId, + pub w_annotation: DefAnnotation, pub from_spans: Vec, } -fn is_call_bad<'tcx>( - tcx: TyCtxt<'tcx>, -) -> impl Fn((&DefId, &Vec)) -> Option>> { +fn call_has_obligations( + tcx: TyCtxt, + property: P, +) -> impl Fn((&DefId, &Vec)) -> Option { move |(to_def_id, from_spans)| { - let requirements = match Requirement::try_parse(tcx, to_def_id)? { - Err(e) => return Some(Err(e)), - Ok(req) => req, - }; - - // match - Some(Ok(CallsToBad { - def_id: *to_def_id, - requirements, - from_spans: from_spans.clone(), - })) + let annotation = parse_fn_def(tcx, *to_def_id, property)?; + + if annotation.creates_obligation() { + Some(CallsWObligations { + call_to: *to_def_id, + w_annotation: annotation, + from_spans: from_spans.clone(), + }) + } else { + None + } } } -pub fn find_bad_calls<'tcx>( - tcx: TyCtxt<'tcx>, +pub fn find_calls_w_obligations( + tcx: TyCtxt, locally_reachable: &LocallyReachable, -) -> Result, ParsingError<'tcx>> { + property: P, +) -> impl Iterator { locally_reachable .calls_to .iter() - .filter_map(is_call_bad(tcx)) - .collect::, ParsingError>>() - .map(std::iter::IntoIterator::into_iter) -} - -pub fn filter_bad_functions( - tcx: TyCtxt, - items: &[FnDef], -) -> Result>>, ErrorGuaranteed> { - let annotated_bad = items - .iter() - .filter_map(|item| { - Some(( - *item, - Requirement::try_parse(tcx, rustc_public::rustc_internal::internal(tcx, item.0))?, - )) - }) - .collect::>() - .emit_all_errors(tcx)?; - - let should_be_bad = items - .iter() - .filter_map(|fn_def| Some((fn_def, should_be_bad(tcx, *fn_def)?))); - - let bad_but_missed = should_be_bad - .filter(|(fn_def, _reason)| !annotated_bad.contains_key(fn_def)) - .collect::>(); - - assert!( - bad_but_missed.is_empty(), - "some functions should be annotated for the following reasons, but are not {bad_but_missed:?}" - ); - - Ok(annotated_bad) -} - -#[derive(Debug)] -pub enum ShouldBeBadReason { - MarkedUnsafe, - // SpecifiedInToml? -} - -// TODO: add config from .toml file. -fn should_be_bad(_tcx: TyCtxt, fn_def: FnDef) -> Option { - if fn_def.fn_sig().value.safety == Safety::Unsafe { - return Some(ShouldBeBadReason::MarkedUnsafe); - } - - None + .filter_map(call_has_obligations(tcx, property)) } diff --git a/crates/sniff-test/src/reachability/entry.rs b/crates/sniff-test/src/reachability/entry.rs index e0be719..4991479 100644 --- a/crates/sniff-test/src/reachability/entry.rs +++ b/crates/sniff-test/src/reachability/entry.rs @@ -3,15 +3,23 @@ use rustc_middle::ty::TyCtxt; use crate::reachability::attr::{self, SniffToolAttr}; -// pub fn filter_entry_points(tcx: TyCtxt, items: &[FnDef]) -> Vec { -// items -// .into_iter() -// .filter(|item| is_entry_point(tcx, **item)) -// .copied() -// .collect::>() -// } +pub fn local_entry_points(tcx: TyCtxt) -> impl Iterator { + // global_annotations(tcx); + if false { + todo!() + } else { + annotated_local_entry_points(tcx) + } +} + +pub fn global_annotations(tcx: TyCtxt) -> bool { + for attr in tcx.hir_krate_attrs() { + println!("attr is {attr:?}"); + } + todo!() +} -pub fn annotated_local_entry_points(tcx: TyCtxt) -> impl Iterator { +fn annotated_local_entry_points(tcx: TyCtxt) -> impl Iterator { tcx.hir_body_owners() .filter(move |item| is_entry_point(tcx, item.to_def_id())) } diff --git a/crates/sniff-test/src/reachability/err.rs b/crates/sniff-test/src/reachability/err.rs index 045c436..c430451 100644 --- a/crates/sniff-test/src/reachability/err.rs +++ b/crates/sniff-test/src/reachability/err.rs @@ -1,14 +1,14 @@ use rustc_span::Span; -use crate::annotations::Justification; +// use crate::annotations::Justification; -#[derive(Debug)] -pub enum ConsistencyIssue { - UnsatisfiedJustification(Justification), -} +// #[derive(Debug)] +// pub enum ConsistencyIssue { +// UnsatisfiedJustification(Justification), +// } -#[derive(Debug)] -pub struct ConsistencyError { - call_at: Span, - issue: ConsistencyIssue, -} +// #[derive(Debug)] +// pub struct ConsistencyError { +// call_at: Span, +// issue: ConsistencyIssue, +// } diff --git a/crates/sniff-test/src/reachability/mod.rs b/crates/sniff-test/src/reachability/mod.rs index 66aa054..edb0b8c 100644 --- a/crates/sniff-test/src/reachability/mod.rs +++ b/crates/sniff-test/src/reachability/mod.rs @@ -4,6 +4,6 @@ mod entry; mod err; mod walk; -pub use bad::{CallsToBad, find_bad_calls}; -pub use entry::annotated_local_entry_points; +pub use bad::{CallsWObligations, find_calls_w_obligations}; +pub use entry::local_entry_points; pub use walk::{LocallyReachable, locally_reachable_from}; diff --git a/tests/unsafe/example_crate/src/main.rs b/tests/unsafe/example_crate/src/main.rs index 1cf6142..8076684 100644 --- a/tests/unsafe/example_crate/src/main.rs +++ b/tests/unsafe/example_crate/src/main.rs @@ -1,7 +1,9 @@ -// /// # Unsafe -// /// - non-null: ptr must be non-null +// #![sniff_tool::check_unsafe] + +/// # Safety +/// - non-null: ptr must be non-null fn foo(ptr: *const i32) -> i32 { - let a = unsafe { *ptr }; + let a = baz(ptr); a + 2 } @@ -22,12 +24,13 @@ fn bar(ptr: *const i32) -> i32 { fn main() { let a = Some(3).unwrap(); let x = 1; - /// Hello - bar(&raw const x); + /// SAFETY: blah blah + /// more doc comments + unsafe { + foo(&raw const x); + } } -// - bug to put safety comments on calls to fn without obligations - // Notes from justus // - instance safety for some traits // - when it cant be done alwyas deny and just allow specific instances From ad6fb9f9e822dbb5fd398a0bb94f3d384a36705f Mon Sep 17 00:00:00 2001 From: AlexanderPortland Date: Tue, 11 Nov 2025 12:06:36 -0500 Subject: [PATCH 30/40] error reporting again --- crates/sniff-test/src/annotations/doc.rs | 2 +- crates/sniff-test/src/check/err.rs | 119 ++++++++++++++++ crates/sniff-test/src/check/mod.rs | 152 +++------------------ crates/sniff-test/src/properties/safety.rs | 2 +- tests/unsafe/example_crate/src/main.rs | 1 + 5 files changed, 144 insertions(+), 132 deletions(-) create mode 100644 crates/sniff-test/src/check/err.rs diff --git a/crates/sniff-test/src/annotations/doc.rs b/crates/sniff-test/src/annotations/doc.rs index 380b880..0180300 100644 --- a/crates/sniff-test/src/annotations/doc.rs +++ b/crates/sniff-test/src/annotations/doc.rs @@ -1,4 +1,4 @@ -//! Utilities for getting attributes from relevant pieces of a program. +//! Utilities for getting attributes & doc strings from relevant pieces of a program. use std::ops::Range; diff --git a/crates/sniff-test/src/check/err.rs b/crates/sniff-test/src/check/err.rs new file mode 100644 index 0000000..affd016 --- /dev/null +++ b/crates/sniff-test/src/check/err.rs @@ -0,0 +1,119 @@ +use itertools::Itertools; +use rustc_errors::Diag; +use rustc_middle::ty::TyCtxt; +use rustc_span::{ErrorGuaranteed, source_map::Spanned}; + +use crate::{ + properties::Property, + reachability::{CallsWObligations, LocallyReachable}, +}; + +pub fn report_errors( + tcx: TyCtxt, + func: LocallyReachable, + property: P, + unjustified_axioms: Vec>, + unjustified_calls: Vec, +) -> ErrorGuaranteed { + let dcx = tcx.dcx(); + let def_span = tcx.def_span(func.reach); + let fn_name = tcx.def_path_str(func.reach.to_def_id()); + + let mut diag = dcx.struct_span_err( + def_span, + summary::summary_string::

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 diff --git a/tests/lib.rs b/tests/lib.rs index e8a7492..70c9c95 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -249,6 +249,9 @@ fn rustc_sniff(file_path: &Path) -> anyhow::Result { cmd.arg("-Zcrate-attr=feature(register_tool)") .arg("-Zcrate-attr=register_tool(sniff_tool)"); + // TODO: should do this all the time i think + cmd.arg("-Zno-codegen"); + // Pass in compilation argument. cmd.arg(file_path); diff --git a/tests/ref_deref b/tests/ref_deref deleted file mode 100755 index 86b0ef739ad79d2fbfa7cbdcf65c805a59b17596..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 436920 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