-
Notifications
You must be signed in to change notification settings - Fork 98
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix crash when using public fns reachability #2065
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,7 +18,9 @@ use tracing::{debug, debug_span, trace, warn}; | |
use rustc_data_structures::fingerprint::Fingerprint; | ||
use rustc_data_structures::fx::FxHashSet; | ||
use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; | ||
use rustc_hir::def::DefKind; | ||
use rustc_hir::def_id::DefId; | ||
use rustc_hir::ItemId; | ||
use rustc_middle::mir::interpret::{AllocId, ConstValue, ErrorHandled, GlobalAlloc, Scalar}; | ||
use rustc_middle::mir::mono::MonoItem; | ||
use rustc_middle::mir::visit::Visitor as MirVisitor; | ||
|
@@ -57,18 +59,35 @@ pub fn collect_reachable_items<'tcx>( | |
} | ||
|
||
/// Collect all (top-level) items in the crate that matches the given predicate. | ||
/// An item can only be a root if they are: non-generic Fn / Static / GlobalASM | ||
pub fn filter_crate_items<F>(tcx: TyCtxt, predicate: F) -> Vec<MonoItem> | ||
where | ||
F: FnMut(TyCtxt, DefId) -> bool, | ||
F: Fn(TyCtxt, DefId) -> bool, | ||
{ | ||
let mut filter = predicate; | ||
tcx.hir_crate_items(()) | ||
.items() | ||
.filter_map(|hir_id| { | ||
let def_id = hir_id.owner_id.def_id.to_def_id(); | ||
filter(tcx, def_id).then(|| MonoItem::Fn(Instance::mono(tcx, def_id))) | ||
}) | ||
.collect() | ||
let crate_items = tcx.hir_crate_items(()); | ||
// Filter regular items. | ||
let root_items = crate_items.items().filter_map(|item| { | ||
let def_id = item.owner_id.def_id.to_def_id(); | ||
if !is_generic(tcx, def_id) && predicate(tcx, def_id) { | ||
to_mono_root(tcx, item, def_id) | ||
} else { | ||
None | ||
} | ||
}); | ||
|
||
// Filter items from implementation blocks. | ||
let impl_items = crate_items.impl_items().filter_map(|impl_item| { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That was my initial though, but I was wrong. For harnesses it didn't matter much, since we don't expect associated functions with them, but for other things they might be important. FYI, for the little test I added in this PR, here are the breakdown of items and impl_items:
Ps.: |
||
let def_id = impl_item.owner_id.def_id.to_def_id(); | ||
if matches!(tcx.def_kind(def_id), DefKind::AssocFn) | ||
&& !is_generic(tcx, def_id) | ||
&& predicate(tcx, def_id) | ||
{ | ||
Some(MonoItem::Fn(Instance::mono(tcx, def_id))) | ||
} else { | ||
None | ||
} | ||
}); | ||
root_items.chain(impl_items).collect() | ||
} | ||
|
||
/// Use a predicate to find `const` declarations, then extract all closures from those declarations | ||
|
@@ -96,6 +115,24 @@ where | |
roots | ||
} | ||
|
||
fn is_generic(tcx: TyCtxt, def_id: DefId) -> bool { | ||
let generics = tcx.generics_of(def_id); | ||
generics.requires_monomorphization(tcx) | ||
} | ||
|
||
fn to_mono_root(tcx: TyCtxt, item_id: ItemId, def_id: DefId) -> Option<MonoItem> { | ||
let kind = tcx.def_kind(def_id); | ||
match kind { | ||
DefKind::Static(..) => Some(MonoItem::Static(def_id)), | ||
DefKind::Fn => Some(MonoItem::Fn(Instance::mono(tcx, def_id))), | ||
DefKind::GlobalAsm => Some(MonoItem::GlobalAsm(item_id)), | ||
_ => { | ||
debug!(?def_id, ?kind, "Ignored item. Not a root type."); | ||
None | ||
} | ||
} | ||
} | ||
|
||
struct MonoItemsCollector<'tcx> { | ||
/// The compiler context. | ||
tcx: TyCtxt<'tcx>, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
// Copyright Kani Contributors | ||
// SPDX-License-Identifier: Apache-2.0 OR MIT | ||
// kani-flags: --enable-unstable --function new | ||
//! This ensures our public functions reachability module works for associated functions. | ||
|
||
struct Dummy { | ||
c: char, | ||
} | ||
|
||
impl Dummy { | ||
#[no_mangle] | ||
pub fn new() -> Self { | ||
Dummy { c: ' ' } | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
Checking harness new... | ||
VERIFICATION:- SUCCESSFUL | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
// Copyright Kani Contributors | ||
// SPDX-License-Identifier: Apache-2.0 OR MIT | ||
// kani-flags: --enable-unstable --function harness | ||
//! This test covers an issue we had with our public-fns implementation. | ||
//! We were not checking if a root was a function in the first place. | ||
//! https://github.com/model-checking/kani/issues/2047 | ||
|
||
pub static DAYS_OF_WEEK: [char; 7] = ['s', 'm', 't', 'w', 't', 'f', 's']; | ||
|
||
#[no_mangle] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why not There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Because the bug this change fixes was on how we were collecting starting points for the public functions reachability mode. For the harnesses reachability mode, the predicate only passes for functions. |
||
pub fn harness() { | ||
let day: usize = kani::any(); | ||
kani::assume(day < DAYS_OF_WEEK.len()); | ||
assert!(['s', 'm', 't', 'w', 'f'].contains(&DAYS_OF_WEEK[day])); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use
{gcx.short_crate_name()}
instead, which will be necessary to make clippy happy with the upcoming rust toolchain update.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh, I didn't know you couldn't use expressions. We'll do
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not working for me. I get the following error:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, I was wrong. Expressions cannot be used.