Skip to content

Commit ad9b86c

Browse files
Fix add_axioms_for_concat_substr
What was happening for start and end index out of bound wasn't clear and could lead to empty index set because the strings where sometimes indexed at negative indices. The behavior is now similar to substring: the actual start index is `start_index' = max(0, start_index)` (where start_index is the argument value) and the actual end index is `max(min(end_index, s2.length), start_index')`.
1 parent b43bbff commit ad9b86c

File tree

1 file changed

+34
-35
lines changed

1 file changed

+34
-35
lines changed

src/solvers/refinement/string_constraint_generator_concat.cpp

+34-35
Original file line numberDiff line numberDiff line change
@@ -14,22 +14,16 @@ Author: Romain Brenguier, [email protected]
1414
#include <solvers/refinement/string_constraint_generator.h>
1515

1616
/// Add axioms enforcing that `res` is the concatenation of `s1` with
17-
/// the substring of `s2` starting at index `start_index` and ending
18-
/// at index `end_index`.
19-
///
20-
/// If `start_index >= end_index`, the value returned is `s1`.
21-
/// If `end_index > |s2|` and/or `start_index < 0`, the appended string will
22-
/// be of length `end_index - start_index` and padded with non-deterministic
23-
/// values.
17+
/// the substring of `s2` starting at index `start_index'` and ending
18+
/// at index `end_index'`.
19+
/// Where start_index' is max(0, start_index) and end_index' is
20+
/// max(min(end_index, s2.length), start_index')
2421
///
2522
/// These axioms are:
26-
/// 1. \f$end\_index > start\_index \Rightarrow |res| = |s_1| + end\_index -
27-
/// start\_index
28-
/// \f$
29-
/// 2. \f$end\_index \le start\_index \Rightarrow res = s_1 \f$
30-
/// 3. \f$\forall i<|s_1|. res[i]=s_1[i] \f$
31-
/// 4. \f$\forall i< end\_index - start\_index.\ res[i+|s_1|]
32-
/// = s_2[start\_index+i]\f$
23+
/// 1. \f$|res| = |s_1| + end\_index' - start\_index' \f$
24+
/// 2. \f$\forall i<|s_1|. res[i]=s_1[i] \f$
25+
/// 3. \f$\forall i< end\_index' - start\_index'.\ res[i+|s_1|]
26+
/// = s_2[start\_index'+i]\f$
3327
///
3428
/// \param res: an array of characters expression
3529
/// \param s1: an array of characters expression
@@ -44,28 +38,33 @@ exprt string_constraint_generatort::add_axioms_for_concat_substr(
4438
const exprt &start_index,
4539
const exprt &end_index)
4640
{
47-
binary_relation_exprt prem(end_index, ID_gt, start_index);
48-
49-
exprt res_length=plus_exprt_with_overflow_check(
50-
s1.length(), minus_exprt(end_index, start_index));
51-
implies_exprt a1(prem, equal_exprt(res.length(), res_length));
52-
lemmas.push_back(a1);
53-
54-
implies_exprt a2(not_exprt(prem), equal_exprt(res.length(), s1.length()));
55-
lemmas.push_back(a2);
41+
const typet &index_type = start_index.type();
42+
const exprt start1 = maximum(start_index, from_integer(0, index_type));
43+
const exprt end1 = maximum(minimum(end_index, s2.length()), start1);
44+
45+
// Axiom 1.
46+
lemmas.push_back([&] { // NOLINT
47+
const plus_exprt res_length(s1.length(), minus_exprt(end1, start1));
48+
return equal_exprt(res.length(), res_length);
49+
}());
50+
51+
// Axiom 2.
52+
constraints.push_back([&] { // NOLINT
53+
const symbol_exprt idx =
54+
fresh_univ_index("QA_index_concat", res.length().type());
55+
return string_constraintt(idx, s1.length(), equal_exprt(s1[idx], res[idx]));
56+
}());
57+
58+
// Axiom 3.
59+
constraints.push_back([&] { // NOLINT
60+
const symbol_exprt idx2 =
61+
fresh_univ_index("QA_index_concat2", res.length().type());
62+
const equal_exprt res_eq(
63+
res[plus_exprt(idx2, s1.length())], s2[plus_exprt(start1, idx2)]);
64+
return string_constraintt(idx2, minus_exprt(end1, start1), res_eq);
65+
}());
5666

57-
symbol_exprt idx=fresh_univ_index("QA_index_concat", res.length().type());
58-
string_constraintt a3(idx, s1.length(), equal_exprt(s1[idx], res[idx]));
59-
constraints.push_back(a3);
60-
61-
symbol_exprt idx2=fresh_univ_index("QA_index_concat2", res.length().type());
62-
equal_exprt res_eq(
63-
res[plus_exprt(idx2, s1.length())], s2[plus_exprt(start_index, idx2)]);
64-
string_constraintt a4(idx2, minus_exprt(end_index, start_index), res_eq);
65-
constraints.push_back(a4);
66-
67-
// We should have a enum type for the possible error codes
68-
return from_integer(0, res.length().type());
67+
return from_integer(0, get_return_code_type());
6968
}
7069

7170
/// Add axioms enforcing that `res` is the concatenation of `s1` with

0 commit comments

Comments
 (0)