Skip to content

Commit 91d07b1

Browse files
romainbrenguierJoel Allred
authored and
Joel Allred
committed
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 #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 d5c6ac6 commit 91d07b1

8 files changed

+173
-67
lines changed

src/cbmc/cbmc_parse_options.h

+4-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,10 @@ class optionst;
3838
"(no-sat-preprocessor)" \
3939
"(no-pretty-names)(beautify)" \
4040
"(dimacs)(refine)(max-node-refinement):(refine-arrays)(refine-arithmetic)"\
41-
"(refine-strings)(string-non-empty)(string-printable)(string-max-length):" \
41+
"(refine-strings)" \
42+
"(string-non-empty)" \
43+
"(string-printable)" \
44+
"(string-max-length):" \
4245
"(aig)(16)(32)(64)(LP64)(ILP64)(LLP64)(ILP32)(LP32)" \
4346
"(little-endian)(big-endian)" \
4447
"(show-goto-functions)(show-loops)" \

src/solvers/refinement/string_constraint_generator.h

+4-13
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ Author: Romain Brenguier, [email protected]
1313
#ifndef CPROVER_SOLVERS_REFINEMENT_STRING_CONSTRAINT_GENERATOR_H
1414
#define CPROVER_SOLVERS_REFINEMENT_STRING_CONSTRAINT_GENERATOR_H
1515

16+
#include <limits>
1617
#include <util/string_expr.h>
1718
#include <util/replace_expr.h>
1819
#include <util/refined_string_type.h>
@@ -22,30 +23,20 @@ class string_constraint_generatort
2223
{
2324
public:
2425
// This module keeps a list of axioms. It has methods which generate
25-
// string constraints for different string funcitons and add them
26+
// string constraints for different string functions and add them
2627
// to the axiom list.
2728

2829
string_constraint_generatort():
29-
mode(ID_unknown),
30-
max_string_length(-1),
30+
max_string_length(std::numeric_limits<size_t>::max()),
3131
force_printable_characters(false)
3232
{ }
3333

3434
// Constraints on the maximal length of strings
35-
int max_string_length;
35+
size_t max_string_length;
3636

3737
// Should we add constraints on the characters
3838
bool force_printable_characters;
3939

40-
void set_mode(irep_idt _mode)
41-
{
42-
// only C and java modes supported
43-
assert((_mode==ID_java) || (_mode==ID_C));
44-
mode=_mode;
45-
}
46-
47-
irep_idt &get_mode() { return mode; }
48-
4940
// Axioms are of three kinds: universally quantified string constraint,
5041
// not contains string constraints and simple formulas.
5142
std::list<exprt> axioms;

src/solvers/refinement/string_constraint_generator_concat.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@ string_exprt string_constraint_generatort::add_axioms_for_concat(
3535
// a4 : forall i<|s1|. res[i]=s1[i]
3636
// a5 : forall i<|s2|. res[i+|s1|]=s2[i]
3737

38-
equal_exprt a1(res.length(), plus_exprt_with_overflow_check(s1.length(), s2.length()));
38+
equal_exprt a1(
39+
res.length(), plus_exprt_with_overflow_check(s1.length(), s2.length()));
3940
axioms.push_back(a1);
4041
axioms.push_back(s1.axiom_for_is_shorter_than(res));
4142
axioms.push_back(s2.axiom_for_is_shorter_than(res));

src/solvers/refinement/string_constraint_generator_insert.cpp

+20-5
Original file line numberDiff line numberDiff line change
@@ -40,17 +40,32 @@ Function: string_constraint_generatort::add_axioms_for_insert
4040
4141
Outputs: a new string expression
4242
43-
Purpose: add axioms corresponding to the StringBuilder.insert(String) java
44-
function
43+
Purpose: add axioms corresponding to the
44+
StringBuilder.insert(int, CharSequence)
45+
and StringBuilder.insert(int, CharSequence, int, int)
46+
java functions
4547
4648
\*******************************************************************/
4749

4850
string_exprt string_constraint_generatort::add_axioms_for_insert(
4951
const function_application_exprt &f)
5052
{
51-
string_exprt s1=get_string_expr(args(f, 3)[0]);
52-
string_exprt s2=get_string_expr(args(f, 3)[2]);
53-
return add_axioms_for_insert(s1, s2, args(f, 3)[1]);
53+
assert(f.arguments().size()>=3);
54+
string_exprt s1=get_string_expr(f.arguments()[0]);
55+
string_exprt s2=get_string_expr(f.arguments()[2]);
56+
const exprt &offset=f.arguments()[1];
57+
if(f.arguments().size()==5)
58+
{
59+
const exprt &start=f.arguments()[3];
60+
const exprt &end=f.arguments()[4];
61+
string_exprt substring=add_axioms_for_substring(s2, start, end);
62+
return add_axioms_for_insert(s1, substring, offset);
63+
}
64+
else
65+
{
66+
assert(f.arguments().size()==3);
67+
return add_axioms_for_insert(s1, s2, offset);
68+
}
5469
}
5570

5671
/*******************************************************************\

src/solvers/refinement/string_constraint_generator_main.cpp

+1-3
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,6 @@ Function: string_constraint_generatort::convert_java_string_to_string_exprt
224224
string_exprt string_constraint_generatort::convert_java_string_to_string_exprt(
225225
const exprt &jls)
226226
{
227-
assert(get_mode()==ID_java);
228227
assert(jls.id()==ID_struct);
229228

230229
exprt length(to_struct_expr(jls).op1());
@@ -269,7 +268,7 @@ void string_constraint_generatort::add_default_axioms(
269268
const string_exprt &s)
270269
{
271270
s.axiom_for_is_longer_than(from_integer(0, s.length().type()));
272-
if(max_string_length>=0)
271+
if(max_string_length!=std::numeric_limits<size_t>::max())
273272
axioms.push_back(s.axiom_for_is_shorter_than(max_string_length));
274273

275274
if(force_printable_characters)
@@ -433,7 +432,6 @@ exprt string_constraint_generatort::add_axioms_for_function_application(
433432
// TODO: This part needs some improvement.
434433
// Stripping the symbol name is not a very robust process.
435434
new_expr.function() = symbol_exprt(str_id.substr(0, pos+4));
436-
assert(get_mode()==ID_java);
437435
new_expr.type() = refined_string_typet(java_int_type(), java_char_type());
438436

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

src/solvers/refinement/string_refinement.cpp

+136-33
Original file line numberDiff line numberDiff line change
@@ -49,35 +49,20 @@ string_refinementt::string_refinementt(
4949

5050
/*******************************************************************\
5151
52-
Function: string_refinementt::set_mode
53-
54-
Purpose: determine which language should be used
55-
56-
\*******************************************************************/
57-
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-
67-
/*******************************************************************\
68-
6952
Function: string_refinementt::set_max_string_length
7053
7154
Inputs:
7255
i - maximum length which is allowed for strings.
73-
negative number means no limit
56+
by default the strings length has no other limit
57+
than the maximal integer according to the type of their
58+
length, for instance 2^31-1 for Java.
7459
7560
Purpose: Add constraints on the size of strings used in the
7661
program.
7762
7863
\*******************************************************************/
7964

80-
void string_refinementt::set_max_string_length(int i)
65+
void string_refinementt::set_max_string_length(size_t i)
8166
{
8267
generator.max_string_length=i;
8368
}
@@ -355,16 +340,18 @@ void string_refinementt::concretize_string(const exprt &expr)
355340
if(!to_integer(length, found_length))
356341
{
357342
assert(found_length.is_long());
358-
if(found_length < 0)
343+
if(found_length<0)
359344
{
345+
// Lengths should not be negative.
346+
// TODO: Add constraints no the sign of string lengths.
360347
debug() << "concretize_results: WARNING found length is negative"
361348
<< eom;
362349
}
363350
else
364351
{
365352
size_t concretize_limit=found_length.to_long();
366-
concretize_limit=concretize_limit>MAX_CONCRETE_STRING_SIZE?
367-
MAX_CONCRETE_STRING_SIZE:concretize_limit;
353+
concretize_limit=concretize_limit>generator.max_string_length?
354+
generator.max_string_length:concretize_limit;
368355
exprt content_expr=str.content();
369356
for(size_t i=0; i<concretize_limit; ++i)
370357
{
@@ -391,9 +378,9 @@ Function: string_refinementt::concretize_results
391378

392379
void string_refinementt::concretize_results()
393380
{
394-
for(const auto& it : symbol_resolve)
381+
for(const auto &it : symbol_resolve)
395382
concretize_string(it.second);
396-
for(const auto& it : generator.created_strings)
383+
for(const auto &it : generator.created_strings)
397384
concretize_string(it);
398385
add_instantiations();
399386
}
@@ -409,7 +396,7 @@ Function: string_refinementt::concretize_lengths
409396

410397
void string_refinementt::concretize_lengths()
411398
{
412-
for(const auto& it : symbol_resolve)
399+
for(const auto &it : symbol_resolve)
413400
{
414401
if(refined_string_typet::is_refined_string_type(it.second.type()))
415402
{
@@ -420,7 +407,7 @@ void string_refinementt::concretize_lengths()
420407
found_length[content]=length;
421408
}
422409
}
423-
for(const auto& it : generator.created_strings)
410+
for(const auto &it : generator.created_strings)
424411
{
425412
if(refined_string_typet::is_refined_string_type(it.type()))
426413
{
@@ -448,12 +435,6 @@ void string_refinementt::set_to(const exprt &expr, bool value)
448435
{
449436
assert(equality_propagation);
450437

451-
// TODO: remove the mode field of generator since we should be language
452-
// independent.
453-
// We only set the mode once.
454-
if(generator.get_mode()==ID_unknown)
455-
set_mode();
456-
457438
if(expr.id()==ID_equal)
458439
{
459440
equal_exprt eq_expr=to_equal_expr(expr);
@@ -743,7 +724,7 @@ exprt string_refinementt::get_array(const exprt &arr, const exprt &size) const
743724
array_typet ret_type(char_type, from_integer(n, index_type));
744725
array_exprt ret(ret_type);
745726

746-
if(n>MAX_CONCRETE_STRING_SIZE)
727+
if(n>generator.max_string_length)
747728
{
748729
#if 0
749730
debug() << "(sr::get_array) long string (size=" << n << ")" << eom;
@@ -947,6 +928,125 @@ void string_refinementt::fill_model()
947928
}
948929

949930

931+
/*******************************************************************\
932+
933+
Function: string_refinementt::substitute_array_with_expr()
934+
935+
Inputs:
936+
expr - A (possibly nested) 'with' expression on an `array_of`
937+
expression
938+
index - An index with which to build the equality condition
939+
940+
Outputs: An expression containing no 'with' expression
941+
942+
Purpose: Create a new expression where 'with' expressions on arrays
943+
are replaced by 'if' expressions.
944+
e.g. for an array access arr[x], where:
945+
`arr := array_of(12) with {0:=24} with {2:=42}`
946+
the constructed expression will be:
947+
`index==0 ? 24 : index==2 ? 42 : 12`
948+
949+
\*******************************************************************/
950+
951+
exprt string_refinementt::substitute_array_with_expr(
952+
const exprt &expr, const exprt &index) const
953+
{
954+
if(expr.id()==ID_with)
955+
{
956+
const with_exprt &with_expr=to_with_expr(expr);
957+
const exprt &then_expr=with_expr.new_value();
958+
exprt else_expr=substitute_array_with_expr(with_expr.old(), index);
959+
const typet &type=then_expr.type();
960+
assert(else_expr.type()==type);
961+
return if_exprt(
962+
equal_exprt(index, with_expr.where()), then_expr, else_expr, type);
963+
}
964+
else
965+
{
966+
// Only handle 'with' expressions on 'array_of' expressions.
967+
assert(expr.id()==ID_array_of);
968+
return to_array_of_expr(expr).what();
969+
}
970+
}
971+
972+
/*******************************************************************\
973+
974+
Function: string_refinementt::substitute_array_access()
975+
976+
Inputs:
977+
expr - an expression containing array accesses
978+
979+
Outputs: an expression containing no array access
980+
981+
Purpose: create an equivalent expression where array accesses and
982+
'with' expressions are replaced by 'if' expressions.
983+
e.g. for an array access arr[x], where:
984+
`arr := {12, 24, 48}`
985+
the constructed expression will be:
986+
`index==0 ? 12 : index==1 ? 24 : 48`
987+
988+
\*******************************************************************/
989+
990+
void string_refinementt::substitute_array_access(exprt &expr) const
991+
{
992+
for(auto &op : expr.operands())
993+
substitute_array_access(op);
994+
995+
if(expr.id()==ID_index)
996+
{
997+
index_exprt &index_expr=to_index_expr(expr);
998+
999+
if(index_expr.array().id()==ID_symbol)
1000+
{
1001+
expr=index_expr;
1002+
return;
1003+
}
1004+
1005+
if(index_expr.array().id()==ID_with)
1006+
{
1007+
expr=substitute_array_with_expr(
1008+
index_expr.array(), index_expr.index());
1009+
return;
1010+
}
1011+
1012+
if(index_expr.array().id()==ID_array_of)
1013+
{
1014+
expr=to_array_of_expr(index_expr.array()).op();
1015+
return;
1016+
}
1017+
1018+
assert(index_expr.array().id()==ID_array);
1019+
array_exprt &array_expr=to_array_expr(index_expr.array());
1020+
1021+
assert(!array_expr.operands().empty());
1022+
size_t last_index=array_expr.operands().size()-1;
1023+
1024+
const typet &char_type=index_expr.array().type().subtype();
1025+
exprt ite=array_expr.operands().back();
1026+
1027+
if(ite.type()!=char_type)
1028+
{
1029+
// We have to manualy set the type for unknown values
1030+
assert(ite.id()==ID_unknown);
1031+
ite.type()=char_type;
1032+
}
1033+
1034+
auto op_it=++array_expr.operands().rbegin();
1035+
for(size_t i=last_index-1;
1036+
op_it!=array_expr.operands().rend(); ++op_it, --i)
1037+
{
1038+
equal_exprt equals(index_expr.index(), from_integer(i, java_int_type()));
1039+
ite=if_exprt(equals, *op_it, ite);
1040+
if(ite.type()!=char_type)
1041+
{
1042+
assert(ite.id()==ID_unknown);
1043+
ite.type()=char_type;
1044+
}
1045+
}
1046+
expr=ite;
1047+
}
1048+
}
1049+
9501050
/*******************************************************************\
9511051
9521052
Function: string_refinementt::add_negation_of_constraint_to_solver
@@ -991,6 +1091,7 @@ void string_refinementt::add_negation_of_constraint_to_solver(
9911091
and_exprt negaxiom(premise, not_exprt(axiom.body()));
9921092

9931093
debug() << "(sr::check_axioms) negated axiom: " << from_expr(negaxiom) << eom;
1094+
substitute_array_access(negaxiom);
9941095
solver << negaxiom;
9951096
}
9961097

@@ -1031,6 +1132,7 @@ bool string_refinementt::check_axioms()
10311132

10321133
satcheck_no_simplifiert sat_check;
10331134
supert solver(ns, sat_check);
1135+
solver.set_ui(ui);
10341136
add_negation_of_constraint_to_solver(axiom_in_model, solver);
10351137

10361138
switch(solver())
@@ -1085,6 +1187,7 @@ bool string_refinementt::check_axioms()
10851187
exprt premise(axiom.premise());
10861188
exprt body(axiom.body());
10871189
implies_exprt instance(premise, body);
1190+
replace_expr(symbol_resolve, instance);
10881191
replace_expr(axiom.univ_var(), val, instance);
10891192
debug() << "adding counter example " << from_expr(instance) << eom;
10901193
add_lemma(instance);

0 commit comments

Comments
 (0)