Skip to content

Commit 39f9c87

Browse files
author
Remi Delmas
committed
CONTRACTS: don't instrument __CPROVER_dead_object anymore.
This change fixes spurious violations on GOTO models generated from MIR programs by Kani. MIR programs declare all stack-allocated place variables at the top of the function regardless of the original scope of the variable, and uses `storageLive` and `storageDead` events to delimit their dynamic lifetime. Kani uses a DECL to introduce place variables and uses dynamic assignments to `__CPROVER_dead_object` to encode `storageLive` and `storageDead`. DFCC instrumentation would only pick up `storageDead` events, not `storageLive`, resulting in spurious proof failures. With this change we go back to relying only on DECL/DEAD for object liftetime tracking in DFCC and completely ignoring dynamic assignments `__CPROVER_dead_object`. This means that contract instrumentation won't be able to detect bad accesses to objects for which the lifetime is managed via `__CPROVER_dead_object`, for intance: dynamic stack-allocated objects created using `alloca`, or MIR place variables as encoded by Kani. As a consequence `--pointer-checks` have to be enabled when analysing contracts-instrumented code.
1 parent b3e9976 commit 39f9c87

File tree

2 files changed

+0
-69
lines changed

2 files changed

+0
-69
lines changed

src/goto-instrument/contracts/dynamic-frames/dfcc_instrument.cpp

Lines changed: 0 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -735,31 +735,6 @@ void dfcc_instrumentt::instrument_lhs(
735735
insert_before_swap_and_advance(goto_program, target, payload);
736736
}
737737

738-
/// Checks if lhs is the `dead_object`, and if the rhs
739-
/// is an `if_exprt(nondet, ptr, dead_object)` expression.
740-
/// Returns `ptr` if the pattern was matched, nullptr otherwise.
741-
std::optional<exprt>
742-
dfcc_instrumentt::is_dead_object_update(const exprt &lhs, const exprt &rhs)
743-
{
744-
if(
745-
lhs.id() == ID_symbol &&
746-
to_symbol_expr(lhs).get_identifier() == CPROVER_PREFIX "dead_object" &&
747-
rhs.id() == ID_if)
748-
{
749-
// only handle `if_exprt(nondet, ptr, dead_object)`
750-
auto &if_expr = to_if_expr(rhs);
751-
if(
752-
if_expr.cond().id() == ID_side_effect &&
753-
to_side_effect_expr(if_expr.cond()).get_statement() == ID_nondet &&
754-
if_expr.false_case() == lhs)
755-
{
756-
return if_expr.true_case();
757-
}
758-
}
759-
760-
return {};
761-
}
762-
763738
void dfcc_instrumentt::instrument_assign(
764739
const irep_idt &function_id,
765740
goto_programt::targett &target,
@@ -775,43 +750,6 @@ void dfcc_instrumentt::instrument_assign(
775750
if(cfg_info.must_check_lhs(target))
776751
instrument_lhs(function_id, target, lhs, goto_program, cfg_info);
777752

778-
// handle dead_object updates (created by __builtin_alloca for instance)
779-
// Remark: we do not really need to track this deallocation since the default
780-
// CBMC checks are already able to detect writes to DEAD objects
781-
const auto dead_ptr = is_dead_object_update(lhs, rhs);
782-
if(dead_ptr.has_value())
783-
{
784-
// ```
785-
// ASSIGN dead_object := if_exprt(nondet, ptr, dead_object);
786-
// ----
787-
// IF !write_set GOTO skip_target;
788-
// CALL record_deallocated(write_set, ptr);
789-
// skip_target: SKIP;
790-
// ```
791-
792-
// step over the instruction
793-
target++;
794-
795-
goto_programt payload;
796-
797-
auto goto_instruction = payload.add(goto_programt::make_incomplete_goto(
798-
dfcc_utilst::make_null_check_expr(write_set), target_location));
799-
800-
payload.add(goto_programt::make_function_call(
801-
library.write_set_record_dead_call(
802-
write_set, dead_ptr.value(), target_location),
803-
target_location));
804-
805-
auto label_instruction =
806-
payload.add(goto_programt::make_skip(target_location));
807-
goto_instruction->complete_goto(label_instruction);
808-
809-
insert_before_swap_and_advance(goto_program, target, payload);
810-
811-
// step back
812-
target--;
813-
}
814-
815753
// is the rhs expression a side_effect("allocate") expression ?
816754
if(rhs.id() == ID_side_effect && rhs.get(ID_statement) == ID_allocate)
817755
{

src/goto-instrument/contracts/dynamic-frames/dfcc_instrument.h

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -283,13 +283,6 @@ class dfcc_instrumentt
283283
goto_programt &goto_program,
284284
dfcc_cfg_infot &cfg_info);
285285

286-
/// Checks if \p lhs is the `dead_object`, and if \p rhs
287-
/// is an `if_exprt(nondet, ptr, dead_object)` expression.
288-
/// Returns a pointer to the `ptr` expression if the pattern was matched,
289-
/// returns `nullptr` otherwise.
290-
std::optional<exprt>
291-
is_dead_object_update(const exprt &lhs, const exprt &rhs);
292-
293286
/// Instrument the \p lhs of an `ASSIGN lhs := rhs` instruction by
294287
/// adding an inclusion check of \p lhs in \p write_set.
295288
/// If \ref is_dead_object_update returns a successful match, the matched

0 commit comments

Comments
 (0)