From ba566acebee775439327790cded59508b18d8541 Mon Sep 17 00:00:00 2001 From: Stuart Pernsteiner Date: Mon, 15 May 2023 10:35:38 -0700 Subject: [PATCH 1/6] analyze: implement fixed_signature attribute for testing --- c2rust-analyze/src/main.rs | 51 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/c2rust-analyze/src/main.rs b/c2rust-analyze/src/main.rs index fc34383fc6..3583628547 100644 --- a/c2rust-analyze/src/main.rs +++ b/c2rust-analyze/src/main.rs @@ -25,6 +25,7 @@ use crate::labeled_ty::LabeledTyCtxt; use crate::log::init_logger; use crate::util::Callee; use context::AdtMetadataTable; +use rustc_ast::ast::AttrKind; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_index::vec::IndexVec; @@ -34,10 +35,12 @@ use rustc_middle::mir::{ Rvalue, StatementKind, }; use rustc_middle::ty::{Ty, TyCtxt, TyKind, WithOptConstParam}; +use rustc_span::symbol::Symbol; use rustc_span::Span; use std::collections::{HashMap, HashSet}; use std::env; use std::fmt::{Debug, Display}; +use std::iter; use std::ops::{Deref, DerefMut, Index}; use std::panic::AssertUnwindSafe; @@ -493,6 +496,19 @@ fn run(tcx: TyCtxt) { info.lasn.set(lasn); } + // For testing, putting #[c2rust_analyze_test::fixed_signature] on a function makes all + // pointers in its signature FIXED. + for &ldid in &all_fn_ldids { + if !has_test_attr(tcx, ldid, "fixed_signature") { + continue; + } + let lsig = match gacx.fn_sigs.get(&ldid.to_def_id()) { + Some(x) => x, + None => continue, + }; + make_sig_fixed(&mut gasn, lsig); + } + eprintln!("=== ADT Metadata ==="); eprintln!("{:?}", gacx.adt_metadata); @@ -738,6 +754,21 @@ impl<'tcx> AssignPointerIds<'tcx> for AnalysisCtxt<'_, 'tcx> { } } +fn make_ty_fixed(gasn: &mut GlobalAssignment, lty: LTy) { + for lty in lty.iter() { + let ptr = lty.label; + if !ptr.is_none() { + gasn.flags[ptr].insert(FlagSet::FIXED); + } + } +} + +fn make_sig_fixed(gasn: &mut GlobalAssignment, lsig: &LFnSig) { + for lty in lsig.inputs.iter().copied().chain(iter::once(lsig.output)) { + make_ty_fixed(gasn, lty); + } +} + fn describe_local(tcx: TyCtxt, decl: &LocalDecl) -> String { let mut span = decl.source_info.span; if let Some(ref info) = decl.local_info { @@ -920,6 +951,26 @@ fn for_each_callee(tcx: TyCtxt, ldid: LocalDefId, f: impl FnMut(LocalDefId)) { CalleeVisitor { tcx, mir, f }.visit_body(mir); } +fn has_test_attr(tcx: TyCtxt, ldid: LocalDefId, name: &str) -> bool { + let tool_sym = Symbol::intern("c2rust_analyze_test"); + let name_sym = Symbol::intern(name); + + for attr in tcx.get_attrs_unchecked(ldid.to_def_id()) { + let path = match attr.kind { + AttrKind::Normal(ref item, _) => &item.path, + AttrKind::DocComment(..) => continue, + }; + let (a, b) = match &path.segments[..] { + &[ref a, ref b] => (a, b), + _ => continue, + }; + if a.ident.name == tool_sym && b.ident.name == name_sym { + return true; + } + } + false +} + struct AnalysisCallbacks; impl rustc_driver::Callbacks for AnalysisCallbacks { From 334efc84510bf72f95f7a1b3b8a032b8e1835cad Mon Sep 17 00:00:00 2001 From: Stuart Pernsteiner Date: Mon, 22 May 2023 10:44:12 -0700 Subject: [PATCH 2/6] analyze: add fail_analysis and skip_rewrite attributes for testing --- c2rust-analyze/src/main.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/c2rust-analyze/src/main.rs b/c2rust-analyze/src/main.rs index 3583628547..8915485e68 100644 --- a/c2rust-analyze/src/main.rs +++ b/c2rust-analyze/src/main.rs @@ -23,6 +23,7 @@ use crate::dataflow::DataflowConstraints; use crate::equiv::{GlobalEquivSet, LocalEquivSet}; use crate::labeled_ty::LabeledTyCtxt; use crate::log::init_logger; +use crate::panic_detail::PanicDetail; use crate::util::Callee; use context::AdtMetadataTable; use rustc_ast::ast::AttrKind; @@ -509,6 +510,17 @@ fn run(tcx: TyCtxt) { make_sig_fixed(&mut gasn, lsig); } + // For testing, putting #[c2rust_analyze_test::fail_analysis] on a function marks it as failed. + for &ldid in &all_fn_ldids { + if !has_test_attr(tcx, ldid, "fail_analysis") { + continue; + } + gacx.mark_fn_failed( + ldid.to_def_id(), + PanicDetail::new("explicit fail_analysis for testing".to_owned()), + ); + } + eprintln!("=== ADT Metadata ==="); eprintln!("{:?}", gacx.adt_metadata); @@ -581,6 +593,10 @@ fn run(tcx: TyCtxt) { continue; } + if has_test_attr(tcx, ldid, "skip_rewrite") { + continue; + } + let ldid_const = WithOptConstParam::unknown(ldid); let name = tcx.item_name(ldid.to_def_id()); let mir = tcx.mir_built(ldid_const); From 6435494e0da191e4ed793557b23cdbc00388098a Mon Sep 17 00:00:00 2001 From: Stuart Pernsteiner Date: Wed, 31 May 2023 14:31:10 -0700 Subject: [PATCH 3/6] analyze: refactor has_test_attr and move into util --- c2rust-analyze/src/main.rs | 30 ++++--------------------- c2rust-analyze/src/util.rs | 45 +++++++++++++++++++++++++++++++++++++- 2 files changed, 48 insertions(+), 27 deletions(-) diff --git a/c2rust-analyze/src/main.rs b/c2rust-analyze/src/main.rs index 8915485e68..07167a50db 100644 --- a/c2rust-analyze/src/main.rs +++ b/c2rust-analyze/src/main.rs @@ -24,9 +24,8 @@ use crate::equiv::{GlobalEquivSet, LocalEquivSet}; use crate::labeled_ty::LabeledTyCtxt; use crate::log::init_logger; use crate::panic_detail::PanicDetail; -use crate::util::Callee; +use crate::util::{Callee, TestAttr}; use context::AdtMetadataTable; -use rustc_ast::ast::AttrKind; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_index::vec::IndexVec; @@ -36,7 +35,6 @@ use rustc_middle::mir::{ Rvalue, StatementKind, }; use rustc_middle::ty::{Ty, TyCtxt, TyKind, WithOptConstParam}; -use rustc_span::symbol::Symbol; use rustc_span::Span; use std::collections::{HashMap, HashSet}; use std::env; @@ -500,7 +498,7 @@ fn run(tcx: TyCtxt) { // For testing, putting #[c2rust_analyze_test::fixed_signature] on a function makes all // pointers in its signature FIXED. for &ldid in &all_fn_ldids { - if !has_test_attr(tcx, ldid, "fixed_signature") { + if !util::has_test_attr(tcx, ldid, TestAttr::FixedSignature) { continue; } let lsig = match gacx.fn_sigs.get(&ldid.to_def_id()) { @@ -512,7 +510,7 @@ fn run(tcx: TyCtxt) { // For testing, putting #[c2rust_analyze_test::fail_analysis] on a function marks it as failed. for &ldid in &all_fn_ldids { - if !has_test_attr(tcx, ldid, "fail_analysis") { + if !util::has_test_attr(tcx, ldid, TestAttr::FailAnalysis) { continue; } gacx.mark_fn_failed( @@ -593,7 +591,7 @@ fn run(tcx: TyCtxt) { continue; } - if has_test_attr(tcx, ldid, "skip_rewrite") { + if util::has_test_attr(tcx, ldid, TestAttr::SkipRewrite) { continue; } @@ -967,26 +965,6 @@ fn for_each_callee(tcx: TyCtxt, ldid: LocalDefId, f: impl FnMut(LocalDefId)) { CalleeVisitor { tcx, mir, f }.visit_body(mir); } -fn has_test_attr(tcx: TyCtxt, ldid: LocalDefId, name: &str) -> bool { - let tool_sym = Symbol::intern("c2rust_analyze_test"); - let name_sym = Symbol::intern(name); - - for attr in tcx.get_attrs_unchecked(ldid.to_def_id()) { - let path = match attr.kind { - AttrKind::Normal(ref item, _) => &item.path, - AttrKind::DocComment(..) => continue, - }; - let (a, b) = match &path.segments[..] { - &[ref a, ref b] => (a, b), - _ => continue, - }; - if a.ident.name == tool_sym && b.ident.name == name_sym { - return true; - } - } - false -} - struct AnalysisCallbacks; impl rustc_driver::Callbacks for AnalysisCallbacks { diff --git a/c2rust-analyze/src/util.rs b/c2rust-analyze/src/util.rs index 7988bd576d..7f09b42957 100644 --- a/c2rust-analyze/src/util.rs +++ b/c2rust-analyze/src/util.rs @@ -1,8 +1,9 @@ use crate::labeled_ty::LabeledTy; use crate::trivial::IsTrivial; +use rustc_ast::ast::AttrKind; use rustc_const_eval::interpret::Scalar; use rustc_hir::def::DefKind; -use rustc_hir::def_id::DefId; +use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::mir::{ BasicBlock, BasicBlockData, Constant, Field, Local, Location, Mutability, Operand, Place, PlaceElem, PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, @@ -10,6 +11,7 @@ use rustc_middle::mir::{ use rustc_middle::ty::{ self, AdtDef, DefIdTree, EarlyBinder, Subst, SubstsRef, Ty, TyCtxt, TyKind, UintTy, }; +use rustc_span::symbol::Symbol; use std::fmt::Debug; #[derive(Debug)] @@ -353,3 +355,44 @@ pub fn is_null_const(constant: Constant) -> bool { pub trait PhantomLifetime<'a> {} impl<'a, T: ?Sized> PhantomLifetime<'a> for T {} + +#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)] +pub enum TestAttr { + /// `#[c2rust_analyze_test::fixed_signature]`: Mark all pointers in the function signature as + /// `FIXED`. + FixedSignature, + /// `#[c2rust_analyze_test::fail_analysis]`: Force an analysis failure for the function. + FailAnalysis, + /// `#[c2rust_analyze_test::skip_rewrite]`: Skip generating rewrites for the function. + SkipRewrite, +} + +impl TestAttr { + pub fn name(self) -> &'static str { + match self { + TestAttr::FixedSignature => "fixed_signature", + TestAttr::FailAnalysis => "fail_analysis", + TestAttr::SkipRewrite => "skip_rewrite", + } + } +} + +pub fn has_test_attr(tcx: TyCtxt, ldid: LocalDefId, attr: TestAttr) -> bool { + let tool_sym = Symbol::intern("c2rust_analyze_test"); + let name_sym = Symbol::intern(attr.name()); + + for attr in tcx.get_attrs_unchecked(ldid.to_def_id()) { + let path = match attr.kind { + AttrKind::Normal(ref item, _) => &item.path, + AttrKind::DocComment(..) => continue, + }; + let (a, b) = match &path.segments[..] { + &[ref a, ref b] => (a, b), + _ => continue, + }; + if a.ident.name == tool_sym && b.ident.name == name_sym { + return true; + } + } + false +} From 9adc18065c19b0dfbb987a46b59e9b2882d322f2 Mon Sep 17 00:00:00 2001 From: Stuart Pernsteiner Date: Mon, 5 Jun 2023 11:38:41 -0700 Subject: [PATCH 4/6] analyze: print "final labeling" for #[skip_rewrite] fns --- c2rust-analyze/src/main.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/c2rust-analyze/src/main.rs b/c2rust-analyze/src/main.rs index 07167a50db..df69a55679 100644 --- a/c2rust-analyze/src/main.rs +++ b/c2rust-analyze/src/main.rs @@ -591,10 +591,6 @@ fn run(tcx: TyCtxt) { continue; } - if util::has_test_attr(tcx, ldid, TestAttr::SkipRewrite) { - continue; - } - let ldid_const = WithOptConstParam::unknown(ldid); let name = tcx.item_name(ldid.to_def_id()); let mir = tcx.mir_built(ldid_const); @@ -627,6 +623,10 @@ fn run(tcx: TyCtxt) { eprintln!(); + if util::has_test_attr(tcx, ldid, TestAttr::SkipRewrite) { + continue; + } + let r = panic_detail::catch_unwind(AssertUnwindSafe(|| { let hir_body_id = tcx.hir().body_owned_by(ldid); let expr_rewrites = rewrite::gen_expr_rewrites(&acx, &asn, &mir, hir_body_id); From 557084bb6a88940b8976b8df441383cabc900cbb Mon Sep 17 00:00:00 2001 From: Stuart Pernsteiner Date: Mon, 5 Jun 2023 11:38:59 -0700 Subject: [PATCH 5/6] analyze: add tests/filecheck/test_attrs.rs --- c2rust-analyze/tests/filecheck.rs | 1 + c2rust-analyze/tests/filecheck/test_attrs.rs | 24 ++++++++++++++++++++ 2 files changed, 25 insertions(+) create mode 100644 c2rust-analyze/tests/filecheck/test_attrs.rs diff --git a/c2rust-analyze/tests/filecheck.rs b/c2rust-analyze/tests/filecheck.rs index 51df9b1b6a..4dac1d337f 100644 --- a/c2rust-analyze/tests/filecheck.rs +++ b/c2rust-analyze/tests/filecheck.rs @@ -54,6 +54,7 @@ define_tests! { offset2, ptrptr1, statics, + test_attrs, trivial, type_annotation_rewrite, } diff --git a/c2rust-analyze/tests/filecheck/test_attrs.rs b/c2rust-analyze/tests/filecheck/test_attrs.rs new file mode 100644 index 0000000000..d1280d0016 --- /dev/null +++ b/c2rust-analyze/tests/filecheck/test_attrs.rs @@ -0,0 +1,24 @@ +#![feature(register_tool)] +#![register_tool(c2rust_analyze_test)] + +// CHECK-LABEL: type assignment for "f": +// CHECK: _0 ({{.*}}: *mut i32): *mut i32 +// CHECK: _1 ({{.*}}: x): *mut i32 +#[c2rust_analyze_test::fixed_signature] +fn f(x: *mut i32) -> *mut i32 { + x +} + +// CHECK-LABEL: type assignment for "g": +// CHECK: _0 ({{.*}}: *mut i32): &i32 +// CHECK: _1 ({{.*}}: x): &i32 +#[c2rust_analyze_test::skip_rewrite] +fn g(x: *mut i32) -> *mut i32 { + x +} + +// CHECK: analysis of DefId({{.*}} ~ test_attrs[{{.*}}]::h) failed: [unknown]: explicit fail_analysis for testing +#[c2rust_analyze_test::fail_analysis] +fn h(x: *mut i32) -> *mut i32 { + x +} From efca777ffac8abab5dc0455964b52912d4d5dfba Mon Sep 17 00:00:00 2001 From: spernsteiner Date: Mon, 5 Jun 2023 11:51:00 -0700 Subject: [PATCH 6/6] analyze: apply suggestions from code review Co-authored-by: Khyber Sen --- c2rust-analyze/src/util.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/c2rust-analyze/src/util.rs b/c2rust-analyze/src/util.rs index 7f09b42957..76f9ea8248 100644 --- a/c2rust-analyze/src/util.rs +++ b/c2rust-analyze/src/util.rs @@ -359,7 +359,7 @@ impl<'a, T: ?Sized> PhantomLifetime<'a> for T {} #[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)] pub enum TestAttr { /// `#[c2rust_analyze_test::fixed_signature]`: Mark all pointers in the function signature as - /// `FIXED`. + /// [`FIXED`](crate::context::FlagSet::FIXED). FixedSignature, /// `#[c2rust_analyze_test::fail_analysis]`: Force an analysis failure for the function. FailAnalysis,