diff --git a/Cargo.lock b/Cargo.lock index 2a5b0c9c..8cb529a1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -189,18 +189,18 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.22" +version = "4.5.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69371e34337c4c984bbe322360c2547210bf632eb2814bbe78a6e87a2935bd2b" +checksum = "3135e7ec2ef7b10c6ed8950f0f792ed96ee093fa088608f1c76e569722700c84" dependencies = [ "clap_builder", ] [[package]] name = "clap_builder" -version = "4.5.22" +version = "4.5.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e24c1b4099818523236a8ca881d2b45db98dadfb4625cf6608c12069fcbbde1" +checksum = "30582fc632330df2bd26877bde0c1f4470d57c582bbc070376afcd04d8cb4838" dependencies = [ "anstream", "anstyle", @@ -210,9 +210,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afb84c814227b90d6895e01398aee0d8033c00e7466aca416fb6a8e0eb19d8a7" +checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" [[package]] name = "cmake" diff --git a/binaries/summary_store.tar b/binaries/summary_store.tar index de0521e1..60c1ec4a 100644 Binary files a/binaries/summary_store.tar and b/binaries/summary_store.tar differ diff --git a/checker/src/call_visitor.rs b/checker/src/call_visitor.rs index 0d123b82..46bacd44 100644 --- a/checker/src/call_visitor.rs +++ b/checker/src/call_visitor.rs @@ -340,18 +340,18 @@ impl<'call, 'block, 'analysis, 'compilation, 'tcx> if let Some(func_ref) = &self.callee_func_ref.clone() { // If the actual arguments include any function constants, collect them together // and pass them to get_summary_for_function_constant so that their signatures - // can be included in the type specific key that is used to look up non generic + // can be included in the type specific key that is used to look up non-generic // predefined summaries. let func_args = self.get_function_constant_signature(self.function_constant_args); let tcx = self.block_visitor.bv.tcx; - let callee_defid = func_ref.def_id.unwrap_or(self.callee_def_id); + let callee_def_id = func_ref.def_id.unwrap_or(self.callee_def_id); self.block_visitor.bv.cv.call_graph.add_call_site( self.block_visitor.bv.current_span, self.block_visitor.bv.def_id, - callee_defid, - !tcx.is_mir_available(callee_defid) - || (!callee_defid.is_local() + callee_def_id, + !tcx.is_mir_available(callee_def_id) + || (!callee_def_id.is_local() && (self.callee_generic_arguments.is_none() || self .callee_generic_arguments diff --git a/checker/src/summaries.rs b/checker/src/summaries.rs index f7f95245..09ee48d9 100644 --- a/checker/src/summaries.rs +++ b/checker/src/summaries.rs @@ -352,20 +352,26 @@ fn extract_reachable_heap_allocations( } } +/// If a call site provides type arguments to a generic function, or if some of the arguments +/// are constant functions, the function summary used at the call site needs to be specialized +/// with respect to these arguments and when we store summaries in a cache we need the cache +/// key to be based on these arguments. #[derive(PartialEq, Eq)] pub struct CallSiteKey<'tcx> { + /// If this is None, type_args must not be None. func_args: Option>>>, - type_cache: Option, Ty<'tcx>>>>, + /// If this is None, func_args must not be None. + type_args: Option, Ty<'tcx>>>>, } impl<'tcx> CallSiteKey<'tcx> { pub fn new( func_args: Option>>>, - type_cache: Option, Ty<'tcx>>>>, + type_args: Option, Ty<'tcx>>>>, ) -> CallSiteKey<'tcx> { CallSiteKey { func_args, - type_cache, + type_args, } } } @@ -375,7 +381,7 @@ impl Hash for CallSiteKey<'_> { if let Some(func_args) = &self.func_args { func_args.hash(state); } - if let Some(cache) = &self.type_cache { + if let Some(cache) = &self.type_args { for (path, ty) in cache.iter() { path.hash(state); ty.kind().hash(state); @@ -396,9 +402,14 @@ pub struct PersistentSummaryCache<'tcx> { /// Functions that are generic instances are identified by their function_id and their summaries /// are cached here. typed_cache: HashMap, + /// Maps call sites to specialized summary of the referenced function. + /// Call site specialization involves using the actual generic arguments supplied by the call + /// site, along with the values of any constant functions that are supplied as actual arguments. typed_cache_table: HashMap, HashMap>, + /// Functions that have no def_id (and hence no function_id) and no type signature are + /// cached here. Such functions are either entry points or dummy functions that provide + /// summaries for functions that have no MIR and are shadowed by definitions in a contracts crate. reference_cache: HashMap, Summary>, - typed_reference_cache: HashMap, Summary>, key_cache: HashMap>, type_context: TyCtxt<'tcx>, } @@ -445,7 +456,6 @@ impl<'tcx> PersistentSummaryCache<'tcx> { typed_cache: HashMap::new(), typed_cache_table: HashMap::new(), reference_cache: HashMap::new(), - typed_reference_cache: HashMap::new(), key_cache: HashMap::new(), type_context, } @@ -505,14 +515,13 @@ impl<'tcx> PersistentSummaryCache<'tcx> { &mut self, func_ref: &Rc, func_args: &Option>>>, - initial_type_cache: &Option, Ty<'tcx>>>>, + type_args: &Option, Ty<'tcx>>>>, ) -> &Summary { match (func_ref.def_id, func_ref.function_id) { // Use the ids as keys if they are available, since they make much better keys. (Some(def_id), Some(function_id)) => { - if func_args.is_some() || initial_type_cache.is_some() { - let typed_cache_key = - CallSiteKey::new(func_args.clone(), initial_type_cache.clone()); + if func_args.is_some() || type_args.is_some() { + let typed_cache_key = CallSiteKey::new(func_args.clone(), type_args.clone()); // Need the double lookup in order to allow the recursive call to get_summary_for_function_constant. let summary_is_cached = if let Some(type_table) = self.typed_cache_table.get(&typed_cache_key) { @@ -566,8 +575,8 @@ impl<'tcx> PersistentSummaryCache<'tcx> { // was created. We look them up in the database. If they are not found there, we use // a default summary. Either way, we cache the summary in the appropriate reference cache. _ => { - if self.typed_reference_cache.contains_key(func_ref) { - let result = self.typed_reference_cache.get(func_ref); + if self.reference_cache.contains_key(func_ref) { + let result = self.reference_cache.get(func_ref); result.expect("value disappeared from typed_reference_cache") } else { if let Some(summary) = self.get_persistent_summary_using_arg_types_if_possible( @@ -575,7 +584,7 @@ impl<'tcx> PersistentSummaryCache<'tcx> { &func_ref.argument_type_key, ) { return self - .typed_reference_cache + .reference_cache .entry(func_ref.clone()) .or_insert(summary); } diff --git a/validate.sh b/validate.sh index 259d95d9..b6a55052 100755 --- a/validate.sh +++ b/validate.sh @@ -18,7 +18,7 @@ cargo update # Run format checks cargo fmt --all # Run lint checks -#cargo audit +cargo audit cargo clippy --no-default-features --all-targets -- -D warnings # Build mirai (in debug mode) so that we can build the standard contracts cargo build --no-default-features