Skip to content

Commit 5f96226

Browse files
Fix string constraints for substring
It was previously not clear what could happen when the argument of substring were out of bounds. This is now clearly specified and avoids getting formulas with array accesses at negative indexes in particular.
1 parent 9ff1e82 commit 5f96226

File tree

3 files changed

+24
-25
lines changed

3 files changed

+24
-25
lines changed

src/solvers/refinement/string_constraint_generator.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -439,4 +439,7 @@ utf16_constant_array_to_java(const array_exprt &arr, std::size_t length);
439439
/// \return expression representing the minimum of two expressions
440440
exprt minimum(const exprt &a, const exprt &b);
441441

442+
/// \return expression representing the maximum of two expressions
443+
exprt maximum(const exprt &a, const exprt &b);
444+
442445
#endif

src/solvers/refinement/string_constraint_generator_main.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -667,3 +667,8 @@ exprt minimum(const exprt &a, const exprt &b)
667667
{
668668
return if_exprt(binary_relation_exprt(a, ID_le, b), a, b);
669669
}
670+
671+
exprt maximum(const exprt &a, const exprt &b)
672+
{
673+
return if_exprt(binary_relation_exprt(a, ID_le, b), b, a);
674+
}

src/solvers/refinement/string_constraint_generator_transformation.cpp

Lines changed: 16 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -98,16 +98,14 @@ exprt string_constraint_generatort::add_axioms_for_substring(
9898
}
9999

100100
/// Add axioms ensuring that `res` corresponds to the substring of `str`
101-
/// between indexes `start` and `end`.
101+
/// between indexes `start' = max(start, 0)` and
102+
/// `end' = max(min(end, |str|), start')`.
102103
///
103104
/// These axioms are:
104-
/// 1. \f$ {\tt start} < {\tt end} \Rightarrow
105-
/// |{\tt res}| = {\tt end} - {\tt start} \f$
106-
/// 2. \f$ {\tt start} \ge {\tt end} \Rightarrow |{\tt res}| = 0 \f$
107-
/// 3. \f$ |{\tt str}| > {\tt end} \f$
108-
/// 4. \f$ \forall i<|{\tt str}|.\ {\tt res}[i]={\tt str}[{\tt start}+i] \f$
109-
/// \todo Should return code different from 0 if `|str| <= |end|` instead of
110-
/// adding constraint 3.
105+
/// 1. \f$ |{\tt res}| = end' - start' \f$
106+
/// 2. \f$ \forall i<|{\tt res}|.\ {\tt res}[i]={\tt str}[{\tt start'}+i] \f$
107+
/// \todo Should return code different from 0 if `start' != start` or
108+
/// `end' != end`
111109
/// \param res: array of characters expression
112110
/// \param str: array of characters expression
113111
/// \param start: integer expression
@@ -123,26 +121,19 @@ exprt string_constraint_generatort::add_axioms_for_substring(
123121
PRECONDITION(start.type()==index_type);
124122
PRECONDITION(end.type()==index_type);
125123

126-
// We add axioms:
124+
const exprt start1 = maximum(start, from_integer(0, start.type()));
125+
const exprt end1 = maximum(minimum(end, str.length()), start1);
127126

128-
implies_exprt a1(
129-
binary_relation_exprt(start, ID_lt, end),
130-
res.axiom_for_has_length(minus_exprt(end, start)));
131-
lemmas.push_back(a1);
127+
// Axiom 1.
128+
lemmas.push_back(equal_exprt(res.length(), minus_exprt(end1, start1)));
132129

133-
exprt is_empty=res.axiom_for_has_length(from_integer(0, index_type));
134-
implies_exprt a2(binary_relation_exprt(start, ID_ge, end), is_empty);
135-
lemmas.push_back(a2);
130+
// Axiom 2.
131+
constraints.push_back([&] { // NOLINT
132+
const symbol_exprt idx = fresh_univ_index("QA_index_substring", index_type);
133+
return string_constraintt(
134+
idx, res.length(), equal_exprt(res[idx], str[plus_exprt(start1, idx)]));
135+
}());
136136

137-
// Warning: check what to do if the string is not long enough
138-
lemmas.push_back(str.axiom_for_length_ge(end));
139-
140-
symbol_exprt idx=fresh_univ_index("QA_index_substring", index_type);
141-
string_constraintt a4(idx,
142-
res.length(),
143-
equal_exprt(res[idx],
144-
str[plus_exprt(start, idx)]));
145-
constraints.push_back(a4);
146137
return from_integer(0, signedbv_typet(32));
147138
}
148139

0 commit comments

Comments
 (0)