Skip to content

Commit db85dc5

Browse files
Adding option to concretize result and get method in string solver
The option to concretize makes sure that the model that we get in the end is correct. Overiding the get method is necessary to get the actual valuation of string gotten by the solver. This two additions makes the trace generation for program with strings more likely to be actual traces of the program.
1 parent 6ecf65f commit db85dc5

File tree

2 files changed

+165
-31
lines changed

2 files changed

+165
-31
lines changed

src/solvers/refinement/string_refinement.cpp

Lines changed: 149 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,27 @@ Author: Alberto Griggio, alberto.griggio@gmail.com
2121
#include <langapi/language_util.h>
2222
#include <java_bytecode/java_types.h>
2323

24+
/*******************************************************************\
25+
26+
Constructor: string_refinementt
27+
28+
Inputs: a namespace, a decision procedure, a bound on the number
29+
of refinements and a boolean flag `concretize_result`
30+
31+
Purpose: refinement_bound is a bound on the number of refinement allowed.
32+
if `concretize_result` is set to true, at the end of the decision
33+
procedure, the solver try to find a concrete value for each
34+
character
35+
36+
\*******************************************************************/
37+
2438
string_refinementt::string_refinementt(
25-
const namespacet &_ns, propt &_prop, unsigned refinement_bound):
39+
const namespacet &_ns,
40+
propt &_prop,
41+
unsigned refinement_bound):
2642
supert(_ns, _prop),
2743
use_counter_example(false),
44+
do_concretizing(false),
2845
initial_loop_bound(refinement_bound)
2946
{ }
3047

@@ -194,7 +211,7 @@ exprt string_refinementt::substitute_function_applications(exprt expr)
194211
return expr;
195212
}
196213

197-
bool string_refinementt::is_char_array(const typet &type)
214+
bool string_refinementt::is_char_array(const typet &type) const
198215
{
199216
if(type.id()==ID_symbol)
200217
return is_char_array(ns.follow(type));
@@ -220,7 +237,12 @@ bool string_refinementt::add_axioms_for_string_assigns(const exprt &lhs,
220237
if(is_char_array(rhs.type()))
221238
{
222239
set_char_array_equality(lhs, rhs);
223-
add_symbol_to_symbol_map(lhs, rhs);
240+
if(rhs.id() != ID_nondet_symbol)
241+
add_symbol_to_symbol_map(lhs, rhs);
242+
else
243+
add_symbol_to_symbol_map(
244+
lhs, generator.fresh_symbol("nondet_array", lhs.type()));
245+
224246
return false;
225247
}
226248
if(refined_string_typet::is_refined_string_type(rhs.type()))
@@ -235,6 +257,46 @@ bool string_refinementt::add_axioms_for_string_assigns(const exprt &lhs,
235257

236258
/*******************************************************************\
237259
260+
Function: string_refinementt::concretize_results
261+
262+
Purpose: For each string whose length has been solved, add constants
263+
to the index set to force the solver to pick concrete values
264+
for each character
265+
266+
\*******************************************************************/
267+
268+
void string_refinementt::concretize_results()
269+
{
270+
for(const auto& it : symbol_resolve)
271+
{
272+
if(refined_string_typet::is_refined_string_type(it.second.type()))
273+
{
274+
string_exprt str=to_string_expr(it.second);
275+
exprt length=current_model[str.length()];
276+
mp_integer found_length;
277+
if(!to_integer(length, found_length))
278+
{
279+
assert(found_length.is_long() && found_length >= 0);
280+
size_t concretize_limit=found_length.to_long();
281+
concretize_limit=concretize_limit>MAX_CONCRETE_STRING_SIZE?
282+
MAX_CONCRETE_STRING_SIZE:concretize_limit;
283+
exprt content_expr=str.content();
284+
replace_expr(current_model, content_expr);
285+
for(size_t i=0; i<concretize_limit; ++i)
286+
{
287+
auto i_expr=from_integer(i, str.length().type());
288+
debug() << "Concretizing " << from_expr(content_expr)
289+
<< " / " << i << eom;
290+
current_index_set[str.content()].insert(i_expr);
291+
}
292+
}
293+
}
294+
}
295+
add_instantiations();
296+
}
297+
298+
/*******************************************************************\
299+
238300
Function: string_refinementt::set_to
239301
240302
Inputs: an expression and the value to set it to
@@ -397,7 +459,13 @@ decision_proceduret::resultt string_refinementt::dec_solve()
397459
if(current_index_set.empty())
398460
{
399461
debug() << "current index set is empty" << eom;
400-
return D_SATISFIABLE;
462+
if(do_concretizing)
463+
{
464+
concretize_results();
465+
do_concretizing=false;
466+
}
467+
else
468+
return D_SATISFIABLE;
401469
}
402470

403471
display_index_set();
@@ -488,7 +556,7 @@ Function: string_refinementt::get_array
488556

489557
exprt string_refinementt::get_array(const exprt &arr, const exprt &size)
490558
{
491-
exprt arr_val=get(arr);
559+
exprt arr_val=get_array(arr);
492560
exprt size_val=get(size);
493561
typet char_type=arr.type().subtype();
494562
typet index_type=size.type();
@@ -566,6 +634,32 @@ exprt string_refinementt::get_array(const exprt &arr, const exprt &size)
566634
return ret;
567635
}
568636

637+
638+
/*******************************************************************\
639+
640+
Function: string_refinementt::get_array
641+
642+
Inputs: an expression representing an array
643+
644+
Outputs: an expression
645+
646+
Purpose: get a model of an array of unknown size and infer the size if
647+
possible
648+
649+
\*******************************************************************/
650+
651+
exprt string_refinementt::get_array(const exprt &arr)
652+
{
653+
exprt arr_model=supert::get(arr);
654+
if(arr_model.id()==ID_array)
655+
{
656+
array_typet &arr_type=to_array_type(arr_model.type());
657+
arr_type.size()=from_integer(
658+
arr_model.operands().size(), arr_type.size().type());
659+
}
660+
return arr_model;
661+
}
662+
569663
/*******************************************************************\
570664
571665
Function: string_refinementt::string_of_array
@@ -616,56 +710,64 @@ std::string string_refinementt::string_of_array(const array_exprt &arr)
616710
617711
Function: string_refinementt::fill_model
618712
619-
Outputs: a replace map
620-
621-
Purpose: maps the variable created by the solver to constant expressions
622-
given by the current model
713+
Purpose: Fill in `current_model` by mapping the variables created by
714+
the solver to constant expressions given by the current model
623715
624716
\*******************************************************************/
625717

626-
replace_mapt string_refinementt::fill_model()
718+
void string_refinementt::fill_model()
627719
{
628-
replace_mapt fmodel;
629-
630720
for(auto it : symbol_resolve)
631721
{
632722
if(refined_string_typet::is_refined_string_type(it.second.type()))
633723
{
634724
string_exprt refined=to_string_expr(it.second);
725+
// TODO: check whith this is necessary:
635726
replace_expr(symbol_resolve, refined);
636727
const exprt &econtent=refined.content();
637728
const exprt &elength=refined.length();
638729

639-
exprt len=get(elength);
730+
exprt len=supert::get(elength);
640731
exprt arr=get_array(econtent, len);
641732

642-
fmodel[elength]=len;
643-
fmodel[econtent]=arr;
644-
733+
current_model[elength]=len;
734+
current_model[econtent]=arr;
645735
debug() << from_expr(to_symbol_expr(it.first)) << "="
646736
<< from_expr(refined);
737+
647738
if(arr.id()==ID_array)
648739
debug() << " = \"" << string_of_array(to_array_expr(arr))
649740
<< "\" (size:" << from_expr(len) << ")"<< eom;
650741
else
651742
debug() << " = " << from_expr(arr) << "" << eom;
652743
}
744+
else
745+
{
746+
assert(is_char_array(it.second.type()));
747+
exprt arr=it.second;
748+
replace_expr(symbol_resolve, arr);
749+
replace_expr(current_model, arr);
750+
exprt arr_model=get_array(arr);
751+
current_model[it.first]=arr_model;
752+
753+
debug() << from_expr(to_symbol_expr(it.first)) << "="
754+
<< from_expr(arr) << " = " << from_expr(arr_model) << "" << eom;
755+
}
653756
}
654757

655758
for(auto it : generator.boolean_symbols)
656759
{
657760
debug() << "" << it.get_identifier() << " := "
658-
<< from_expr(get(it)) << eom;
659-
fmodel[it]=get(it);
761+
<< from_expr(supert::get(it)) << eom;
762+
current_model[it]=supert::get(it);
660763
}
661764

662765
for(auto it : generator.index_symbols)
663766
{
664-
debug() << "" << it.get_identifier() << " := "
665-
<< from_expr(get(it)) << eom;
666-
fmodel[it]=get(it);
767+
debug() << "" << it.get_identifier() << " := "
768+
<< from_expr(supert::get(it)) << eom;
769+
current_model[it]=supert::get(it);
667770
}
668-
return fmodel;
669771
}
670772

671773
/*******************************************************************\
@@ -730,7 +832,7 @@ bool string_refinementt::check_axioms()
730832
<< "===========================================" << eom;
731833
debug() << "string_refinementt::check_axioms: build the"
732834
<< " interpretation from the model of the prop_solver" << eom;
733-
replace_mapt fmodel=fill_model();
835+
fill_model();
734836

735837
// Maps from indexes of violated universal axiom to a witness of violation
736838
std::map<size_t, exprt> violated;
@@ -746,10 +848,10 @@ bool string_refinementt::check_axioms()
746848
exprt prem=axiom.premise();
747849
exprt body=axiom.body();
748850

749-
replace_expr(fmodel, bound_inf);
750-
replace_expr(fmodel, bound_sup);
751-
replace_expr(fmodel, prem);
752-
replace_expr(fmodel, body);
851+
replace_expr(current_model, bound_inf);
852+
replace_expr(current_model, bound_sup);
853+
replace_expr(current_model, prem);
854+
replace_expr(current_model, body);
753855
string_constraintt axiom_in_model(
754856
univ_var, bound_inf, bound_sup, prem, body);
755857

@@ -1320,3 +1422,23 @@ void string_refinementt::instantiate_not_contains(
13201422
new_lemmas.push_back(witness_bounds);
13211423
}
13221424
}
1425+
1426+
/*******************************************************************\
1427+
1428+
Function: string_refinementt::get
1429+
1430+
Inputs: an expression
1431+
1432+
Outputs: an expression
1433+
1434+
Purpose: evaluation of the expression in the current model
1435+
1436+
\*******************************************************************/
1437+
1438+
exprt string_refinementt::get(const exprt &expr) const
1439+
{
1440+
exprt ecopy(expr);
1441+
replace_expr(symbol_resolve, ecopy);
1442+
replace_expr(current_model, ecopy);
1443+
return supert::get(ecopy);
1444+
}

src/solvers/refinement/string_refinement.h

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,22 +28,27 @@ Author: Alberto Griggio, alberto.griggio@gmail.com
2828
class string_refinementt: public bv_refinementt
2929
{
3030
public:
31-
// refinement_bound is a bound on the number of refinement allowed
3231
string_refinementt(
33-
const namespacet &_ns, propt &_prop, unsigned refinement_bound);
32+
const namespacet &_ns,
33+
propt &_prop,
34+
unsigned refinement_bound);
3435

3536
void set_mode();
3637

3738
// Should we use counter examples at each iteration?
3839
bool use_counter_example;
3940

41+
bool do_concretizing;
42+
4043
virtual std::string decision_procedure_text() const override
4144
{
4245
return "string refinement loop with "+prop.solver_text();
4346
}
4447

4548
static exprt is_positive(const exprt &x);
4649

50+
exprt get(const exprt &expr) const override;
51+
4752
protected:
4853
typedef std::set<exprt> expr_sett;
4954
typedef std::list<exprt> exprt_listt;
@@ -78,6 +83,10 @@ class string_refinementt: public bv_refinementt
7883
std::map<exprt, exprt_listt> reverse_symbol_resolve;
7984
std::list<std::pair<exprt, bool>> non_string_axioms;
8085

86+
// Valuation in the current model of the symbols that have been created
87+
// by the solver
88+
replace_mapt current_model;
89+
8190
void add_equivalence(const irep_idt & lhs, const exprt & rhs);
8291

8392
void display_index_set();
@@ -88,14 +97,14 @@ class string_refinementt: public bv_refinementt
8897
typet substitute_java_string_types(typet type);
8998
exprt substitute_java_strings(exprt expr);
9099
void add_symbol_to_symbol_map(const exprt &lhs, const exprt &rhs);
91-
bool is_char_array(const typet &type);
100+
bool is_char_array(const typet &type) const;
92101
bool add_axioms_for_string_assigns(const exprt &lhs, const exprt &rhs);
93102
void set_to(const exprt &expr, bool value) override;
94103

95104
void add_instantiations();
96105
void add_negation_of_constraint_to_solver(
97106
const string_constraintt &axiom, supert &solver);
98-
replace_mapt fill_model();
107+
void fill_model();
99108
bool check_axioms();
100109

101110
void set_char_array_equality(const exprt &lhs, const exprt &rhs);
@@ -120,7 +129,10 @@ class string_refinementt: public bv_refinementt
120129

121130
exprt simplify_sum(const exprt &f) const;
122131

132+
void concretize_results();
133+
123134
exprt get_array(const exprt &arr, const exprt &size);
135+
exprt get_array(const exprt &arr);
124136

125137
std::string string_of_array(const array_exprt &arr);
126138
};

0 commit comments

Comments
 (0)