Skip to content
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

Unreachable code detection #1385

Open
wants to merge 42 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
9ac293b
Add prusti_refute! macro
Feb 6, 2023
2c4fb37
Merge branch 'master' of github.com:simon-hrabec/prusti-dev into feat…
Feb 15, 2023
c49f9a7
Add macro to generate getters/setters for fields via JNI
Feb 21, 2023
6c3d955
Resolve fmt-check and clippy errors, simplify naming, small refactoring
Feb 21, 2023
bee6c22
Merge branch 'master' of github.com:viperproject/prusti-dev into feat…
Feb 21, 2023
a896d5a
Add test for field! macro
Feb 26, 2023
ec17da5
Update field! macro to not ask for signature (WIP)
Feb 26, 2023
dc8642c
Update field! macro to search all the class hierarchy for the field t…
Feb 27, 2023
019f222
Merge pull request #2 from simon-hrabec/feature/jni-field-getter-sett…
simon-hrabec Feb 27, 2023
608c4aa
Rename variables, add comments, delete leftover commented code
Feb 27, 2023
0c2ecc8
Merge branch 'feature/refute_macro' into combined
Feb 27, 2023
a60bb1e
Merge branch 'master' of github.com:viperproject/prusti-dev into comb…
Feb 27, 2023
542d905
Merge branch 'master' of github.com:viperproject/prusti-dev into comb…
simon-hrabec Feb 27, 2023
667c3b6
Follow update in master branch
simon-hrabec Feb 27, 2023
864c896
current code, just a snapshot of my working dir
simon-hrabec Mar 6, 2023
b9796a6
fix bug with env/ast_utils with_local_frame - calling wrong function
simon-hrabec Mar 13, 2023
a490f2f
Merge branch 'master' of github.com:viperproject/prusti-dev into comb…
simon-hrabec Mar 13, 2023
0d48d5a
add
simon-hrabec Mar 13, 2023
ea965ab
Remove unecessary changes
simon-hrabec Mar 13, 2023
76e0376
additional temporary code removal
simon-hrabec Mar 13, 2023
8117694
Add "refute.failed:refutation.true" into error_manager
simon-hrabec Mar 13, 2023
e6b5692
Remove unnecessary code, fmt-all
simon-hrabec Mar 13, 2023
7443fd2
Merge branch 'master' of github.com:viperproject/prusti-dev into comb…
simon-hrabec Mar 13, 2023
cc7bb62
cargo lock update
simon-hrabec Mar 13, 2023
fc2bda8
add frotend support also for carbon
simon-hrabec Mar 17, 2023
d0ad6a6
add assert.failed:assertion.false-PanicCause::Refute entry to the err…
simon-hrabec Mar 19, 2023
6867a3b
Add field access via Scala methods, use SilFrontend wrapper and remov…
simon-hrabec Mar 20, 2023
0415395
Remove empty line - fmt-all error
simon-hrabec Mar 20, 2023
2695baf
add tests for prusti_refute!
simon-hrabec Mar 21, 2023
a207e10
update docs (user guide) - add mention to refute
simon-hrabec Mar 21, 2023
e6897da
trying to figure out positions for added refutes
simon-hrabec Mar 27, 2023
e71787a
use terminator span
simon-hrabec Mar 28, 2023
31bc7d9
Update unreachable message
simon-hrabec Mar 29, 2023
bdfcd24
delete lefrover code
simon-hrabec Mar 29, 2023
b66210e
make code unreachable errors just warnings
simon-hrabec Apr 3, 2023
7592282
change detection of assert/panic terminators
simon-hrabec Apr 3, 2023
ca94f92
remove unecessary case in the error manager
simon-hrabec Apr 3, 2023
27ecb2e
make line/column numbers unique for code reachability refute statements
simon-hrabec Apr 4, 2023
b9cb939
remove unecessary member variable, use just position id
simon-hrabec Apr 4, 2023
d7deab6
Merge branch 'master' of github.com:viperproject/prusti-dev into feat…
simon-hrabec Apr 4, 2023
5cd88f5
make position manager return positions with unique line/column
simon-hrabec Apr 5, 2023
8433a89
rely on the change in position manager for unique line/column numbers…
simon-hrabec Apr 6, 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
5 changes: 5 additions & 0 deletions docs/dev-guide/src/config/flags.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
| [`CHECK_TIMEOUT`](#check_timeout) | `Option<u32>` | `None` | A |
| [`COUNTEREXAMPLE`](#counterexample) | `bool` | `false` | A |
| [`DELETE_BASIC_BLOCKS`](#delete_basic_blocks) | `Vec<String>` | `vec![]` | A |
| [`DETECT_UNREACHABLE_CODE`](#detect_unreachable_code) | `bool` | `false` | A |
| [`DISABLE_NAME_MANGLING`](#disable_name_mangling) | `bool` | `false` | A |
| [`DUMP_BORROWCK_INFO`](#dump_borrowck_info) | `bool` | `false` | A |
| [`DUMP_DEBUG_INFO`](#dump_debug_info) | `bool` | `false` | A |
Expand Down Expand Up @@ -146,6 +147,10 @@ When enabled, Prusti will try to find and print a counterexample for any failed

The given basic blocks will be replaced with `assume false`.

## `DETECT_UNREACHABLE_CODE`

When enabled, Viper will issue warning for code that cannot be reached.

## `DISABLE_NAME_MANGLING`

When enabled, Viper name mangling will be disabled.
Expand Down
5 changes: 5 additions & 0 deletions prusti-utils/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ lazy_static::lazy_static! {
settings.set_default("use_new_encoder", true).unwrap();
settings.set_default::<Option<u8>>("number_of_parallel_verifiers", None).unwrap();
settings.set_default::<Option<String>>("min_prusti_version", None).unwrap();
settings.set_default("detect_unreachable_code", false).unwrap();

settings.set_default("print_desugared_specs", false).unwrap();
settings.set_default("print_typeckd_specs", false).unwrap();
Expand Down Expand Up @@ -958,6 +959,10 @@ pub fn delete_basic_blocks() -> Vec<String> {
read_setting("delete_basic_blocks")
}

pub fn detect_unreachable_code() -> bool {
read_setting("detect_unreachable_code")
}

/// When enabled, features not supported by Prusti will be reported as warnings
/// rather than errors.
pub fn skip_unsupported_features() -> bool {
Expand Down
6 changes: 3 additions & 3 deletions prusti-viper/src/encoder/encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ use super::high::to_typed::types::HighToTypedTypeEncoderState;

pub struct Encoder<'v, 'tcx: 'v> {
env: &'v Environment<'tcx>,
error_manager: RefCell<ErrorManager<'tcx>>,
error_manager: RefCell<ErrorManager>,
/// A map containing all functions: identifier → function definition.
functions: RefCell<FxHashMap<vir::FunctionIdentifier, Rc<vir::Function>>>,
builtin_domains: RefCell<FxHashMap<BuiltinDomainKind, vir::Domain>>,
Expand Down Expand Up @@ -151,7 +151,7 @@ impl<'v, 'tcx> Encoder<'v, 'tcx> {

Encoder {
env,
error_manager: RefCell::new(ErrorManager::new(env.query.codemap())),
error_manager: RefCell::new(ErrorManager::default()),
functions: RefCell::new(FxHashMap::default()),
builtin_domains: RefCell::new(FxHashMap::default()),
builtin_domains_in_progress: RefCell::new(FxHashSet::default()),
Expand Down Expand Up @@ -228,7 +228,7 @@ impl<'v, 'tcx> Encoder<'v, 'tcx> {
self.env
}

pub fn error_manager(&self) -> RefMut<ErrorManager<'tcx>> {
pub fn error_manager(&self) -> RefMut<ErrorManager> {
self.error_manager.borrow_mut()
}

Expand Down
23 changes: 10 additions & 13 deletions prusti-viper/src/encoder/errors/error_manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ use std::fmt::Debug;

use vir_crate::polymorphic::Position;
use rustc_hash::FxHashMap;
use prusti_rustc_interface::span::source_map::SourceMap;
use prusti_rustc_interface::errors::MultiSpan;
use viper::VerificationError;
use prusti_interface::PrustiError;
Expand Down Expand Up @@ -188,25 +187,19 @@ pub enum ErrorCtxt {
/// The state that fold-unfold algorithm deduced as unreachable, is actually
/// reachable.
UnreachableFoldingState,
/// Raised when DETECT_UNREACHABLE_CODE is enabled and an code is determined as unreachable.
UnreachableCode,
}

/// The error manager
#[derive(Clone)]
pub struct ErrorManager<'tcx> {
position_manager: PositionManager<'tcx>,
#[derive(Clone, Default)]
pub struct ErrorManager {
position_manager: PositionManager,
error_contexts: FxHashMap<u64, ErrorCtxt>,
inner_positions: FxHashMap<u64, Position>,
}

impl<'tcx> ErrorManager<'tcx> {
pub fn new(codemap: &'tcx SourceMap) -> Self {
ErrorManager {
position_manager: PositionManager::new(codemap),
error_contexts: FxHashMap::default(),
inner_positions: FxHashMap::default(),
}
}

impl ErrorManager {
pub fn position_manager(&self) -> &PositionManager {
&self.position_manager
}
Expand Down Expand Up @@ -705,6 +698,10 @@ impl<'tcx> ErrorManager<'tcx> {
)
}

("refute.failed:refutation.true", ErrorCtxt::UnreachableCode) => {
PrustiError::warning("Detected unreachable code", error_span)
}

(full_err_id, ErrorCtxt::Unexpected) => {
PrustiError::internal(
format!(
Expand Down
42 changes: 7 additions & 35 deletions prusti-viper/src/encoder/errors/position_manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,69 +8,41 @@ use std::fmt::Debug;

use vir_crate::polymorphic::Position;
use rustc_hash::FxHashMap;
use prusti_rustc_interface::span::source_map::SourceMap;
use prusti_rustc_interface::errors::MultiSpan;
use log::debug;
use prusti_interface::data::ProcedureDefId;

/// Mapping from VIR positions to the source code that generated them.
/// One VIR position can be involved in multiple errors. If an error needs to refer to a special
/// span, that should be done by adding the span to `ErrorCtxt`, not by registering a new span.
#[derive(Clone)]
pub struct PositionManager<'tcx> {
codemap: &'tcx SourceMap,
pub struct PositionManager {
next_pos_id: u64,
/// The def_id of the procedure that generated the given VIR position.
pub(crate) def_id: FxHashMap<u64, ProcedureDefId>,
/// The span of the source code that generated the given VIR position.
pub(crate) source_span: FxHashMap<u64, MultiSpan>,
}

impl<'tcx> PositionManager<'tcx>
{
pub fn new(codemap: &'tcx SourceMap) -> Self {
impl Default for PositionManager {
fn default() -> Self {
PositionManager {
codemap,
next_pos_id: 1,
def_id: FxHashMap::default(),
source_span: FxHashMap::default(),
}
}
}

impl PositionManager
{
#[tracing::instrument(level = "trace", skip(self), ret)]
pub fn register_span<T: Into<MultiSpan> + Debug>(&mut self, def_id: ProcedureDefId, span: T) -> Position {
let span = span.into();
let pos_id = self.next_pos_id;
self.next_pos_id += 1;

let pos = if let Some(primary_span) = span.primary_span() {
let lines_info_res = self
.codemap
.span_to_lines(primary_span.source_callsite());
match lines_info_res {
Ok(lines_info) => {
if let Some(first_line_info) = lines_info.lines.get(0) {
let line = first_line_info.line_index as i32 + 1;
let column = first_line_info.start_col.0 as i32 + 1;
Position::new(line, column, pos_id)
} else {
debug!("Primary span of position id {} has no lines", pos_id);
Position::new(0, 0, pos_id)
}
}
Err(e) => {
debug!("Error converting primary span of position id {} to lines: {:?}", pos_id, e);
Position::new(0, 0, pos_id)
}
}
} else {
debug!("Position id {} has no primary span", pos_id);
Position::new(0, 0, pos_id)
};

self.def_id.insert(pos_id, def_id);
self.source_span.insert(pos_id, span);
pos
Position::new(pos_id as i32, 0, pos_id)
}

pub fn duplicate(&mut self, pos: Position) -> Position {
Expand Down
41 changes: 41 additions & 0 deletions prusti-viper/src/encoder/procedure_encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1257,6 +1257,47 @@ impl<'p, 'v: 'p, 'tcx: 'v> ProcedureEncoder<'p, 'v, 'tcx> {
);
}

if config::detect_unreachable_code() {
let bb_data = &self.mir.basic_blocks[bbi];
let statements: &Vec<mir::Statement<'tcx>> = &bb_data.statements;

let panic_free = match &bb_data.terminator().kind {
TerminatorKind::Unreachable => false,
TerminatorKind::Assert { .. } => false,
TerminatorKind::Call {
func:
mir::Operand::Constant(box mir::Constant {
literal,
..
}),
..
} => {
if let ty::TyKind::FnDef(called_def_id, _call_substs) = literal.ty().kind() {
let full_func_proc_name: &str =
&self.encoder.env().name.get_absolute_item_name(*called_def_id);

!matches!(full_func_proc_name, "std::rt::begin_panic" | "core::panicking::panic" | "core::panicking::panic_fmt")
} else {
true
}
}
_ => true,
};

if !statements.is_empty() && panic_free {
let location = mir::Location {
block: bbi,
statement_index: 0,
};
let span = self.mir_encoder.get_span_of_location(location);
let expr_position = self.mir_encoder.register_span(span);
let stmt_position = self.register_error(span, ErrorCtxt::UnreachableCode);
let refute_expr = vir::ast::Expr::Const(vir_crate::polymorphic::ConstExpr{value: vir_crate::polymorphic::Const::Bool(false), position: expr_position});
let refute_stmt = vir::Stmt::Refute(vir::Refute {expr: refute_expr, position: stmt_position});
self.cfg_method.add_stmt(curr_block, refute_stmt);
}
}

self.encode_execution_flag(bbi, curr_block)?;
let opt_successor = self.encode_block_statements(bbi, curr_block)?;
let mir_successor: MirSuccessor = if let Some(successor) = opt_successor {
Expand Down
3 changes: 2 additions & 1 deletion prusti/src/verifier.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,8 @@ pub fn verify(env: Environment<'_>, def_spec: typed::DefSpecificationMap) {
env.diagnostic.has_errors()
|| config::internal_errors_as_warnings()
|| (config::skip_unsupported_features()
&& config::allow_unreachable_unsupported_code())
&& config::allow_unreachable_unsupported_code()
|| config::detect_unreachable_code())
);
}
};
Expand Down