Skip to content

Commit 2e115f1

Browse files
Merge pull request #1104 from romainbrenguier/feature/string-solver-if-expr#275
Handling of if_exprt in string solver
2 parents 2c29180 + 05ffc71 commit 2e115f1

File tree

6 files changed

+101
-13
lines changed

6 files changed

+101
-13
lines changed
914 Bytes
Binary file not shown.
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
CORE
2+
test.class
3+
--refine-strings --string-max-length 100
4+
^EXIT=10$
5+
^SIGNAL=0$
6+
^\[.*assertion.1\].* line 12.* SUCCESS$
7+
^\[.*assertion.2\].* line 13.* FAILURE$
8+
--
9+
$ignoring\s*char\s*array
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
public class test
2+
{
3+
public static String main()
4+
{
5+
Object t[] = new Object[5];
6+
t[0] = "world!";
7+
StringBuilder s = new StringBuilder("Hello ");
8+
if(t[0] instanceof String)
9+
{
10+
s.append((String) t[0]);
11+
}
12+
assert(s.toString().equals("Hello world!"));
13+
assert(!s.toString().equals("Hello world!"));
14+
return s.toString();
15+
}
16+
}

src/solvers/refinement/string_constraint_generator.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,9 @@ class string_constraint_generatort
9494

9595
static constant_exprt constant_char(int i, const typet &char_type);
9696

97+
// Used by string refinement
98+
void add_axioms_for_if_array(const exprt &lhs, const if_exprt &expr);
99+
97100
private:
98101
// The integer with the longest string is Integer.MIN_VALUE which is -2^31,
99102
// that is -2147483648 so takes 11 characters to write.

src/solvers/refinement/string_constraint_generator_main.cpp

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,46 @@ string_exprt string_constraint_generatort::add_axioms_for_if(
272272
return res;
273273
}
274274

275+
/// Add axioms enforcing that the content of the first array is equal to
276+
/// the true case array if the condition is true and
277+
/// the else case array otherwise.
278+
/// \param lhs: an expression
279+
/// \param expr: an if expression of type array
280+
void string_constraint_generatort::add_axioms_for_if_array(
281+
const exprt &lhs, const if_exprt &expr)
282+
{
283+
PRECONDITION(lhs.type()==expr.type());
284+
PRECONDITION(expr.type().id()==ID_array);
285+
exprt t=expr.true_case();
286+
exprt f=expr.false_case();
287+
INVARIANT(t.type()==f.type(), "branches of if_exprt should have same type");
288+
const array_typet &type=to_array_type(t.type());
289+
const typet &index_type=type.size().type();
290+
const exprt max_length=from_integer(max_string_length, index_type);
291+
292+
// We add axioms:
293+
// a1 : forall qvar<max_length, cond => lhs[qvar] = t[qvar]
294+
// a1 : forall qvar2<max_length, !cond => lhs[qvar] = f[qvar]
295+
symbol_exprt qvar=fresh_univ_index("QA_array_if_true", index_type);
296+
equal_exprt qequal(index_exprt(lhs, qvar), index_exprt(t, qvar));
297+
298+
// In case t is a constant array of fixed length is does not make sense
299+
// to talk about indexes exceeding this length
300+
exprt upper_bound_t=
301+
(t.id()==ID_array)?from_integer(t.operands().size(), index_type):max_length;
302+
string_constraintt a1(qvar, upper_bound_t, expr.cond(), qequal);
303+
axioms.push_back(a1);
304+
305+
symbol_exprt qvar2=fresh_univ_index("QA_array_if_false", index_type);
306+
equal_exprt qequal2(index_exprt(lhs, qvar2), index_exprt(f, qvar2));
307+
// In case f is a constant array of fixed length is does not make sense
308+
// to talk about indexes exceeding this length
309+
exprt upper_bound_f=
310+
(f.id()==ID_array)?from_integer(f.operands().size(), index_type):max_length;
311+
string_constraintt a2(qvar2, upper_bound_f, not_exprt(expr.cond()), qequal2);
312+
axioms.push_back(a2);
313+
}
314+
275315
/// if a symbol representing a string is present in the symbol_to_string table,
276316
/// returns the corresponding string, if the symbol is not yet present, creates
277317
/// a new string with the correct type depending on whether the mode is java or

src/solvers/refinement/string_refinement.cpp

Lines changed: 33 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -218,16 +218,20 @@ bool string_refinementt::add_axioms_for_string_assigns(
218218
add_symbol_to_symbol_map(lhs, rhs);
219219
return false;
220220
}
221-
else if(rhs.id() == ID_nondet_symbol)
221+
else if(rhs.id()==ID_nondet_symbol)
222222
{
223223
add_symbol_to_symbol_map(
224224
lhs, generator.fresh_symbol("nondet_array", lhs.type()));
225225
return false;
226226
}
227+
else if(rhs.id()==ID_if)
228+
{
229+
generator.add_axioms_for_if_array(lhs, to_if_expr(rhs));
230+
return false;
231+
}
227232
else
228233
{
229-
debug() << "string_refinement warning: not handling char_array: "
230-
<< from_expr(ns, "", rhs) << eom;
234+
warning() << "ignoring char array " << from_expr(ns, "", rhs) << eom;
231235
return true;
232236
}
233237
}
@@ -370,8 +374,8 @@ void string_refinementt::set_to(const exprt &expr, bool value)
370374

371375
if(eq_expr.lhs().type()!=eq_expr.rhs().type())
372376
{
373-
debug() << "(sr::set_to) WARNING: ignoring "
374-
<< from_expr(ns, "", expr) << " [inconsistent types]" << eom;
377+
warning() << "ignoring " << from_expr(ns, "", expr)
378+
<< " [inconsistent types]" << eom;
375379
debug() << "lhs has type: " << eq_expr.lhs().type().pretty(12) << eom;
376380
debug() << "rhs has type: " << eq_expr.rhs().type().pretty(12) << eom;
377381
return;
@@ -392,8 +396,7 @@ void string_refinementt::set_to(const exprt &expr, bool value)
392396
// TODO: See if this happens at all.
393397
if(lhs.id()!=ID_symbol)
394398
{
395-
debug() << "(sr::set_to) WARNING: ignoring "
396-
<< from_expr(ns, "", expr) << eom;
399+
warning() << "ignoring " << from_expr(ns, "", expr) << eom;
397400
return;
398401
}
399402

@@ -404,9 +407,8 @@ void string_refinementt::set_to(const exprt &expr, bool value)
404407
subst_rhs.type().id() != ID_array ||
405408
eq_expr.lhs().type().subtype() != subst_rhs.type().subtype())
406409
{
407-
debug() << "(sr::set_to) WARNING: ignoring "
408-
<< from_expr(ns, "", expr) << " [inconsistent types after substitution]"
409-
<< eom;
410+
warning() << "ignoring " << from_expr(ns, "", expr)
411+
<< " [inconsistent types after substitution]" << eom;
410412
return;
411413
}
412414
else
@@ -857,9 +859,15 @@ exprt string_refinementt::substitute_array_with_expr(
857859
}
858860

859861
/// create an equivalent expression where array accesses and 'with' expressions
860-
/// are replaced by 'if' expressions. e.g. for an array access arr[x], where:
861-
/// `arr := {12, 24, 48}` the constructed expression will be: `index==0 ? 12 :
862-
/// index==1 ? 24 : 48`
862+
/// are replaced by 'if' expressions, in particular:
863+
/// * for an array access `arr[x]`, where:
864+
/// `arr := {12, 24, 48}` the constructed expression will be:
865+
/// `index==0 ? 12 : index==1 ? 24 : 48`
866+
/// * for an array access `arr[x]`, where:
867+
/// `arr := array_of(12) with {0:=24} with {2:=42}` the constructed
868+
/// expression will be: `index==0 ? 24 : index==2 ? 42 : 12`
869+
/// * for an array access `(g1?arr1:arr2)[x]` where `arr1 := {12}` and
870+
/// `arr2 := {34}`, the constructed expression will be: `g1 ? 12 : 34`
863871
/// \param expr: an expression containing array accesses
864872
/// \return an expression containing no array access
865873
void string_refinementt::substitute_array_access(exprt &expr) const
@@ -890,6 +898,18 @@ void string_refinementt::substitute_array_access(exprt &expr) const
890898
return;
891899
}
892900

901+
if(index_expr.array().id()==ID_if)
902+
{
903+
// Substitute recursively in branches of conditional expressions
904+
if_exprt if_expr=to_if_expr(index_expr.array());
905+
exprt true_case=index_exprt(if_expr.true_case(), index_expr.index());
906+
substitute_array_access(true_case);
907+
exprt false_case=index_exprt(if_expr.false_case(), index_expr.index());
908+
substitute_array_access(false_case);
909+
expr=if_exprt(if_expr.cond(), true_case, false_case);
910+
return;
911+
}
912+
893913
assert(index_expr.array().id()==ID_array);
894914
array_exprt &array_expr=to_array_expr(index_expr.array());
895915

0 commit comments

Comments
 (0)