Skip to content

Commit c17fe72

Browse files
author
Owen
committed
filter value sets at gotos and assumes
1 parent 28ce0ef commit c17fe72

File tree

5 files changed

+173
-2
lines changed

5 files changed

+173
-2
lines changed

src/goto-symex/goto_symex.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,25 @@ class goto_symext
225225
virtual void symex_dead(statet &);
226226
virtual void symex_other(statet &);
227227

228+
/// Try to filter value sets based on whether possible values of a
229+
/// pointer-typed symbol make the condition true or false. We only do this
230+
/// when there is only one pointer-typed symbol in \p condition.
231+
/// \param state: The current state
232+
/// \param condition: The condition which is being evaluated
233+
/// \param value_set_for_true_case: A pointer to the value set that possible
234+
/// values should be removed from if they make the condition false, or
235+
/// nullptr if this shouldn't be done
236+
/// \param value_set_for_false_case: A pointer to the value set that possible
237+
/// values should be removed from if they make the condition true, or
238+
/// nullptr if this shouldn't be done
239+
/// \param ns: A namespace
240+
void try_filter_value_sets(
241+
goto_symex_statet &state,
242+
exprt condition,
243+
value_sett *value_set_for_true_case,
244+
value_sett *value_set_for_false_case,
245+
const namespacet &ns);
246+
228247
virtual void vcc(
229248
const exprt &,
230249
const std::string &msg,

src/goto-symex/symex_goto.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ Author: Daniel Kroening, [email protected]
2020
#include <util/std_expr.h>
2121

2222
#include <analyses/dirty.h>
23+
#include <util/replace_symbol.h>
2324
#include <util/simplify_expr.h>
2425

2526
void goto_symext::symex_goto(statet &state)
@@ -224,6 +225,18 @@ void goto_symext::symex_goto(statet &state)
224225

225226
symex_transition(state, state_pc, backward);
226227

228+
if(!new_guard.is_true())
229+
{
230+
// try to update the value sets using information contained in which branch
231+
// is being taken
232+
try_filter_value_sets(
233+
state,
234+
instruction.get_condition(),
235+
backward ? &state.value_set : &goto_state_list.back().value_set,
236+
!backward ? &state.value_set : &goto_state_list.back().value_set,
237+
ns);
238+
}
239+
227240
// adjust guards
228241
if(new_guard.is_true())
229242
{

src/goto-symex/symex_main.cpp

Lines changed: 120 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,9 +133,15 @@ void goto_symext::symex_assume(statet &state, const exprt &cond)
133133
else
134134
state.guard.add(simplified_cond);
135135

136-
if(state.atomic_section_id!=0 &&
137-
state.guard.is_false())
136+
if(state.atomic_section_id != 0 && state.guard.is_false())
138137
symex_atomic_end(state);
138+
139+
if(!simplified_cond.is_false())
140+
{
141+
// try to update the value sets using information contained in the guard
142+
try_filter_value_sets(
143+
state, simplified_cond, &state.value_set, nullptr, ns);
144+
}
139145
}
140146

141147
void goto_symext::rewrite_quantifiers(exprt &expr, statet &state)
@@ -519,3 +525,115 @@ void goto_symext::symex_step(
519525
UNREACHABLE;
520526
}
521527
}
528+
529+
/// Collect all sub-expressions of an expression that are pointer-typed symbols
530+
/// \param expr: The expression to examine
531+
/// \param [out] output: The set to put the results into
532+
static void
533+
collect_pointer_typed_symbols(const exprt &expr, std::set<symbol_exprt> &output)
534+
{
535+
const symbol_exprt *symbol_expr = expr_try_dynamic_cast<symbol_exprt>(expr);
536+
if(symbol_expr && can_cast_type<pointer_typet>(symbol_expr->type()))
537+
{
538+
output.insert(*symbol_expr);
539+
}
540+
541+
for(const exprt &op : expr.operands())
542+
{
543+
collect_pointer_typed_symbols(op, output);
544+
}
545+
}
546+
547+
void goto_symext::try_filter_value_sets(
548+
goto_symex_statet &state,
549+
exprt condition,
550+
value_sett *value_set_for_true_case,
551+
value_sett *value_set_for_false_case,
552+
const namespacet &ns)
553+
{
554+
condition = state.rename<goto_symex_statet::L1>(std::move(condition), ns);
555+
556+
std::set<symbol_exprt> pointer_typed_symbols{};
557+
collect_pointer_typed_symbols(condition, pointer_typed_symbols);
558+
559+
if(pointer_typed_symbols.size() == 1)
560+
{
561+
const symbol_exprt &symbol_expr = *pointer_typed_symbols.begin();
562+
const pointer_typet &symbol_type = to_pointer_type(symbol_expr.type());
563+
564+
// If symbol_expr has already been L2-renamed then we need to strip it back
565+
// to L1-renaming for the purposes of getting its value set
566+
const symbol_exprt symbol_expr_l1 =
567+
is_ssa_expr(symbol_expr) ? to_ssa_expr(symbol_expr).get_l1_object()
568+
: symbol_expr;
569+
value_setst::valuest possible_values;
570+
state.value_set.get_value_set(symbol_expr_l1, possible_values, ns);
571+
572+
// Try evaluating the condition with symbol_expr pointing to each one of
573+
// its possible values in turn. If that leads to a true from o1 then we can
574+
// delete that o1 from the value set that will be used if the condition is
575+
// false, and vice versa.
576+
for(const auto &possible_value : possible_values)
577+
{
578+
if(!can_cast_expr<object_descriptor_exprt>(possible_value))
579+
{
580+
continue;
581+
}
582+
583+
object_descriptor_exprt o = to_object_descriptor_expr(possible_value);
584+
585+
const exprt &root_object = o.root_object();
586+
const exprt &object = o.object();
587+
exprt value_for_symbol_expr;
588+
589+
if(root_object.id() == ID_null_object)
590+
{
591+
value_for_symbol_expr = null_pointer_exprt{symbol_type};
592+
}
593+
else if(root_object.id() == ID_integer_address)
594+
{
595+
continue;
596+
}
597+
else
598+
{
599+
// We should do something like
600+
// value_set_dereference::dereference_type_compare, which deals with
601+
// arrays having types containing void
602+
if(o.offset().is_zero() && object.type() == symbol_type.subtype())
603+
{
604+
value_for_symbol_expr = address_of_exprt(object);
605+
}
606+
else
607+
{
608+
continue;
609+
}
610+
}
611+
612+
exprt modified_condition(condition);
613+
614+
replace_symbolt replace_symbol{};
615+
replace_symbol.insert(symbol_expr, value_for_symbol_expr);
616+
replace_symbol(modified_condition);
617+
618+
do_simplify(modified_condition);
619+
modified_condition = state.rename(std::move(modified_condition), ns);
620+
do_simplify(modified_condition);
621+
622+
if(value_set_for_true_case && modified_condition.is_false())
623+
{
624+
value_sett::entryt *entry = const_cast<value_sett::entryt *>(
625+
value_set_for_true_case->get_entry_for_symbol(
626+
symbol_expr_l1.get_identifier(), ns.follow(symbol_type), ""));
627+
value_set_for_true_case->erase_value_from_entry(*entry, possible_value);
628+
}
629+
else if(value_set_for_false_case && modified_condition.is_true())
630+
{
631+
value_sett::entryt *entry = const_cast<value_sett::entryt *>(
632+
value_set_for_false_case->get_entry_for_symbol(
633+
symbol_expr_l1.get_identifier(), ns.follow(symbol_type), ""));
634+
value_set_for_false_case->erase_value_from_entry(
635+
*entry, possible_value);
636+
}
637+
}
638+
}
639+
}

src/pointer-analysis/value_set.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1611,3 +1611,22 @@ exprt value_sett::make_member(
16111611

16121612
return member_expr;
16131613
}
1614+
1615+
void value_sett::erase_value_from_entry(entryt &entry, const exprt &value_to_erase)
1616+
{
1617+
std::vector<object_map_dt::key_type> keys_to_erase;
1618+
for(const auto &key_value : entry.object_map.read())
1619+
{
1620+
const auto &rhs_object = to_expr(key_value);
1621+
if(rhs_object == value_to_erase)
1622+
{
1623+
keys_to_erase.emplace_back(key_value.first);
1624+
}
1625+
}
1626+
DATA_INVARIANT(
1627+
!keys_to_erase.empty(), "erase_value() should erase at least one value");
1628+
for(const auto &key : keys_to_erase)
1629+
{
1630+
entry.object_map.write().erase(key);
1631+
}
1632+
}

src/pointer-analysis/value_set.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -452,6 +452,8 @@ class value_sett
452452
const typet &expr_type,
453453
const std::string &suffix) const;
454454

455+
void erase_value_from_entry(entryt &entry, const exprt &value_to_erase);
456+
455457
protected:
456458
/// Reads the set of objects pointed to by `expr`, including making
457459
/// recursive lookups for dereference operations etc.

0 commit comments

Comments
 (0)