Skip to content

Commit d015c9d

Browse files
committed
Move rw_ok rewriting to separate pass
This reverts selected changes from "r/w/rw_ok and pointer_in_range depend on deallocated and dead_object" for transformations of goto programs can now safely introduce rw_ok expressions into the goto program. Not all analyses, however, are able to cope with these expressions. Dependence graphs (and any analyses building upon these), for example, also require this rewriting. goto-instrument is adjusted accordingly.
1 parent a9ad0be commit d015c9d

File tree

16 files changed

+130
-68
lines changed

16 files changed

+130
-68
lines changed

regression/cbmc/realloc-should-not-free-on-failure-to-allocate/test.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
CORE new-smt-backend
22
test.c
33
--malloc-may-fail --malloc-fail-null
4-
^\[free.precondition.\d+] line \d+ double free: SUCCESS$
4+
^\[main.precondition_instance.\d+] line \d+ double free: SUCCESS$
55
^VERIFICATION SUCCESSFUL$
66
^EXIT=0$
77
^SIGNAL=0$

regression/goto-cc-goto-analyzer/instrument_preconditions_locations/test.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ test.c
44
^EXIT=0$
55
^SIGNAL=0$
66
Checking assertions
7-
^\[free.precondition.1\] line \d+ free argument must be NULL or valid pointer: SUCCESS
7+
^\[EVP_MD_CTX_free.precondition_instance.1\] line \d+ free argument must be NULL or valid pointer: SUCCESS
88
--
99
Invariant check failed
1010
--

src/cbmc/cbmc_parse_options.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -406,6 +406,7 @@ void cbmc_parse_optionst::get_command_line_options(optionst &options)
406406
PARSE_OPTIONS_GOTO_TRACE(cmdline, options);
407407

408408
// Options for process_goto_program
409+
options.set_option("rewrite-rw-ok", true);
409410
options.set_option("rewrite-union", true);
410411

411412
if(cmdline.isset("smt1"))

src/cprover/state_encoding.cpp

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -294,20 +294,6 @@ exprt state_encodingt::evaluate_expr_rec(
294294
: ID_state_rw_ok;
295295
return ternary_exprt(new_id, state, pointer, size, what.type());
296296
}
297-
else if(
298-
const auto r_or_w_ok_expr =
299-
expr_try_dynamic_cast<prophecy_r_or_w_ok_exprt>(what))
300-
{
301-
// we replace prophecy expressions by our state
302-
auto pointer =
303-
evaluate_expr_rec(loc, state, r_or_w_ok_expr->pointer(), bound_symbols);
304-
auto size =
305-
evaluate_expr_rec(loc, state, r_or_w_ok_expr->size(), bound_symbols);
306-
auto new_id = what.id() == ID_prophecy_r_ok ? ID_state_r_ok
307-
: what.id() == ID_prophecy_w_ok ? ID_state_w_ok
308-
: ID_state_rw_ok;
309-
return ternary_exprt(new_id, state, pointer, size, what.type());
310-
}
311297
else if(what.id() == ID_is_cstring)
312298
{
313299
// we need to add the state

src/goto-analyzer/goto_analyzer_parse_options.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,7 @@ int goto_analyzer_parse_optionst::doit()
393393

394394
// Preserve backwards compatibility in processing
395395
options.set_option("partial-inline", true);
396+
options.set_option("rewrite-rw-ok", false);
396397
options.set_option("rewrite-union", false);
397398
options.set_option("remove-returns", true);
398399

src/goto-diff/goto_diff_parse_options.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ void goto_diff_parse_optionst::get_command_line_options(optionst &options)
6565
options.set_option("show-properties", cmdline.isset("show-properties"));
6666

6767
// Options for process_goto_program
68+
options.set_option("rewrite-rw-ok", false);
6869
options.set_option("rewrite-union", true);
6970
}
7071

src/goto-instrument/contracts/instrument_spec_assigns.cpp

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -644,13 +644,9 @@ exprt instrument_spec_assignst::target_validity_expr(
644644
// (or is NULL if we allow it explicitly).
645645
// This assertion will be falsified whenever `start_address` is invalid or
646646
// not of the right size (or is NULL if we do not allow it explicitly).
647-
symbol_exprt deallocated =
648-
ns.lookup(CPROVER_PREFIX "deallocated").symbol_expr();
649-
symbol_exprt dead = ns.lookup(CPROVER_PREFIX "dead_object").symbol_expr();
650-
auto result = or_exprt{
651-
not_exprt{car.condition()},
652-
prophecy_w_ok_exprt{
653-
car.target_start_address(), car.target_size(), deallocated, dead}};
647+
auto result =
648+
or_exprt{not_exprt{car.condition()},
649+
w_ok_exprt{car.target_start_address(), car.target_size()}};
654650

655651
if(allow_null_target)
656652
result.add_to_operands(null_object(car.target_start_address()));

src/goto-instrument/contracts/utils.cpp

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -178,11 +178,7 @@ exprt all_dereferences_are_valid(const exprt &expr, const namespacet &ns)
178178
const auto size_of_expr_opt = size_of_expr(expr.type(), ns);
179179
CHECK_RETURN(size_of_expr_opt.has_value());
180180

181-
symbol_exprt deallocated =
182-
ns.lookup(CPROVER_PREFIX "deallocated").symbol_expr();
183-
symbol_exprt dead = ns.lookup(CPROVER_PREFIX "dead_object").symbol_expr();
184-
validity_checks.push_back(prophecy_r_ok_exprt{
185-
deref->pointer(), *size_of_expr_opt, deallocated, dead});
181+
validity_checks.push_back(r_ok_exprt{deref->pointer(), *size_of_expr_opt});
186182
}
187183

188184
for(const auto &op : expr.operands())

src/goto-instrument/goto_instrument_parse_options.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ Author: Daniel Kroening, [email protected]
4545
#include <goto-programs/remove_unused_functions.h>
4646
#include <goto-programs/remove_virtual_functions.h>
4747
#include <goto-programs/restrict_function_pointers.h>
48+
#include <goto-programs/rewrite_rw_ok.h>
4849
#include <goto-programs/rewrite_union.h>
4950
#include <goto-programs/set_properties.h>
5051
#include <goto-programs/show_properties.h>
@@ -569,6 +570,7 @@ int goto_instrument_parse_optionst::doit()
569570
if(cmdline.isset("show-reaching-definitions"))
570571
{
571572
do_indirect_call_and_rtti_removal();
573+
rewrite_rw_ok(goto_model);
572574

573575
const namespacet ns(goto_model.symbol_table);
574576
reaching_definitions_analysist rd_analysis(ns);
@@ -581,6 +583,7 @@ int goto_instrument_parse_optionst::doit()
581583
if(cmdline.isset("show-dependence-graph"))
582584
{
583585
do_indirect_call_and_rtti_removal();
586+
rewrite_rw_ok(goto_model);
584587

585588
const namespacet ns(goto_model.symbol_table);
586589
dependence_grapht dependence_graph(ns);
@@ -1767,6 +1770,7 @@ void goto_instrument_parse_optionst::instrument_goto_program()
17671770
{
17681771
do_indirect_call_and_rtti_removal();
17691772
do_remove_returns();
1773+
rewrite_rw_ok(goto_model);
17701774

17711775
log.warning() << "**** WARNING: Experimental option --full-slice, "
17721776
<< "analysis results may be unsound. See "

src/goto-programs/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ SRC = allocate_objects.cpp \
5656
remove_vector.cpp \
5757
remove_virtual_functions.cpp \
5858
restrict_function_pointers.cpp \
59+
rewrite_rw_ok.cpp \
5960
rewrite_union.cpp \
6061
resolve_inherited_component.cpp \
6162
safety_checker.cpp \

src/goto-programs/builtin_functions.cpp

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -669,10 +669,7 @@ void goto_convertt::do_havoc_slice(
669669
// char nondet_contents[argument[1]];
670670
// __CPROVER_array_replace(p, nondet_contents);
671671

672-
symbol_exprt deallocated =
673-
ns.lookup(CPROVER_PREFIX "deallocated").symbol_expr();
674-
symbol_exprt dead = ns.lookup(CPROVER_PREFIX "dead_object").symbol_expr();
675-
prophecy_w_ok_exprt ok_expr{arguments[0], arguments[1], deallocated, dead};
672+
r_or_w_ok_exprt ok_expr(ID_w_ok, arguments[0], arguments[1]);
676673
ok_expr.add_source_location() = source_location;
677674
source_locationt annotated_location = source_location;
678675
annotated_location.set("user-provided", false);

src/goto-programs/goto_clean_expr.cpp

Lines changed: 0 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ Author: Daniel Kroening, [email protected]
1111

1212
#include "goto_convert_class.h"
1313

14-
#include <util/cprover_prefix.h>
1514
#include <util/expr_util.h>
1615
#include <util/fresh_symbol.h>
1716
#include <util/pointer_expr.h>
@@ -74,15 +73,6 @@ bool goto_convertt::needs_cleaning(const exprt &expr)
7473
return true;
7574
}
7675

77-
// Rewrite rw_ok and pointer_in_range front-end expressions into ones
78-
// including prophecy expressions.
79-
if(
80-
can_cast_expr<r_or_w_ok_exprt>(expr) ||
81-
can_cast_expr<pointer_in_range_exprt>(expr))
82-
{
83-
return true;
84-
}
85-
8676
// We can't flatten quantified expressions by introducing new literals for
8777
// conditional expressions. This is because the body of the quantified
8878
// may refer to bound variables, which are not visible outside the scope
@@ -446,32 +436,6 @@ void goto_convertt::clean_expr(
446436
expr.operands().size() == 1, "ID_compound_literal has a single operand");
447437
expr = to_unary_expr(expr).op();
448438
}
449-
else if(auto r_or_w_ok = expr_try_dynamic_cast<r_or_w_ok_exprt>(expr))
450-
{
451-
const auto &id = expr.id();
452-
expr =
453-
prophecy_r_or_w_ok_exprt{
454-
id == ID_r_ok ? ID_prophecy_r_ok
455-
: id == ID_w_ok ? ID_prophecy_w_ok
456-
: ID_prophecy_rw_ok,
457-
r_or_w_ok->pointer(),
458-
r_or_w_ok->size(),
459-
ns.lookup(CPROVER_PREFIX "deallocated").symbol_expr(),
460-
ns.lookup(CPROVER_PREFIX "dead_object").symbol_expr()}
461-
.with_source_location<exprt>(expr);
462-
}
463-
else if(
464-
auto pointer_in_range = expr_try_dynamic_cast<pointer_in_range_exprt>(expr))
465-
{
466-
expr =
467-
prophecy_pointer_in_range_exprt{
468-
pointer_in_range->lower_bound(),
469-
pointer_in_range->pointer(),
470-
pointer_in_range->upper_bound(),
471-
ns.lookup(CPROVER_PREFIX "deallocated").symbol_expr(),
472-
ns.lookup(CPROVER_PREFIX "dead_object").symbol_expr()}
473-
.with_source_location<exprt>(expr);
474-
}
475439
}
476440

477441
void goto_convertt::clean_expr_address_of(

src/goto-programs/process_goto_program.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ Author: Martin Brain, [email protected]
2323
#include <goto-programs/remove_function_pointers.h>
2424
#include <goto-programs/remove_returns.h>
2525
#include <goto-programs/remove_vector.h>
26+
#include <goto-programs/rewrite_rw_ok.h>
2627
#include <goto-programs/rewrite_union.h>
2728
#include <goto-programs/string_abstraction.h>
2829
#include <goto-programs/string_instrumentation.h>
@@ -70,6 +71,9 @@ bool process_goto_program(
7071
if(options.get_bool_option("rewrite-union"))
7172
rewrite_union(goto_model);
7273

74+
if(options.get_bool_option("rewrite-rw-ok"))
75+
rewrite_rw_ok(goto_model);
76+
7377
// add generic checks
7478
log.status() << "Generic Property Instrumentation" << messaget::eom;
7579
goto_check_c(options, goto_model, log.get_message_handler());

src/goto-programs/rewrite_rw_ok.cpp

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
/*******************************************************************\
2+
3+
Module: Rewrite {r,w,rw}_ok expressions as required by symbolic execution
4+
5+
Author: Michael Tautschnig
6+
7+
\*******************************************************************/
8+
9+
#include "rewrite_rw_ok.h"
10+
11+
#include <util/expr_iterator.h>
12+
#include <util/pointer_expr.h>
13+
14+
#include <goto-programs/goto_model.h>
15+
16+
static optionalt<exprt> rewrite_rw_ok(exprt expr, const namespacet &ns)
17+
{
18+
bool unchanged = true;
19+
20+
for(auto it = expr.depth_begin(), itend = expr.depth_end();
21+
it != itend;) // no ++it
22+
{
23+
if(auto r_or_w_ok = expr_try_dynamic_cast<r_or_w_ok_exprt>(*it))
24+
{
25+
const auto &id = it->id();
26+
exprt replacement =
27+
prophecy_r_or_w_ok_exprt{
28+
id == ID_r_ok ? ID_prophecy_r_ok
29+
: id == ID_w_ok ? ID_prophecy_w_ok
30+
: ID_prophecy_rw_ok,
31+
r_or_w_ok->pointer(),
32+
r_or_w_ok->size(),
33+
ns.lookup(CPROVER_PREFIX "deallocated").symbol_expr(),
34+
ns.lookup(CPROVER_PREFIX "dead_object").symbol_expr()}
35+
.with_source_location<exprt>(*it);
36+
37+
it.mutate() = std::move(replacement);
38+
unchanged = false;
39+
it.next_sibling_or_parent();
40+
}
41+
else if(
42+
auto pointer_in_range =
43+
expr_try_dynamic_cast<pointer_in_range_exprt>(*it))
44+
{
45+
exprt replacement =
46+
prophecy_pointer_in_range_exprt{
47+
pointer_in_range->lower_bound(),
48+
pointer_in_range->pointer(),
49+
pointer_in_range->upper_bound(),
50+
ns.lookup(CPROVER_PREFIX "deallocated").symbol_expr(),
51+
ns.lookup(CPROVER_PREFIX "dead_object").symbol_expr()}
52+
.with_source_location<exprt>(*it);
53+
54+
it.mutate() = std::move(replacement);
55+
unchanged = false;
56+
it.next_sibling_or_parent();
57+
}
58+
else
59+
++it;
60+
}
61+
62+
if(unchanged)
63+
return {};
64+
else
65+
return std::move(expr);
66+
}
67+
68+
static void rewrite_rw_ok(
69+
goto_functionst::goto_functiont &goto_function,
70+
const namespacet &ns)
71+
{
72+
for(auto &instruction : goto_function.body.instructions)
73+
instruction.transform(
74+
[&ns](exprt expr) { return rewrite_rw_ok(expr, ns); });
75+
}
76+
77+
void rewrite_rw_ok(goto_modelt &goto_model)
78+
{
79+
const namespacet ns(goto_model.symbol_table);
80+
81+
for(auto &gf_entry : goto_model.goto_functions.function_map)
82+
rewrite_rw_ok(gf_entry.second, ns);
83+
}

src/goto-programs/rewrite_rw_ok.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/*******************************************************************\
2+
3+
Module: Rewrite {r,w,rw}_ok expressions as required by symbolic execution
4+
5+
Author: Michael Tautschnig
6+
7+
\*******************************************************************/
8+
9+
/// \file
10+
/// Rewrite r/w/rw_ok expressions to ones including prophecy variables recording
11+
/// the state.
12+
13+
#ifndef CPROVER_GOTO_PROGRAMS_REWRITE_RW_OK_H
14+
#define CPROVER_GOTO_PROGRAMS_REWRITE_RW_OK_H
15+
16+
class goto_modelt;
17+
18+
/// Replace all occurrences of `r_ok_exprt`, `w_ok_exprt`, `rw_ok_exprt`,
19+
/// `pointer_in_range_exprt` by their prophecy variants
20+
/// `prophecy_r_or_w_ok_exprt` and `prophecy_pointer_in_range_exprt`,
21+
/// respectively.
22+
/// Each analysis may choose to natively support `r_ok_exprt` etc. (like
23+
/// `cprover_parse_optionst` does) or may instead require the expression to be
24+
/// lowered to other primitives (like `goto_symext`).
25+
void rewrite_rw_ok(goto_modelt &);
26+
27+
#endif // CPROVER_GOTO_PROGRAMS_REWRITE_RW_OK_H

src/goto-synthesizer/goto_synthesizer_parse_options.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,7 @@ optionst goto_synthesizer_parse_optionst::get_options()
199199
options.set_option("depth", UINT32_MAX);
200200
options.set_option("exploration-strategy", "lifo");
201201
options.set_option("symex-cache-dereferences", false);
202+
options.set_option("rewrite-rw-ok", true);
202203
options.set_option("rewrite-union", true);
203204
options.set_option("self-loops-to-assumptions", true);
204205

0 commit comments

Comments
 (0)