Skip to content

Commit 78bacbf

Browse files
romainbrenguiertautschnig
authored andcommitted
Bug corrections in string refinement
Case of array-of in substitute array access making substitute_array_access do in-place substitution Setting the type for unknown values in substitute_array_access Unknown values could cause type problems if we do not force the type for them. Setting ui for temporary solver Remove the mode option from string solver This option is no longer requiered because the implementation is now language independent. Adapt add_axioms_for_insert for 5 arguments diffblue#110 Fixed linting issue in string_constraint_generator_concat.cpp Comment on the maximal length for string Using max_string_length as the limit for refinement Using unsigned type for max string length Using const ref in substitute_array_with_expr Correcting type of max_string_length and length comparison functions space before & sign instead of after Correcting initial_loop_bound type Putting each cbmc option on a separate line for easy merging Use size_t for string sizes Add comment in concretize_string
1 parent 39b8812 commit 78bacbf

8 files changed

+184
-62
lines changed

src/cbmc/cbmc_parse_options.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,10 @@ class optionst;
4141
"(no-sat-preprocessor)" \
4242
"(no-pretty-names)(beautify)" \
4343
"(dimacs)(refine)(max-node-refinement):(refine-arrays)(refine-arithmetic)"\
44-
"(refine-strings)(string-non-empty)(string-printable)(string-max-length):" \
44+
"(refine-strings)" \
45+
"(string-non-empty)" \
46+
"(string-printable)" \
47+
"(string-max-length):" \
4548
"(aig)(16)(32)(64)(LP64)(ILP64)(LLP64)(ILP32)(LP32)" \
4649
"(little-endian)(big-endian)" \
4750
"(show-goto-functions)(show-loops)" \

src/solvers/refinement/string_constraint_generator.h

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ Author: Romain Brenguier, [email protected]
2020
#ifndef CPROVER_SOLVERS_REFINEMENT_STRING_CONSTRAINT_GENERATOR_H
2121
#define CPROVER_SOLVERS_REFINEMENT_STRING_CONSTRAINT_GENERATOR_H
2222

23+
#include <limits>
2324
#include <util/string_expr.h>
2425
#include <util/replace_expr.h>
2526
#include <util/refined_string_type.h>
@@ -29,30 +30,20 @@ class string_constraint_generatort
2930
{
3031
public:
3132
// This module keeps a list of axioms. It has methods which generate
32-
// string constraints for different string funcitons and add them
33+
// string constraints for different string functions and add them
3334
// to the axiom list.
3435

3536
string_constraint_generatort():
36-
mode(ID_unknown),
37-
max_string_length(-1),
37+
max_string_length(std::numeric_limits<size_t>::max()),
3838
force_printable_characters(false)
3939
{ }
4040

4141
// Constraints on the maximal length of strings
42-
int max_string_length;
42+
size_t max_string_length;
4343

4444
// Should we add constraints on the characters
4545
bool force_printable_characters;
4646

47-
void set_mode(irep_idt _mode)
48-
{
49-
// only C and java modes supported
50-
assert((_mode==ID_java) || (_mode==ID_C));
51-
mode=_mode;
52-
}
53-
54-
irep_idt &get_mode() { return mode; }
55-
5647
// Axioms are of three kinds: universally quantified string constraint,
5748
// not contains string constraints and simple formulas.
5849
std::list<exprt> axioms;

src/solvers/refinement/string_constraint_generator_concat.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ string_exprt string_constraint_generatort::add_axioms_for_concat(
3030
// a4 : forall i<|s1|. res[i]=s1[i]
3131
// a5 : forall i<|s2|. res[i+|s1|]=s2[i]
3232

33-
equal_exprt a1(res.length(), plus_exprt_with_overflow_check(s1.length(), s2.length()));
33+
equal_exprt a1(
34+
res.length(), plus_exprt_with_overflow_check(s1.length(), s2.length()));
3435
axioms.push_back(a1);
3536
axioms.push_back(s1.axiom_for_is_shorter_than(res));
3637
axioms.push_back(s2.axiom_for_is_shorter_than(res));

src/solvers/refinement/string_constraint_generator_insert.cpp

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,16 +26,40 @@ string_exprt string_constraint_generatort::add_axioms_for_insert(
2626
return add_axioms_for_concat(concat1, suf);
2727
}
2828

29-
/// add axioms corresponding to the StringBuilder.insert(String) java function
30-
/// \par parameters: function application with three arguments: two strings and
31-
/// an index
32-
/// \return a new string expression
29+
/*******************************************************************\
30+
31+
Function: string_constraint_generatort::add_axioms_for_insert
32+
33+
Inputs: function application with three arguments: two strings and an index
34+
35+
Outputs: a new string expression
36+
37+
Purpose: add axioms corresponding to the
38+
StringBuilder.insert(int, CharSequence)
39+
and StringBuilder.insert(int, CharSequence, int, int)
40+
java functions
41+
42+
\*******************************************************************/
43+
3344
string_exprt string_constraint_generatort::add_axioms_for_insert(
3445
const function_application_exprt &f)
3546
{
36-
string_exprt s1=get_string_expr(args(f, 3)[0]);
37-
string_exprt s2=get_string_expr(args(f, 3)[2]);
38-
return add_axioms_for_insert(s1, s2, args(f, 3)[1]);
47+
assert(f.arguments().size()>=3);
48+
string_exprt s1=get_string_expr(f.arguments()[0]);
49+
string_exprt s2=get_string_expr(f.arguments()[2]);
50+
const exprt &offset=f.arguments()[1];
51+
if(f.arguments().size()==5)
52+
{
53+
const exprt &start=f.arguments()[3];
54+
const exprt &end=f.arguments()[4];
55+
string_exprt substring=add_axioms_for_substring(s2, start, end);
56+
return add_axioms_for_insert(s1, substring, offset);
57+
}
58+
else
59+
{
60+
assert(f.arguments().size()==3);
61+
return add_axioms_for_insert(s1, s2, offset);
62+
}
3963
}
4064

4165
/// add axioms corresponding to the StringBuilder.insert(I) java function

src/solvers/refinement/string_constraint_generator_main.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,6 @@ Function: string_constraint_generatort::convert_java_string_to_string_exprt
169169
string_exprt string_constraint_generatort::convert_java_string_to_string_exprt(
170170
const exprt &jls)
171171
{
172-
assert(get_mode()==ID_java);
173172
assert(jls.id()==ID_struct);
174173

175174
exprt length(to_struct_expr(jls).op1());
@@ -214,7 +213,7 @@ void string_constraint_generatort::add_default_axioms(
214213
const string_exprt &s)
215214
{
216215
s.axiom_for_is_longer_than(from_integer(0, s.length().type()));
217-
if(max_string_length>=0)
216+
if(max_string_length!=std::numeric_limits<size_t>::max())
218217
axioms.push_back(s.axiom_for_is_shorter_than(max_string_length));
219218

220219
if(force_printable_characters)
@@ -352,7 +351,6 @@ exprt string_constraint_generatort::add_axioms_for_function_application(
352351
// TODO: This part needs some improvement.
353352
// Stripping the symbol name is not a very robust process.
354353
new_expr.function() = symbol_exprt(str_id.substr(0, pos+4));
355-
assert(get_mode()==ID_java);
356354
new_expr.type() = refined_string_typet(java_int_type(), java_char_type());
357355

358356
auto res_it=function_application_cache.insert(std::make_pair(new_expr,

src/solvers/refinement/string_refinement.cpp

Lines changed: 136 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -54,30 +54,22 @@ string_refinementt::string_refinementt(
5454
non_empty_string(false)
5555
{ }
5656

57-
/// determine which language should be used
58-
void string_refinementt::set_mode()
59-
{
60-
debug() << "initializing mode" << eom;
61-
symbolt init=ns.lookup(irep_idt(CPROVER_PREFIX"initialize"));
62-
irep_idt mode=init.mode;
63-
debug() << "mode detected as " << mode << eom;
64-
generator.set_mode(mode);
65-
}
66-
6757
/*******************************************************************\
6858
6959
Function: string_refinementt::set_max_string_length
7060
7161
Inputs:
7262
i - maximum length which is allowed for strings.
73-
negative number means no limit
63+
by default the strings length has no other limit
64+
than the maximal integer according to the type of their
65+
length, for instance 2^31-1 for Java.
7466
7567
Purpose: Add constraints on the size of strings used in the
7668
program.
7769
7870
\*******************************************************************/
7971

80-
void string_refinementt::set_max_string_length(int i)
72+
void string_refinementt::set_max_string_length(size_t i)
8173
{
8274
generator.max_string_length=i;
8375
}
@@ -325,16 +317,18 @@ void string_refinementt::concretize_string(const exprt &expr)
325317
if(!to_integer(length, found_length))
326318
{
327319
assert(found_length.is_long());
328-
if(found_length < 0)
320+
if(found_length<0)
329321
{
322+
// Lengths should not be negative.
323+
// TODO: Add constraints no the sign of string lengths.
330324
debug() << "concretize_results: WARNING found length is negative"
331325
<< eom;
332326
}
333327
else
334328
{
335329
size_t concretize_limit=found_length.to_long();
336-
concretize_limit=concretize_limit>MAX_CONCRETE_STRING_SIZE?
337-
MAX_CONCRETE_STRING_SIZE:concretize_limit;
330+
concretize_limit=concretize_limit>generator.max_string_length?
331+
generator.max_string_length:concretize_limit;
338332
exprt content_expr=str.content();
339333
for(size_t i=0; i<concretize_limit; ++i)
340334
{
@@ -361,9 +355,9 @@ Function: string_refinementt::concretize_results
361355

362356
void string_refinementt::concretize_results()
363357
{
364-
for(const auto& it : symbol_resolve)
358+
for(const auto &it : symbol_resolve)
365359
concretize_string(it.second);
366-
for(const auto& it : generator.created_strings)
360+
for(const auto &it : generator.created_strings)
367361
concretize_string(it);
368362
add_instantiations();
369363
}
@@ -379,7 +373,7 @@ Function: string_refinementt::concretize_lengths
379373

380374
void string_refinementt::concretize_lengths()
381375
{
382-
for(const auto& it : symbol_resolve)
376+
for(const auto &it : symbol_resolve)
383377
{
384378
if(refined_string_typet::is_refined_string_type(it.second.type()))
385379
{
@@ -390,7 +384,7 @@ void string_refinementt::concretize_lengths()
390384
found_length[content]=length;
391385
}
392386
}
393-
for(const auto& it : generator.created_strings)
387+
for(const auto &it : generator.created_strings)
394388
{
395389
if(refined_string_typet::is_refined_string_type(it.type()))
396390
{
@@ -418,12 +412,6 @@ void string_refinementt::set_to(const exprt &expr, bool value)
418412
{
419413
assert(equality_propagation);
420414

421-
// TODO: remove the mode field of generator since we should be language
422-
// independent.
423-
// We only set the mode once.
424-
if(generator.get_mode()==ID_unknown)
425-
set_mode();
426-
427415
if(expr.id()==ID_equal)
428416
{
429417
equal_exprt eq_expr=to_equal_expr(expr);
@@ -695,7 +683,7 @@ exprt string_refinementt::get_array(const exprt &arr, const exprt &size) const
695683
array_typet ret_type(char_type, from_integer(n, index_type));
696684
array_exprt ret(ret_type);
697685

698-
if(n>MAX_CONCRETE_STRING_SIZE)
686+
if(n>generator.max_string_length)
699687
{
700688
#if 0
701689
debug() << "(sr::get_array) long string (size=" << n << ")" << eom;
@@ -898,6 +886,125 @@ void string_refinementt::fill_model()
898886
}
899887

900888

889+
/*******************************************************************\
890+
891+
Function: string_refinementt::substitute_array_with_expr()
892+
893+
Inputs:
894+
expr - A (possibly nested) 'with' expression on an `array_of`
895+
expression
896+
index - An index with which to build the equality condition
897+
898+
Outputs: An expression containing no 'with' expression
899+
900+
Purpose: Create a new expression where 'with' expressions on arrays
901+
are replaced by 'if' expressions.
902+
e.g. for an array access arr[x], where:
903+
`arr := array_of(12) with {0:=24} with {2:=42}`
904+
the constructed expression will be:
905+
`index==0 ? 24 : index==2 ? 42 : 12`
906+
907+
\*******************************************************************/
908+
909+
exprt string_refinementt::substitute_array_with_expr(
910+
const exprt &expr, const exprt &index) const
911+
{
912+
if(expr.id()==ID_with)
913+
{
914+
const with_exprt &with_expr=to_with_expr(expr);
915+
const exprt &then_expr=with_expr.new_value();
916+
exprt else_expr=substitute_array_with_expr(with_expr.old(), index);
917+
const typet &type=then_expr.type();
918+
assert(else_expr.type()==type);
919+
return if_exprt(
920+
equal_exprt(index, with_expr.where()), then_expr, else_expr, type);
921+
}
922+
else
923+
{
924+
// Only handle 'with' expressions on 'array_of' expressions.
925+
assert(expr.id()==ID_array_of);
926+
return to_array_of_expr(expr).what();
927+
}
928+
}
929+
930+
/*******************************************************************\
931+
932+
Function: string_refinementt::substitute_array_access()
933+
934+
Inputs:
935+
expr - an expression containing array accesses
936+
937+
Outputs: an expression containing no array access
938+
939+
Purpose: create an equivalent expression where array accesses and
940+
'with' expressions are replaced by 'if' expressions.
941+
e.g. for an array access arr[x], where:
942+
`arr := {12, 24, 48}`
943+
the constructed expression will be:
944+
`index==0 ? 12 : index==1 ? 24 : 48`
945+
946+
\*******************************************************************/
947+
948+
void string_refinementt::substitute_array_access(exprt &expr) const
949+
{
950+
for(auto &op : expr.operands())
951+
substitute_array_access(op);
952+
953+
if(expr.id()==ID_index)
954+
{
955+
index_exprt &index_expr=to_index_expr(expr);
956+
957+
if(index_expr.array().id()==ID_symbol)
958+
{
959+
expr=index_expr;
960+
return;
961+
}
962+
963+
if(index_expr.array().id()==ID_with)
964+
{
965+
expr=substitute_array_with_expr(
966+
index_expr.array(), index_expr.index());
967+
return;
968+
}
969+
970+
if(index_expr.array().id()==ID_array_of)
971+
{
972+
expr=to_array_of_expr(index_expr.array()).op();
973+
return;
974+
}
975+
976+
assert(index_expr.array().id()==ID_array);
977+
array_exprt &array_expr=to_array_expr(index_expr.array());
978+
979+
assert(!array_expr.operands().empty());
980+
size_t last_index=array_expr.operands().size()-1;
981+
982+
const typet &char_type=index_expr.array().type().subtype();
983+
exprt ite=array_expr.operands().back();
984+
985+
if(ite.type()!=char_type)
986+
{
987+
// We have to manualy set the type for unknown values
988+
assert(ite.id()==ID_unknown);
989+
ite.type()=char_type;
990+
}
991+
992+
auto op_it=++array_expr.operands().rbegin();
993+
for(size_t i=last_index-1;
994+
op_it!=array_expr.operands().rend(); ++op_it, --i)
995+
{
996+
equal_exprt equals(index_expr.index(), from_integer(i, java_int_type()));
997+
ite=if_exprt(equals, *op_it, ite);
998+
if(ite.type()!=char_type)
999+
{
1000+
assert(ite.id()==ID_unknown);
1001+
ite.type()=char_type;
1002+
}
1003+
}
1004+
expr=ite;
1005+
}
1006+
}
1007+
9011008
/*******************************************************************\
9021009
9031010
Function: string_refinementt::add_negation_of_constraint_to_solver
@@ -942,6 +1049,7 @@ void string_refinementt::add_negation_of_constraint_to_solver(
9421049
and_exprt negaxiom(premise, not_exprt(axiom.body()));
9431050

9441051
debug() << "(sr::check_axioms) negated axiom: " << from_expr(negaxiom) << eom;
1052+
substitute_array_access(negaxiom);
9451053
solver << negaxiom;
9461054
}
9471055

@@ -982,6 +1090,7 @@ bool string_refinementt::check_axioms()
9821090

9831091
satcheck_no_simplifiert sat_check;
9841092
supert solver(ns, sat_check);
1093+
solver.set_ui(ui);
9851094
add_negation_of_constraint_to_solver(axiom_in_model, solver);
9861095

9871096
switch(solver())
@@ -1036,6 +1145,7 @@ bool string_refinementt::check_axioms()
10361145
exprt premise(axiom.premise());
10371146
exprt body(axiom.body());
10381147
implies_exprt instance(premise, body);
1148+
replace_expr(symbol_resolve, instance);
10391149
replace_expr(axiom.univ_var(), val, instance);
10401150
debug() << "adding counter example " << from_expr(instance) << eom;
10411151
add_lemma(instance);

0 commit comments

Comments
 (0)