Skip to content

Commit 530a2dd

Browse files
authored
Merge pull request #1078 from jasigal/fix/contains-mem-issue-511
For contains, added bounds for substring index in !contains case
2 parents c242674 + 939fb87 commit 530a2dd

File tree

10 files changed

+57
-17
lines changed

10 files changed

+57
-17
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
CORE
22
test_contains.class
33
--refine-strings
4-
^EXIT=0$
4+
^EXIT=10$
55
^SIGNAL=0$
66
^\[.*assertion.1\].* line 8.* SUCCESS$
7+
^\[.*assertion.2\].* line 9.* SUCCESS$
8+
^\[.*assertion.3\].* line 12.* FAILURE$
9+
^\[.*assertion.4\].* line 13.* FAILURE$
10+
^VERIFICATION FAILED$
711
--
812
Issue: diffblue/test-gen#201
Binary file not shown.
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
public class test_contains
22
{
3-
public static void main(/*String[] argv*/)
3+
public static void main(String x)
44
{
55
String s = new String("Abc");
66
String u = "bc";
77
String t = "ab";
88
assert(s.contains(u));
9-
// Long version:
10-
// assert(s.contains(t));
9+
assert(!s.contains(t));
10+
11+
String z = new String(x);
12+
if (z.length() > 3) assert(t.contains(z));
13+
else assert(z.contains(u));
1114
}
1215
}
618 Bytes
Binary file not shown.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
FUTURE
2+
test.class
3+
--refine-strings
4+
^EXIT=10$
5+
^SIGNAL=0$
6+
^VERIFICATION FAILED$
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
public class test
2+
{
3+
public static void main(String s)
4+
{
5+
String ab = "abc";
6+
assert(ab.contains(s));
7+
}
8+
}
606 Bytes
Binary file not shown.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
FUTURE
2+
test.class
3+
--refine-strings
4+
^EXIT=10$
5+
^SIGNAL=0$
6+
^VERIFICATION FAILED$
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
public class test
2+
{
3+
public static void main(String s)
4+
{
5+
assert(s.contains("Hello"));
6+
}
7+
}

src/solvers/refinement/string_constraint_generator_testing.cpp

+19-13
Original file line numberDiff line numberDiff line change
@@ -194,9 +194,10 @@ exprt string_constraint_generatort::add_axioms_for_contains(
194194

195195
// We add axioms:
196196
// a1 : contains ==> |s0| >= |s1|
197-
// a2 : 0 <= startpos <= |s0|-|s1|
198-
// a3 : forall qvar < |s1|. contains ==> s1[qvar] = s0[startpos + qvar]
199-
// a4 : !contains ==> |s1| > |s0| ||
197+
// a2 : contains ==> 0 <= startpos <= |s0|-|s1|
198+
// a3 : !contains ==> startpos = -1
199+
// a4 : forall qvar < |s1|. contains ==> s1[qvar] = s0[startpos + qvar]
200+
// a5 : !contains ==> |s1| > |s0| ||
200201
// (forall startpos <= |s0| - |s1|.
201202
// exists witness < |s1|. s1[witness] != s0[witness + startpos])
202203

@@ -211,9 +212,14 @@ exprt string_constraint_generatort::add_axioms_for_contains(
211212
implies_exprt a2(contains, bounds);
212213
axioms.push_back(a2);
213214

215+
implies_exprt a3(
216+
not_exprt(contains),
217+
equal_exprt(startpos, from_integer(-1, index_type)));
218+
axioms.push_back(a3);
219+
214220
if(constant)
215221
{
216-
// If the string is constant, we can use a more efficient axiom for a3:
222+
// If the string is constant, we can use a more efficient axiom for a4:
217223
// contains ==> AND_{i < |s1|} s1[i] = s0[startpos + i]
218224
mp_integer s1_length;
219225
assert(!to_integer(s1.length(), s1_length));
@@ -224,10 +230,10 @@ exprt string_constraint_generatort::add_axioms_for_contains(
224230
plus_exprt shifted_i(expr_i, startpos);
225231
conjuncts.push_back(equal_exprt(s1[expr_i], s0[shifted_i]));
226232
}
227-
implies_exprt a3(contains, conjunction(conjuncts));
228-
axioms.push_back(a3);
233+
implies_exprt a4(contains, conjunction(conjuncts));
234+
axioms.push_back(a4);
229235

230-
// The a4 constraint for constant strings translates to:
236+
// The a5 constraint for constant strings translates to:
231237
// !contains ==> |s1| > |s0| ||
232238
// (forall qvar <= |s0| - |s1|.
233239
// !(AND_{i < |s1|} s1[i] == s0[i + qvar])
@@ -244,30 +250,30 @@ exprt string_constraint_generatort::add_axioms_for_contains(
244250
conjuncts1.push_back(equal_exprt(s1[expr_i], s0[shifted_i]));
245251
}
246252

247-
string_constraintt a4(
253+
string_constraintt a5(
248254
qvar,
249255
plus_exprt(from_integer(1, index_type), length_diff),
250256
and_exprt(not_exprt(contains), s0.axiom_for_is_longer_than(s1)),
251257
not_exprt(conjunction(conjuncts1)));
252-
axioms.push_back(a4);
258+
axioms.push_back(a5);
253259
}
254260
else
255261
{
256262
symbol_exprt qvar=fresh_univ_index("QA_contains", index_type);
257263
exprt qvar_shifted=plus_exprt(qvar, startpos);
258-
string_constraintt a3(
264+
string_constraintt a4(
259265
qvar, s1.length(), contains, equal_exprt(s1[qvar], s0[qvar_shifted]));
260-
axioms.push_back(a3);
266+
axioms.push_back(a4);
261267

262268
// We rewrite axiom a4 as:
263269
// forall startpos <= |s0|-|s1|. (!contains && |s0| >= |s1|)
264270
// ==> exists witness < |s1|. s1[witness] != s0[startpos+witness]
265-
string_not_contains_constraintt a4(
271+
string_not_contains_constraintt a5(
266272
from_integer(0, index_type),
267273
plus_exprt(from_integer(1, index_type), length_diff),
268274
and_exprt(not_exprt(contains), s0.axiom_for_is_longer_than(s1)),
269275
from_integer(0, index_type), s1.length(), s0, s1);
270-
axioms.push_back(a4);
276+
axioms.push_back(a5);
271277
}
272278
return typecast_exprt(contains, f.type());
273279
}

0 commit comments

Comments
 (0)