Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
45bbc53
analyze: keep a copy of the callgraph in GlobalAnalysisCtxt
spernsteiner Mar 16, 2023
e284b8f
analyze: catch panics during analysis and recover
spernsteiner Mar 16, 2023
dbdf047
analyze: handle panics around rewriting
spernsteiner Mar 28, 2023
f9a28ac
analyze: report caught panics in more detail
spernsteiner Mar 28, 2023
e75a6cf
analyze: fix warnings
spernsteiner Mar 29, 2023
7ac897d
analyze: PanicDetail: use primary loc if no relevant loc is found
spernsteiner Mar 29, 2023
4a9fdce
analyze: add comments around panic recovery
spernsteiner Mar 29, 2023
540a7b0
analyze: include source span in panic messages when available
spernsteiner Mar 29, 2023
5d03754
analyze: Apply suggestions from code review
spernsteiner May 3, 2023
79f855b
analyze: panic_detail: rename `sp` to `span`
spernsteiner May 3, 2023
9298e0d
analyze: add panic_detail::catch_unwind wrapper
spernsteiner May 3, 2023
f3cb046
analyze: panic_detail: call default panic hook when not in catch_unwind
spernsteiner May 3, 2023
cbf6dc1
analyze: add "bad function calls good function" case in catch_panic test
spernsteiner May 3, 2023
4aeccba
analyze: panic_detail: panic instead of warn! on double unwind
spernsteiner May 5, 2023
f84d0ba
analyze: apply suggestion from code review
spernsteiner May 5, 2023
24b9284
analyze: panic_detail: provide a panic_detail::set_hook function
spernsteiner May 5, 2023
ce24f38
analyze: panic_unwind: fix stale inter-doc link
spernsteiner May 5, 2023
172808d
analyze: don't catch panics when running certain tests
spernsteiner May 9, 2023
176ecb1
analyze: rename env var to C2RUST_ANALYZE_TEST_DONT_CATCH_PANIC
spernsteiner May 18, 2023
47ebc33
analyze: disable panic catching in all tests except catch_panic.rs
spernsteiner May 18, 2023
cd9d001
analyze: only catch panics if panic_detail hook is set
spernsteiner May 22, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions c2rust-analyze/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ assert_matches = "1.5.0"
indexmap = "1.9.2"
env_logger = "0.10.0"
log = "0.4.17"
backtrace = "0.3.67"

[build-dependencies]
c2rust-build-paths = { path = "../c2rust-build-paths", version = "0.18.0" }
Expand Down
3 changes: 3 additions & 0 deletions c2rust-analyze/src/borrowck/type_check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use crate::borrowck::atoms::{AllFacts, AtomMaps, Loan, Origin, Path, Point, SubP
use crate::borrowck::{construct_adt_origins, LTy, LTyCtxt, Label, OriginParam};
use crate::c_void_casts::CVoidCasts;
use crate::context::PermissionSet;
use crate::panic_detail;
use crate::util::{self, ty_callee, Callee};
use crate::AdtMetadataTable;
use assert_matches::assert_matches;
Expand Down Expand Up @@ -429,6 +430,7 @@ impl<'tcx> TypeChecker<'tcx, '_> {
}

pub fn visit_statement(&mut self, stmt: &Statement<'tcx>) {
let _g = panic_detail::set_current_span(stmt.source_info.span);
// TODO(spernsteiner): other `StatementKind`s will be handled in the future
#[allow(clippy::single_match)]
match stmt.kind {
Expand All @@ -445,6 +447,7 @@ impl<'tcx> TypeChecker<'tcx, '_> {

pub fn visit_terminator(&mut self, term: &Terminator<'tcx>) {
eprintln!("borrowck: visit_terminator({:?})", term.kind);
let _g = panic_detail::set_current_span(term.source_info.span);
// TODO(spernsteiner): other `TerminatorKind`s will be handled in the future
#[allow(clippy::single_match)]
match term.kind {
Expand Down
32 changes: 32 additions & 0 deletions c2rust-analyze/src/context.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::borrowck::{AdtMetadata, FieldMetadata, OriginArg, OriginParam};
use crate::c_void_casts::CVoidCasts;
use crate::labeled_ty::{LabeledTy, LabeledTyCtxt};
use crate::panic_detail::PanicDetail;
use crate::pointer_id::{
GlobalPointerTable, LocalPointerTable, NextGlobalPointerId, NextLocalPointerId, PointerTable,
PointerTableMut,
Expand Down Expand Up @@ -272,7 +273,13 @@ pub struct GlobalAnalysisCtxt<'tcx> {

ptr_info: GlobalPointerTable<PointerInfo>,

/// Map from a function to all of its callers.
pub fn_callers: HashMap<DefId, Vec<DefId>>,

pub fn_sigs: HashMap<DefId, LFnSig<'tcx>>,
/// `DefId`s of functions where analysis failed, and a [`PanicDetail`] explaining the reason
/// for each failure.
pub fns_failed: HashMap<DefId, PanicDetail>,

pub field_ltys: HashMap<DefId, LTy<'tcx>>,

Expand Down Expand Up @@ -522,7 +529,9 @@ impl<'tcx> GlobalAnalysisCtxt<'tcx> {
tcx,
lcx: LabeledTyCtxt::new(tcx),
ptr_info: GlobalPointerTable::empty(),
fn_callers: HashMap::new(),
fn_sigs: HashMap::new(),
fns_failed: HashMap::new(),
field_ltys: HashMap::new(),
static_tys: HashMap::new(),
addr_of_static: HashMap::new(),
Expand Down Expand Up @@ -566,7 +575,9 @@ impl<'tcx> GlobalAnalysisCtxt<'tcx> {
tcx: _,
lcx,
ref mut ptr_info,
fn_callers: _,
ref mut fn_sigs,
fns_failed: _,
ref mut field_ltys,
ref mut static_tys,
ref mut addr_of_static,
Expand Down Expand Up @@ -620,6 +631,27 @@ impl<'tcx> GlobalAnalysisCtxt<'tcx> {
self.assign_pointer_to_field(field);
}
}

pub fn fn_failed(&mut self, did: DefId) -> bool {
self.fns_failed.contains_key(&did)
}

pub fn mark_fn_failed(&mut self, did: DefId, detail: PanicDetail) {
if self.fns_failed.contains_key(&did) {
return;
}

self.fns_failed.insert(did, detail);

// This is the first time marking `did` as failed, so also mark all of its callers.
let callers = self.fn_callers.get(&did).cloned().unwrap_or(Vec::new());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
let callers = self.fn_callers.get(&did).cloned().unwrap_or(Vec::new());
let callers = self.fn_callers.get(&did).cloned().unwrap_or_default();

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This only removes a type hint that might be useful for the reader.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a clippy::or_fun_call warning. I don't see a good reason not to follow it. The fact that it's Vec isn't important here.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a false positive in Clippy. "This is only bad if it allocates or does some non-trivial amount of work," but "The lint also cannot figure out whether the function you call is actually expensive to call or not." In this case the function being called is const, so it doesn't need to do any run-time work at all. The lint in question has also been downgraded to allow-by-default due to the high rate of false positives.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one is a slightly different warning. When it suggests using a closure that calls a const fn, that is more of a false warning as you were saying, but in this case, .unwrap_or_default() is functionally different (I'm surprised it falls under the same clippy lint, as it's quite different). Using Default::default() for this is more semantically clear (we don't care that it's actually Vec::new(), but that it's the default, empty container). We could conceivably change it to ThinVec, Box<[T]>, IndexSet, etc., in which case the .unwrap_or_default() wouldn't need to be changed since it's the same semantic logic.

That said, I don't really want to spend time debating the merits of clippy lints. I think we should just do what clippy says here. There's no major reason not to, and using Default here is more semantically specific.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should just do what clippy says here. There's no major reason not to

There's no good reason to make this change. The fact that Clippy suggested it isn't a good reason on its own, because Clippy often gives bad advice. (Any clippy lints that do regularly give good advice tend to get uplifted into rustc.)

The fact that it's Vec isn't important here.

I disagree. Knowing the type of xs is useful for knowing what you'll get if you do for x in xs.

As far as I know, the official policy for this repo does not require the code to be clippy-clean. Unless that changes (which I would oppose), I don't see any value in making the code (very slightly) worse just to appease the tool.

for caller in callers {
self.mark_fn_failed(
caller,
PanicDetail::new(format!("analysis failed on callee {:?}", did)),
);
}
}
}

impl<'a, 'tcx> AnalysisCtxt<'a, 'tcx> {
Expand Down
5 changes: 4 additions & 1 deletion c2rust-analyze/src/dataflow/type_check.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use super::DataflowConstraints;
use crate::c_void_casts::CVoidCastDirection;
use crate::context::{AnalysisCtxt, LTy, PermissionSet, PointerId};
use crate::panic_detail;
use crate::util::{describe_rvalue, is_null_const, ty_callee, Callee, RvalueDesc};
use assert_matches::assert_matches;
use rustc_hir::def_id::DefId;
Expand Down Expand Up @@ -317,11 +318,12 @@ impl<'tcx> TypeChecker<'tcx, '_> {

pub fn visit_statement(&mut self, stmt: &Statement<'tcx>, loc: Location) {
eprintln!("visit_statement({:?})", stmt);

if self.acx.c_void_casts.should_skip_stmt(loc) {
return;
}

let _g = panic_detail::set_current_span(stmt.source_info.span);

// TODO(spernsteiner): other `StatementKind`s will be handled in the future
#[allow(clippy::single_match)]
match stmt.kind {
Expand All @@ -342,6 +344,7 @@ impl<'tcx> TypeChecker<'tcx, '_> {
pub fn visit_terminator(&mut self, term: &Terminator<'tcx>, loc: Location) {
eprintln!("visit_terminator({:?})", term.kind);
let tcx = self.acx.tcx();
let _g = panic_detail::set_current_span(term.source_info.span);
// TODO(spernsteiner): other `TerminatorKind`s will be handled in the future
#[allow(clippy::single_match)]
match term.kind {
Expand Down
Loading