Skip to content

Commit 0910010

Browse files
Fix string constraints
For the PASS algorithm, the premise should be of a form that can be analyzed by the index set construction. For now the index set only works with the explicit bounds of the string constraints, so the premise should not be used for now.
1 parent 7586f76 commit 0910010

8 files changed

+59
-49
lines changed

src/solvers/refinement/string_constraint.h

+1-12
Original file line numberDiff line numberDiff line change
@@ -93,36 +93,25 @@ class string_constraintt : public exprt
9393
const symbol_exprt &_univ_var,
9494
const exprt &bound_inf,
9595
const exprt &bound_sup,
96-
const exprt &prem,
9796
const exprt &body):
9897
exprt(ID_string_constraint)
9998
{
100-
copy_to_operands(prem, body);
99+
copy_to_operands(true_exprt(), body);
101100
copy_to_operands(_univ_var, bound_sup, bound_inf);
102101
}
103102

104103
// Default bound inferior is 0
105104
string_constraintt(
106105
const symbol_exprt &_univ_var,
107106
const exprt &bound_sup,
108-
const exprt &prem,
109107
const exprt &body):
110108
string_constraintt(
111109
_univ_var,
112110
from_integer(0, _univ_var.type()),
113111
bound_sup,
114-
prem,
115112
body)
116113
{}
117114

118-
// Default premise is true
119-
string_constraintt(
120-
const symbol_exprt &_univ_var,
121-
const exprt &bound_sup,
122-
const exprt &body):
123-
string_constraintt(_univ_var, bound_sup, true_exprt(), body)
124-
{}
125-
126115
exprt univ_within_bounds() const
127116
{
128117
return and_exprt(

src/solvers/refinement/string_constraint_generator.h

+3
Original file line numberDiff line numberDiff line change
@@ -436,4 +436,7 @@ size_t max_printed_string_length(const typet &type, unsigned long ul_radix);
436436
std::string
437437
utf16_constant_array_to_java(const array_exprt &arr, std::size_t length);
438438

439+
/// \return expression representing the minimum of two expressions
440+
exprt minimum(const exprt &a, const exprt &b);
441+
439442
#endif

src/solvers/refinement/string_constraint_generator_comparison.cpp

+5-4
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,8 @@ exprt string_constraint_generatort::add_axioms_for_equals(
4343
lemmas.push_back(a1);
4444

4545
symbol_exprt qvar=fresh_univ_index("QA_equal", index_type);
46-
string_constraintt a2(qvar, s1.length(), eq, equal_exprt(s1[qvar], s2[qvar]));
46+
string_constraintt a2(
47+
qvar, s1.length(), implies_exprt(eq, equal_exprt(s1[qvar], s2[qvar])));
4748
constraints.push_back(a2);
4849

4950
symbol_exprt witness=fresh_exist_index("witness_unequal", index_type);
@@ -130,7 +131,7 @@ exprt string_constraint_generatort::add_axioms_for_equals_ignore_case(
130131
fresh_univ_index("QA_equal_ignore_case", index_type);
131132
const exprt constr2 =
132133
character_equals_ignore_case(s1[qvar], s2[qvar], char_a, char_A, char_Z);
133-
const string_constraintt a2(qvar, s1.length(), eq, constr2);
134+
const string_constraintt a2(qvar, s1.length(), implies_exprt(eq, constr2));
134135
constraints.push_back(a2);
135136

136137
const symbol_exprt witness =
@@ -224,7 +225,7 @@ exprt string_constraint_generatort::add_axioms_for_compare_to(
224225

225226
const symbol_exprt i = fresh_univ_index("QA_compare_to", index_type);
226227
const string_constraintt a2(
227-
i, s1.length(), res_null, equal_exprt(s1[i], s2[i]));
228+
i, s1.length(), implies_exprt(res_null, equal_exprt(s1[i], s2[i])));
228229
constraints.push_back(a2);
229230

230231
const symbol_exprt x = fresh_exist_index("index_compare_to", index_type);
@@ -255,7 +256,7 @@ exprt string_constraint_generatort::add_axioms_for_compare_to(
255256

256257
const symbol_exprt i2 = fresh_univ_index("QA_compare_to", index_type);
257258
const string_constraintt a4(
258-
i2, x, not_exprt(res_null), equal_exprt(s1[i2], s2[i2]));
259+
i2, x, implies_exprt(not_exprt(res_null), equal_exprt(s1[i2], s2[i2])));
259260
constraints.push_back(a4);
260261

261262
return res;

src/solvers/refinement/string_constraint_generator_indexof.cpp

+10-9
Original file line numberDiff line numberDiff line change
@@ -65,16 +65,15 @@ exprt string_constraint_generatort::add_axioms_for_index_of(
6565

6666
symbol_exprt n=fresh_univ_index("QA_index_of", index_type);
6767
string_constraintt a4(
68-
n, lower_bound, index, contains, not_exprt(equal_exprt(str[n], c)));
68+
n, lower_bound, index, implies_exprt(contains, notequal_exprt(str[n], c)));
6969
constraints.push_back(a4);
7070

7171
symbol_exprt m=fresh_univ_index("QA_index_of", index_type);
7272
string_constraintt a5(
7373
m,
7474
lower_bound,
7575
str.length(),
76-
not_exprt(contains),
77-
not_exprt(equal_exprt(str[m], c)));
76+
implies_exprt(not_exprt(contains), not_exprt(equal_exprt(str[m], c))));
7877
constraints.push_back(a5);
7978

8079
return index;
@@ -130,8 +129,8 @@ exprt string_constraint_generatort::add_axioms_for_index_of_string(
130129
string_constraintt a3(
131130
qvar,
132131
needle.length(),
133-
contains,
134-
equal_exprt(haystack[plus_exprt(qvar, offset)], needle[qvar]));
132+
implies_exprt(
133+
contains, equal_exprt(haystack[plus_exprt(qvar, offset)], needle[qvar])));
135134
constraints.push_back(a3);
136135

137136
// string_not contains_constraintt are formulas of the form:
@@ -221,7 +220,8 @@ exprt string_constraint_generatort::add_axioms_for_last_index_of_string(
221220

222221
symbol_exprt qvar=fresh_univ_index("QA_index_of_string", index_type);
223222
equal_exprt constr3(haystack[plus_exprt(qvar, offset)], needle[qvar]);
224-
string_constraintt a3(qvar, needle.length(), contains, constr3);
223+
const string_constraintt a3(
224+
qvar, needle.length(), implies_exprt(contains, constr3));
225225
constraints.push_back(a3);
226226

227227
// end_index is min(from_index, |str| - |substring|)
@@ -364,13 +364,14 @@ exprt string_constraint_generatort::add_axioms_for_last_index_of(
364364
n,
365365
plus_exprt(index, index1),
366366
end_index,
367-
contains,
368-
notequal_exprt(str[n], c));
367+
implies_exprt(contains, notequal_exprt(str[n], c)));
369368
constraints.push_back(a4);
370369

371370
const symbol_exprt m = fresh_univ_index("QA_last_index_of2", index_type);
372371
const string_constraintt a5(
373-
m, end_index, not_exprt(contains), notequal_exprt(str[m], c));
372+
m,
373+
end_index,
374+
implies_exprt(not_exprt(contains), notequal_exprt(str[m], c)));
374375
constraints.push_back(a5);
375376

376377
return index;

src/solvers/refinement/string_constraint_generator_main.cpp

+6-1
Original file line numberDiff line numberDiff line change
@@ -369,7 +369,7 @@ void string_constraint_generatort::add_constraint_on_characters(
369369
const and_exprt char_in_set(
370370
binary_relation_exprt(chr, ID_ge, from_integer(low_char, chr.type())),
371371
binary_relation_exprt(chr, ID_le, from_integer(high_char, chr.type())));
372-
const string_constraintt sc(qvar, start, end, true_exprt(), char_in_set);
372+
const string_constraintt sc(qvar, start, end, char_in_set);
373373
constraints.push_back(sc);
374374
}
375375

@@ -662,3 +662,8 @@ exprt string_constraint_generatort::add_axioms_for_char_at(
662662
lemmas.push_back(equal_exprt(char_sym, str[f.arguments()[1]]));
663663
return char_sym;
664664
}
665+
666+
exprt minimum(const exprt &a, const exprt &b)
667+
{
668+
return if_exprt(binary_relation_exprt(a, ID_le, b), a, b);
669+
}

src/solvers/refinement/string_constraint_generator_testing.cpp

+8-4
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,8 @@ exprt string_constraint_generatort::add_axioms_for_is_prefix(
4646
string_constraintt a2(
4747
qvar,
4848
prefix.length(),
49-
isprefix,
50-
equal_exprt(str[plus_exprt(qvar, offset)], prefix[qvar]));
49+
implies_exprt(
50+
isprefix, equal_exprt(str[plus_exprt(qvar, offset)], prefix[qvar])));
5151
constraints.push_back(a2);
5252

5353
symbol_exprt witness=fresh_exist_index("witness_not_isprefix", index_type);
@@ -153,7 +153,9 @@ exprt string_constraint_generatort::add_axioms_for_is_suffix(
153153
symbol_exprt qvar=fresh_univ_index("QA_suffix", index_type);
154154
const plus_exprt qvar_shifted(qvar, minus_exprt(s1.length(), s0.length()));
155155
string_constraintt a2(
156-
qvar, s0.length(), issuffix, equal_exprt(s0[qvar], s1[qvar_shifted]));
156+
qvar,
157+
s0.length(),
158+
implies_exprt(issuffix, equal_exprt(s0[qvar], s1[qvar_shifted])));
157159
constraints.push_back(a2);
158160

159161
symbol_exprt witness=fresh_exist_index("witness_not_suffix", index_type);
@@ -221,7 +223,9 @@ exprt string_constraint_generatort::add_axioms_for_contains(
221223
symbol_exprt qvar=fresh_univ_index("QA_contains", index_type);
222224
const plus_exprt qvar_shifted(qvar, startpos);
223225
string_constraintt a4(
224-
qvar, s1.length(), contains, equal_exprt(s1[qvar], s0[qvar_shifted]));
226+
qvar,
227+
s1.length(),
228+
implies_exprt(contains, equal_exprt(s1[qvar], s0[qvar_shifted])));
225229
constraints.push_back(a4);
226230

227231
string_not_contains_constraintt a5(

src/solvers/refinement/string_constraint_generator_transformation.cpp

+23-18
Original file line numberDiff line numberDiff line change
@@ -45,24 +45,21 @@ exprt string_constraint_generatort::add_axioms_for_set_length(
4545

4646
// We add axioms:
4747
// a1 : |res|=k
48-
// a2 : forall i<|res|. i < |s1| ==> res[i] = s1[i]
49-
// a3 : forall i<|res|. i >= |s1| ==> res[i] = 0
48+
// a2 : forall i< min(|s1|, k) .res[i] = s1[i]
49+
// a3 : forall |s1| <= i < |res|. res[i] = 0
5050

5151
lemmas.push_back(res.axiom_for_has_length(k));
5252

53-
symbol_exprt idx = fresh_univ_index("QA_index_set_length", index_type);
54-
string_constraintt a2(
55-
idx,
56-
res.length(),
57-
s1.axiom_for_length_gt(idx),
58-
equal_exprt(s1[idx], res[idx]));
53+
const symbol_exprt idx = fresh_univ_index("QA_index_set_length", index_type);
54+
const string_constraintt a2(
55+
idx, minimum(s1.length(), k), equal_exprt(s1[idx], res[idx]));
5956
constraints.push_back(a2);
6057

6158
symbol_exprt idx2 = fresh_univ_index("QA_index_set_length2", index_type);
6259
string_constraintt a3(
6360
idx2,
61+
s1.length(),
6462
res.length(),
65-
s1.axiom_for_length_le(idx2),
6663
equal_exprt(res[idx2], constant_char(0, char_type)));
6764
constraints.push_back(a3);
6865

@@ -395,8 +392,8 @@ exprt string_constraint_generatort::add_axioms_for_to_upper_case(
395392
/// These axioms are:
396393
/// 1. \f$ |{\tt res}| = |{\tt str}|\f$
397394
/// 2. \f$ {\tt res}[{\tt pos}]={\tt char}\f$
398-
/// 3. \f$ \forall i<|{\tt res}|.\ i \ne {\tt pos}
399-
/// \Rightarrow {\tt res}[i] = {\tt str}[i]\f$
395+
/// 3. \f$ \forall i < min(|{\tt res}|, pos). {\tt res}[i] = {\tt str}[i]\f$
396+
/// 4. \f$ \forall pos+1 <= i < |{\tt res}|.\ {\tt res}[i] = {\tt str}[i]\f$
400397
/// \param f: function application with arguments integer `|res|`, character
401398
/// pointer `&res[0]`, refined_string `str`, integer `pos`,
402399
/// and character `char`
@@ -413,14 +410,22 @@ exprt string_constraint_generatort::add_axioms_for_char_set(
413410
const exprt &character = f.arguments()[4];
414411

415412
const binary_relation_exprt out_of_bounds(position, ID_ge, str.length());
416-
lemmas.push_back(equal_exprt(res.length(), str.length()));
417-
lemmas.push_back(equal_exprt(res[position], character));
413+
const equal_exprt a1(res.length(), str.length());
414+
lemmas.push_back(a1);
415+
const equal_exprt a2(res[position], character);
416+
lemmas.push_back(a2);
417+
418418
const symbol_exprt q = fresh_univ_index("QA_char_set", position.type());
419-
equal_exprt a3_body(res[q], str[q]);
420-
notequal_exprt a3_guard(q, position);
421-
constraints.push_back(
422-
string_constraintt(
423-
q, from_integer(0, q.type()), res.length(), a3_guard, a3_body));
419+
const equal_exprt a3_body(res[q], str[q]);
420+
const string_constraintt a3(q, minimum(res.length(), position), a3_body);
421+
constraints.push_back(a3);
422+
423+
const symbol_exprt q2 = fresh_univ_index("QA_char_set2", position.type());
424+
const plus_exprt lower_bound(position, from_integer(1, position.type()));
425+
const equal_exprt a4_body(res[q2], str[q2]);
426+
const string_constraintt a4(q2, lower_bound, res.length(), a4_body);
427+
constraints.push_back(a4);
428+
424429
return if_exprt(
425430
out_of_bounds, from_integer(1, f.type()), from_integer(0, f.type()));
426431
}

src/solvers/refinement/string_refinement.cpp

+3-1
Original file line numberDiff line numberDiff line change
@@ -1549,10 +1549,12 @@ static std::pair<bool, std::vector<exprt>> check_axioms(
15491549
const exprt &bound_inf=axiom.lower_bound();
15501550
const exprt &bound_sup=axiom.upper_bound();
15511551
const exprt &prem=axiom.premise();
1552+
INVARIANT(
1553+
prem == true_exprt(), "string constraint premises are not supported");
15521554
const exprt &body=axiom.body();
15531555

15541556
const string_constraintt axiom_in_model(
1555-
univ_var, get(bound_inf), get(bound_sup), get(prem), get(body));
1557+
univ_var, get(bound_inf), get(bound_sup), get(body));
15561558

15571559
exprt negaxiom=negation_of_constraint(axiom_in_model);
15581560
negaxiom = simplify_expr(negaxiom, ns);

0 commit comments

Comments
 (0)