Skip to content

Commit f01c03c

Browse files
author
Joel Allred
committed
Fix string_constraintt bound values
Some of the bounds could be negative, potentially leading to inconsistencies in the index set. Bounds that are at risk have been replaced by `maximum(0, old_bound)`.
1 parent 6ccce5b commit f01c03c

8 files changed

+67
-36
lines changed

src/solvers/refinement/string_constraint_generator.h

+1
Original file line numberDiff line numberDiff line change
@@ -458,4 +458,5 @@ exprt length_constraint_for_insert(
458458
const array_string_exprt &s1,
459459
const array_string_exprt &s2);
460460

461+
exprt zero_if_negative(const exprt &expr);
461462
#endif

src/solvers/refinement/string_constraint_generator_comparison.cpp

+11-4
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,9 @@ exprt string_constraint_generatort::add_axioms_for_equals(
4545

4646
symbol_exprt qvar=fresh_univ_index("QA_equal", index_type);
4747
string_constraintt a2(
48-
qvar, s1.length(), implies_exprt(eq, equal_exprt(s1[qvar], s2[qvar])));
48+
qvar,
49+
zero_if_negative(s1.length()),
50+
implies_exprt(eq, equal_exprt(s1[qvar], s2[qvar])));
4951
constraints.push_back(a2);
5052

5153
symbol_exprt witness=fresh_exist_index("witness_unequal", index_type);
@@ -132,7 +134,8 @@ exprt string_constraint_generatort::add_axioms_for_equals_ignore_case(
132134
fresh_univ_index("QA_equal_ignore_case", index_type);
133135
const exprt constr2 =
134136
character_equals_ignore_case(s1[qvar], s2[qvar], char_a, char_A, char_Z);
135-
const string_constraintt a2(qvar, s1.length(), implies_exprt(eq, constr2));
137+
const string_constraintt a2(
138+
qvar, zero_if_negative(s1.length()), implies_exprt(eq, constr2));
136139
constraints.push_back(a2);
137140

138141
const symbol_exprt witness =
@@ -226,7 +229,9 @@ exprt string_constraint_generatort::add_axioms_for_compare_to(
226229

227230
const symbol_exprt i = fresh_univ_index("QA_compare_to", index_type);
228231
const string_constraintt a2(
229-
i, s1.length(), implies_exprt(res_null, equal_exprt(s1[i], s2[i])));
232+
i,
233+
zero_if_negative(s1.length()),
234+
implies_exprt(res_null, equal_exprt(s1[i], s2[i])));
230235
constraints.push_back(a2);
231236

232237
const symbol_exprt x = fresh_exist_index("index_compare_to", index_type);
@@ -257,7 +262,9 @@ exprt string_constraint_generatort::add_axioms_for_compare_to(
257262

258263
const symbol_exprt i2 = fresh_univ_index("QA_compare_to", index_type);
259264
const string_constraintt a4(
260-
i2, x, implies_exprt(not_exprt(res_null), equal_exprt(s1[i2], s2[i2])));
265+
i2,
266+
zero_if_negative(x),
267+
implies_exprt(not_exprt(res_null), equal_exprt(s1[i2], s2[i2])));
261268
constraints.push_back(a4);
262269

263270
return res;

src/solvers/refinement/string_constraint_generator_concat.cpp

+5-3
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,8 @@ exprt string_constraint_generatort::add_axioms_for_concat_substr(
5353
constraints.push_back([&] { // NOLINT
5454
const symbol_exprt idx =
5555
fresh_univ_index("QA_index_concat", res.length().type());
56-
return string_constraintt(idx, s1.length(), equal_exprt(s1[idx], res[idx]));
56+
return string_constraintt(
57+
idx, zero_if_negative(s1.length()), equal_exprt(s1[idx], res[idx]));
5758
}());
5859

5960
// Axiom 3.
@@ -63,7 +64,7 @@ exprt string_constraint_generatort::add_axioms_for_concat_substr(
6364
const equal_exprt res_eq(
6465
res[plus_exprt(idx2, s1.length())], s2[plus_exprt(start1, idx2)]);
6566
const minus_exprt upper_bound(res.length(), s1.length());
66-
return string_constraintt(idx2, upper_bound, res_eq);
67+
return string_constraintt(idx2, zero_if_negative(upper_bound), res_eq);
6768
}());
6869

6970
return from_integer(0, get_return_code_type());
@@ -120,7 +121,8 @@ exprt string_constraint_generatort::add_axioms_for_concat_char(
120121
lemmas.push_back(length_constraint_for_concat_char(res, s1));
121122

122123
symbol_exprt idx = fresh_univ_index("QA_index_concat_char", index_type);
123-
string_constraintt a2(idx, s1.length(), equal_exprt(s1[idx], res[idx]));
124+
string_constraintt a2(
125+
idx, zero_if_negative(s1.length()), equal_exprt(s1[idx], res[idx]));
124126
constraints.push_back(a2);
125127

126128
equal_exprt a3(res[s1.length()], c);

src/solvers/refinement/string_constraint_generator_indexof.cpp

+11-10
Original file line numberDiff line numberDiff line change
@@ -59,20 +59,21 @@ exprt string_constraint_generatort::add_axioms_for_index_of(
5959
equal_exprt(str[index], c)));
6060
lemmas.push_back(a3);
6161

62-
const auto zero = from_integer(0, index_type);
63-
const if_exprt lower_bound(
64-
binary_relation_exprt(from_index, ID_le, zero), zero, from_index);
62+
const exprt lower_bound(zero_if_negative(from_index));
6563

6664
symbol_exprt n=fresh_univ_index("QA_index_of", index_type);
6765
string_constraintt a4(
68-
n, lower_bound, index, implies_exprt(contains, notequal_exprt(str[n], c)));
66+
n,
67+
lower_bound,
68+
zero_if_negative(index),
69+
implies_exprt(contains, notequal_exprt(str[n], c)));
6970
constraints.push_back(a4);
7071

7172
symbol_exprt m=fresh_univ_index("QA_index_of", index_type);
7273
string_constraintt a5(
7374
m,
7475
lower_bound,
75-
str.length(),
76+
zero_if_negative(str.length()),
7677
implies_exprt(not_exprt(contains), not_exprt(equal_exprt(str[m], c))));
7778
constraints.push_back(a5);
7879

@@ -128,7 +129,7 @@ exprt string_constraint_generatort::add_axioms_for_index_of_string(
128129
symbol_exprt qvar=fresh_univ_index("QA_index_of_string", index_type);
129130
string_constraintt a3(
130131
qvar,
131-
needle.length(),
132+
zero_if_negative(needle.length()),
132133
implies_exprt(
133134
contains, equal_exprt(haystack[plus_exprt(qvar, offset)], needle[qvar])));
134135
constraints.push_back(a3);
@@ -221,7 +222,7 @@ exprt string_constraint_generatort::add_axioms_for_last_index_of_string(
221222
symbol_exprt qvar=fresh_univ_index("QA_index_of_string", index_type);
222223
equal_exprt constr3(haystack[plus_exprt(qvar, offset)], needle[qvar]);
223224
const string_constraintt a3(
224-
qvar, needle.length(), implies_exprt(contains, constr3));
225+
qvar, zero_if_negative(needle.length()), implies_exprt(contains, constr3));
225226
constraints.push_back(a3);
226227

227228
// end_index is min(from_index, |str| - |substring|)
@@ -361,15 +362,15 @@ exprt string_constraint_generatort::add_axioms_for_last_index_of(
361362
const symbol_exprt n = fresh_univ_index("QA_last_index_of1", index_type);
362363
const string_constraintt a4(
363364
n,
364-
plus_exprt(index, index1),
365-
end_index,
365+
zero_if_negative(plus_exprt(index, index1)),
366+
zero_if_negative(end_index),
366367
implies_exprt(contains, notequal_exprt(str[n], c)));
367368
constraints.push_back(a4);
368369

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

src/solvers/refinement/string_constraint_generator_insert.cpp

+4-2
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,9 @@ exprt string_constraint_generatort::add_axioms_for_insert(
5353
constraints.push_back([&] { // NOLINT
5454
const symbol_exprt i = fresh_symbol("QA_insert2", index_type);
5555
return string_constraintt(
56-
i, s2.length(), equal_exprt(res[plus_exprt(i, offset1)], s2[i]));
56+
i,
57+
zero_if_negative(s2.length()),
58+
equal_exprt(res[plus_exprt(i, offset1)], s2[i]));
5759
}());
5860

5961
// Axiom 4.
@@ -62,7 +64,7 @@ exprt string_constraint_generatort::add_axioms_for_insert(
6264
return string_constraintt(
6365
i,
6466
offset1,
65-
s1.length(),
67+
zero_if_negative(s1.length()),
6668
equal_exprt(res[plus_exprt(i, s2.length())], s1[i]));
6769
}());
6870

src/solvers/refinement/string_constraint_generator_main.cpp

+10-1
Original file line numberDiff line numberDiff line change
@@ -324,7 +324,8 @@ void string_constraint_generatort::add_constraint_on_characters(
324324
const and_exprt char_in_set(
325325
binary_relation_exprt(chr, ID_ge, from_integer(low_char, chr.type())),
326326
binary_relation_exprt(chr, ID_le, from_integer(high_char, chr.type())));
327-
const string_constraintt sc(qvar, start, end, char_in_set);
327+
const string_constraintt sc(
328+
qvar, zero_if_negative(start), zero_if_negative(end), char_in_set);
328329
constraints.push_back(sc);
329330
}
330331

@@ -627,3 +628,11 @@ exprt maximum(const exprt &a, const exprt &b)
627628
{
628629
return if_exprt(binary_relation_exprt(a, ID_le, b), b, a);
629630
}
631+
632+
/// Returns a non-negative version of the argument.
633+
/// \param expr: expression of which we want a non-negative version
634+
/// \return `max(0, expr)`
635+
exprt zero_if_negative(const exprt &expr)
636+
{
637+
return maximum(from_integer(0, expr.type()), expr);
638+
}

src/solvers/refinement/string_constraint_generator_testing.cpp

+4-3
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,8 @@ exprt string_constraint_generatort::add_axioms_for_is_prefix(
5454
const symbol_exprt qvar = fresh_univ_index("QA_isprefix", index_type);
5555
const exprt body = implies_exprt(
5656
isprefix, equal_exprt(str[plus_exprt(qvar, offset)], prefix[qvar]));
57-
return string_constraintt(qvar, prefix.length(), body);
57+
return string_constraintt(
58+
qvar, maximum(from_integer(0, index_type), prefix.length()), body);
5859
}());
5960

6061
// Axiom 3.
@@ -169,7 +170,7 @@ exprt string_constraint_generatort::add_axioms_for_is_suffix(
169170
const plus_exprt qvar_shifted(qvar, minus_exprt(s1.length(), s0.length()));
170171
string_constraintt a2(
171172
qvar,
172-
s0.length(),
173+
zero_if_negative(s0.length()),
173174
implies_exprt(issuffix, equal_exprt(s0[qvar], s1[qvar_shifted])));
174175
constraints.push_back(a2);
175176

@@ -239,7 +240,7 @@ exprt string_constraint_generatort::add_axioms_for_contains(
239240
const plus_exprt qvar_shifted(qvar, startpos);
240241
string_constraintt a4(
241242
qvar,
242-
s1.length(),
243+
zero_if_negative(s1.length()),
243244
implies_exprt(contains, equal_exprt(s1[qvar], s0[qvar_shifted])));
244245
constraints.push_back(a4);
245246

src/solvers/refinement/string_constraint_generator_transformation.cpp

+21-13
Original file line numberDiff line numberDiff line change
@@ -52,14 +52,16 @@ exprt string_constraint_generatort::add_axioms_for_set_length(
5252

5353
const symbol_exprt idx = fresh_univ_index("QA_index_set_length", index_type);
5454
const string_constraintt a2(
55-
idx, minimum(s1.length(), k), equal_exprt(s1[idx], res[idx]));
55+
idx,
56+
zero_if_negative(minimum(s1.length(), k)),
57+
equal_exprt(s1[idx], res[idx]));
5658
constraints.push_back(a2);
5759

5860
symbol_exprt idx2 = fresh_univ_index("QA_index_set_length2", index_type);
5961
string_constraintt a3(
6062
idx2,
61-
s1.length(),
62-
res.length(),
63+
zero_if_negative(s1.length()),
64+
zero_if_negative(res.length()),
6365
equal_exprt(res[idx2], constant_char(0, char_type)));
6466
constraints.push_back(a3);
6567

@@ -131,7 +133,9 @@ exprt string_constraint_generatort::add_axioms_for_substring(
131133
constraints.push_back([&] {
132134
const symbol_exprt idx = fresh_univ_index("QA_index_substring", index_type);
133135
return string_constraintt(
134-
idx, res.length(), equal_exprt(res[idx], str[plus_exprt(start1, idx)]));
136+
idx,
137+
zero_if_negative(res.length()),
138+
equal_exprt(res[idx], str[plus_exprt(start1, idx)]));
135139
}());
136140

137141
return from_integer(0, signedbv_typet(32));
@@ -193,7 +197,7 @@ exprt string_constraint_generatort::add_axioms_for_trim(
193197

194198
symbol_exprt n=fresh_univ_index("QA_index_trim", index_type);
195199
binary_relation_exprt non_print(str[n], ID_le, space_char);
196-
string_constraintt a6(n, idx, non_print);
200+
string_constraintt a6(n, zero_if_negative(idx), non_print);
197201
constraints.push_back(a6);
198202

199203
// Axiom 7.
@@ -202,12 +206,12 @@ exprt string_constraint_generatort::add_axioms_for_trim(
202206
const minus_exprt bound(minus_exprt(str.length(), idx), res.length());
203207
const binary_relation_exprt eqn2(
204208
str[plus_exprt(idx, plus_exprt(res.length(), n2))], ID_le, space_char);
205-
return string_constraintt(n2, bound, eqn2);
209+
return string_constraintt(n2, zero_if_negative(bound), eqn2);
206210
}());
207211

208212
symbol_exprt n3=fresh_univ_index("QA_index_trim3", index_type);
209213
equal_exprt eqn3(res[n3], str[plus_exprt(n3, idx)]);
210-
string_constraintt a8(n3, res.length(), eqn3);
214+
string_constraintt a8(n3, zero_if_negative(res.length()), eqn3);
211215
constraints.push_back(a8);
212216

213217
// Axiom 9.
@@ -291,7 +295,8 @@ exprt string_constraint_generatort::add_axioms_for_to_lower_case(
291295
binary_relation_exprt(str[idx], ID_lt, from_integer(0x100, char_type)));
292296
if_exprt conditional_convert(is_upper_case, converted, non_converted);
293297

294-
string_constraintt a2(idx, res.length(), conditional_convert);
298+
string_constraintt a2(
299+
idx, zero_if_negative(res.length()), conditional_convert);
295300
constraints.push_back(a2);
296301

297302
return from_integer(0, f.type());
@@ -338,7 +343,7 @@ exprt string_constraint_generatort::add_axioms_for_to_upper_case(
338343
minus_exprt diff(char_A, char_a);
339344
equal_exprt convert(res[idx1], plus_exprt(str[idx1], diff));
340345
implies_exprt body1(is_lower_case, convert);
341-
string_constraintt a2(idx1, res.length(), body1);
346+
string_constraintt a2(idx1, zero_if_negative(res.length()), body1);
342347
constraints.push_back(a2);
343348

344349
symbol_exprt idx2=fresh_univ_index("QA_upper_case2", index_type);
@@ -348,7 +353,7 @@ exprt string_constraint_generatort::add_axioms_for_to_upper_case(
348353
binary_relation_exprt(str[idx2], ID_le, char_z)));
349354
equal_exprt eq(res[idx2], str[idx2]);
350355
implies_exprt body2(is_not_lower_case, eq);
351-
string_constraintt a3(idx2, res.length(), body2);
356+
string_constraintt a3(idx2, zero_if_negative(res.length()), body2);
352357
constraints.push_back(a3);
353358
return from_integer(0, signedbv_typet(32));
354359
}
@@ -406,13 +411,15 @@ exprt string_constraint_generatort::add_axioms_for_char_set(
406411

407412
const symbol_exprt q = fresh_univ_index("QA_char_set", position.type());
408413
const equal_exprt a3_body(res[q], str[q]);
409-
const string_constraintt a3(q, minimum(res.length(), position), a3_body);
414+
const string_constraintt a3(
415+
q, minimum(zero_if_negative(res.length()), position), a3_body);
410416
constraints.push_back(a3);
411417

412418
const symbol_exprt q2 = fresh_univ_index("QA_char_set2", position.type());
413419
const plus_exprt lower_bound(position, from_integer(1, position.type()));
414420
const equal_exprt a4_body(res[q2], str[q2]);
415-
const string_constraintt a4(q2, lower_bound, res.length(), a4_body);
421+
const string_constraintt a4(
422+
q2, lower_bound, zero_if_negative(res.length()), a4_body);
416423
constraints.push_back(a4);
417424

418425
return if_exprt(
@@ -489,7 +496,8 @@ exprt string_constraint_generatort::add_axioms_for_replace(
489496
implies_exprt case2(
490497
not_exprt(equal_exprt(str[qvar], old_char)),
491498
equal_exprt(res[qvar], str[qvar]));
492-
string_constraintt a2(qvar, res.length(), and_exprt(case1, case2));
499+
string_constraintt a2(
500+
qvar, zero_if_negative(res.length()), and_exprt(case1, case2));
493501
constraints.push_back(a2);
494502
return from_integer(0, f.type());
495503
}

0 commit comments

Comments
 (0)