Skip to content

Commit 6c90b35

Browse files
author
Daniel Kroening
authored
Merge pull request diffblue#2052 from romainbrenguier/bugfix/default-axioms2#TG-2138
[TG-2138] Stop adding default axioms in string solver
2 parents 53dfa0a + b59a453 commit 6c90b35

26 files changed

+232
-105
lines changed
0 Bytes
Binary file not shown.

regression/jbmc-strings/long_string/Test.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,9 @@ public static void checkAbort(String s, String t) {
3030
String u = s.concat(t);
3131

3232
// Filter out
33-
if(u.length() < 67_108_864)
33+
// 67_108_864 corresponds to the maximum length for which the solver
34+
// will concretize the string.
35+
if(u.length() <= 67_108_864)
3436
return;
3537
if(CProverString.charAt(u, 2_000_000) != 'b')
3638
return;
Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
CORE
22
Test.class
3-
--refine-strings --function Test.checkAbort
4-
^EXIT=6$
3+
--refine-strings --function Test.checkAbort --trace
4+
^EXIT=10$
55
^SIGNAL=0$
6+
dynamic_object[0-9]*=\(assignment removed\)
67
--
78
--
8-
This tests should abort, because concretizing a string of the required
9-
length may take to much memory.
9+
This tests that the object does not appear in the trace, because concretizing
10+
a string of the required length may take too much memory.
Binary file not shown.
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
public class IntegerTests {
2+
3+
public static Boolean testMyGenSet(Integer key) {
4+
if (key == null) return null;
5+
MyGenSet<Integer> ms = new MyGenSet<>();
6+
ms.array[0] = 101;
7+
if (ms.contains(key)) return true;
8+
return false;
9+
}
10+
11+
public static Boolean testMySet(Integer key) {
12+
if (key == null) return null;
13+
MySet ms = new MySet();
14+
ms.array[0] = 101;
15+
if (ms.contains(key)) return true;
16+
return false;
17+
}
18+
19+
}
20+
21+
class MyGenSet<E> {
22+
E[] array;
23+
@SuppressWarnings("unchecked")
24+
MyGenSet() {
25+
array = (E[]) new Object[1];
26+
}
27+
boolean contains(E o) {
28+
if (o.equals(array[0]))
29+
return true;
30+
return false;
31+
}
32+
}
33+
34+
class MySet {
35+
Integer[] array;
36+
MySet() {
37+
array = new Integer[1];
38+
}
39+
boolean contains(Integer o) {
40+
if (o.equals(array[0]))
41+
return true;
42+
return false;
43+
}
44+
}
Binary file not shown.
Binary file not shown.
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
CORE
2+
IntegerTests.class
3+
-refine-strings --string-max-length 100 IntegerTests.class --function IntegerTests.testMySet --cover location
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
coverage.* line 12 function java::IntegerTests.testMySet.* bytecode-index 1 .* SATISFIED
7+
coverage.* line 12 function java::IntegerTests.testMySet.* bytecode-index 3 .* SATISFIED
8+
coverage.* line 13 function java::IntegerTests.testMySet.* bytecode-index 4 .* SATISFIED
9+
coverage.* line 13 function java::IntegerTests.testMySet.* bytecode-index 6 .* SATISFIED
10+
coverage.* line 13 function java::IntegerTests.testMySet.* bytecode-index 7 .* SATISFIED
11+
coverage.* line 14 function java::IntegerTests.testMySet.* bytecode-index 12 .* SATISFIED
12+
coverage.* line 14 function java::IntegerTests.testMySet.* bytecode-index 13 .* SATISFIED
13+
coverage.* line 15 function java::IntegerTests.testMySet.* bytecode-index 16 .* SATISFIED
14+
coverage.* line 15 function java::IntegerTests.testMySet.* bytecode-index 17 .* SATISFIED
15+
coverage.* line 16 function java::IntegerTests.testMySet.* bytecode-index 21 .* SATISFIED
16+
coverage.* line 15 function java::IntegerTests.testMySet.* bytecode-index 19 .* SATISFIED
17+
coverage.* line 15 function java::IntegerTests.testMySet.* bytecode-index 20 .* SATISFIED
18+
coverage.* line 16 function java::IntegerTests.testMySet.* bytecode-index 22 .* SATISFIED
19+
coverage.* line 16 function java::IntegerTests.testMySet.* bytecode-index 23 .* SATISFIED
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
CORE
2+
IntegerTests.class
3+
-refine-strings --string-max-length 100 IntegerTests.class --function IntegerTests.testMyGenSet --cover location
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
coverage.* line 4 function java::IntegerTests.testMyGenSet.* bytecode-index 1 .* SATISFIED
7+
coverage.* line 4 function java::IntegerTests.testMyGenSet.* bytecode-index 3 .* SATISFIED
8+
coverage.* line 5 function java::IntegerTests.testMyGenSet.* bytecode-index 4 .* SATISFIED
9+
coverage.* line 5 function java::IntegerTests.testMyGenSet.* bytecode-index 6 .* SATISFIED
10+
coverage.* line 5 function java::IntegerTests.testMyGenSet.* bytecode-index 7 .* SATISFIED
11+
coverage.* line 6 function java::IntegerTests.testMyGenSet.* bytecode-index 10 .* SATISFIED
12+
coverage.* line 6 function java::IntegerTests.testMyGenSet.* bytecode-index 13 .* SATISFIED
13+
coverage.* line 6 function java::IntegerTests.testMyGenSet.* bytecode-index 14 .* SATISFIED
14+
coverage.* line 7 function java::IntegerTests.testMyGenSet.* bytecode-index 17 .* SATISFIED
15+
coverage.* line 7 function java::IntegerTests.testMyGenSet.* bytecode-index 18 .* SATISFIED
16+
coverage.* line 8 function java::IntegerTests.testMyGenSet.* bytecode-index 22 .* SATISFIED
17+
coverage.* line 7 function java::IntegerTests.testMyGenSet.* bytecode-index 20 .* SATISFIED
18+
coverage.* line 7 function java::IntegerTests.testMyGenSet.* bytecode-index 21 .* SATISFIED
19+
coverage.* line 8 function java::IntegerTests.testMyGenSet.* bytecode-index 23 .* SATISFIED
20+
coverage.* line 8 function java::IntegerTests.testMyGenSet.* bytecode-index 24 .* SATISFIED
1.04 KB
Binary file not shown.
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
public class Test {
2+
3+
static void checkMaxInputLength(String arg1, String arg2) {
4+
// Filter
5+
if (arg1 == null || arg2 == null)
6+
return;
7+
8+
// The validity of this depends on string-max-input-length
9+
assert arg1.length() + arg2.length() < 1_000_000;
10+
}
11+
12+
static void checkMaxLength(String arg1, String arg2) {
13+
// Filter
14+
if (arg1 == null || arg2 == null)
15+
return;
16+
17+
if(arg1.length() + arg2.length() < 4_001)
18+
return;
19+
20+
// Act
21+
String s = arg1.concat(arg2);
22+
23+
// When string-max-length is smaller than 4_000 this will
24+
// always be the case
25+
assert org.cprover.CProverString.charAt(s, 4_000) == '?';
26+
}
27+
28+
static void main(String argv[]) {
29+
// Filter
30+
if (argv.length < 2)
31+
return;
32+
33+
// Act
34+
checkMaxInputLength(argv[0], argv[1]);
35+
checkMaxLength(argv[0], argv[1]);
36+
}
37+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
CORE
2+
Test.class
3+
--refine-strings --verbosity 10 --string-max-input-length 499999 --function Test.checkMaxInputLength
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
assertion.* line 9 function java::Test.checkMaxInputLength.* bytecode-index 16: SUCCESS
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
CORE
2+
Test.class
3+
--refine-strings --verbosity 10 --string-max-input-length 500000 --function Test.checkMaxInputLength
4+
^EXIT=10$
5+
^SIGNAL=0$
6+
assertion.* line 9 function java::Test.checkMaxInputLength.* bytecode-index 16: FAILURE
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
CORE
2+
Test.class
3+
--refine-strings --verbosity 10 --string-max-length 4001 --function Test.checkMaxLength
4+
^EXIT=10$
5+
^SIGNAL=0$
6+
assertion.* line 25 function java::Test.checkMaxLength.* bytecode-index 26: FAILURE
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
CORE
2+
Test.class
3+
--refine-strings --verbosity 10 --string-max-length 4000 --function Test.checkMaxLength
4+
^SIGNAL=0$
5+
--
6+
^EXIT=0$
7+
assertion.* line 25 function java::Test.checkMaxLength.* bytecode-index 26: SUCCESS
8+
--
9+
The solver may give an ERROR because the value of string-max-length is too
10+
small to give an answer about the assertion.
11+
So we just check that the answer is not success.

src/cbmc/cbmc_parse_options.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -999,8 +999,9 @@ void cbmc_parse_optionst::help()
999999
" --refine use refinement procedure (experimental)\n"
10001000
" --refine-strings use string refinement (experimental)\n"
10011001
" --string-printable add constraint that strings are printable (experimental)\n" // NOLINT(*)
1002-
" --string-max-length add constraint on the length of strings\n" // NOLINT(*)
10031002
" --string-max-input-length add constraint on the length of input strings\n" // NOLINT(*)
1003+
" --string-max-length add constraint on the length of strings"
1004+
" (deprecated: use string-max-input-length instead)\n" // NOLINT(*)
10041005
" --outfile filename output formula to given file\n"
10051006
" --arrays-uf-never never turn arrays into uninterpreted functions\n" // NOLINT(*)
10061007
" --arrays-uf-always always turn arrays into uninterpreted functions\n" // NOLINT(*)

src/cbmc/cbmc_solvers.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ std::unique_ptr<cbmc_solverst::solvert> cbmc_solverst::get_string_refinement()
177177
info.refinement_bound=DEFAULT_MAX_NB_REFINEMENT;
178178
info.ui=ui;
179179
if(options.get_bool_option("string-max-length"))
180-
info.string_max_length=options.get_signed_int_option("string-max-length");
180+
info.max_string_length = options.get_signed_int_option("string-max-length");
181181
info.trace=options.get_bool_option("trace");
182182
if(options.get_bool_option("max-node-refinement"))
183183
info.max_node_refinement=

src/java_bytecode/java_bytecode_language.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,10 @@ void java_bytecode_languaget::get_language_options(const cmdlinet &cmd)
5555
if(cmd.isset("string-max-input-length"))
5656
object_factory_parameters.max_nondet_string_length=
5757
std::stoi(cmd.get_value("string-max-input-length"));
58+
else if(cmd.isset("string-max-length"))
59+
object_factory_parameters.max_nondet_string_length =
60+
std::stoi(cmd.get_value("string-max-length"));
61+
5862
object_factory_parameters.string_printable = cmd.isset("string-printable");
5963
if(cmd.isset("java-max-vla-length"))
6064
max_user_array_length=std::stoi(cmd.get_value("java-max-vla-length"));

src/java_bytecode/java_string_library_preprocess.cpp

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -878,7 +878,7 @@ codet java_string_library_preprocesst::code_assign_string_expr_to_java_string(
878878
/// \param symbol_table: symbol table
879879
/// \param [out] code: code block that gets appended the following code:
880880
/// ~~~~~~~~~~~~~~~~~~~~~~
881-
/// lhs.length=rhs->length
881+
/// lhs.length = rhs==null ? 0 : rhs->length
882882
/// lhs.data=rhs->data
883883
/// ~~~~~~~~~~~~~~~~~~~~~~
884884
void java_string_library_preprocesst::code_assign_java_string_to_string_expr(
@@ -899,8 +899,13 @@ void java_string_library_preprocesst::code_assign_java_string_to_string_expr(
899899

900900
const dereference_exprt deref = checked_dereference(rhs, deref_type);
901901

902-
// Fields of the string object
903-
const exprt rhs_length = get_length(deref, symbol_table);
902+
// Although we should not reach this code if rhs is null, the association
903+
// `pointer -> length` is added to the solver anyway, so we have to make sure
904+
// the length is set to something reasonable.
905+
const auto rhs_length = if_exprt(
906+
equal_exprt(rhs, null_pointer_exprt(to_pointer_type(rhs.type()))),
907+
from_integer(0, lhs.length().type()),
908+
get_length(deref, symbol_table));
904909

905910
// Assignments
906911
code.add(code_assignt(lhs.length(), rhs_length), loc);

src/solvers/refinement/string_constraint_generator.h

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -94,14 +94,7 @@ class string_constraint_generatort final
9494
// Used by format function
9595
class format_specifiert;
9696

97-
/// Arguments pack for the string_constraint_generator constructor
98-
struct infot
99-
{
100-
/// Max length of non-deterministic strings
101-
size_t string_max_length=std::numeric_limits<size_t>::max();
102-
};
103-
104-
string_constraint_generatort(const infot& info, const namespacet& ns);
97+
explicit string_constraint_generatort(const namespacet &ns);
10598

10699
/// Axioms are of three kinds: universally quantified string constraint,
107100
/// not contains string constraints and simple formulas.
@@ -181,10 +174,9 @@ class string_constraint_generatort final
181174

182175
static constant_exprt constant_char(int i, const typet &char_type);
183176

184-
array_string_exprt
177+
const array_string_exprt &
185178
char_array_of_pointer(const exprt &pointer, const exprt &length);
186179

187-
void add_default_axioms(const array_string_exprt &s);
188180
exprt axiom_for_is_positive_index(const exprt &x);
189181

190182
void add_constraint_on_characters(
@@ -402,7 +394,6 @@ class string_constraint_generatort final
402394

403395
// MEMBERS
404396
public:
405-
const size_t max_string_length;
406397
// Used to store information about witnesses for not_contains constraints
407398
std::map<string_not_contains_constraintt, symbol_exprt> witness;
408399
private:

src/solvers/refinement/string_constraint_generator_main.cpp

Lines changed: 7 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,8 @@ Author: Romain Brenguier, [email protected]
2828
#include <util/string_constant.h>
2929
#include <util/deprecate.h>
3030

31-
string_constraint_generatort::string_constraint_generatort(
32-
const string_constraint_generatort::infot &info,
33-
const namespacet &ns)
34-
: array_pool(fresh_symbol), max_string_length(info.string_max_length), ns(ns)
31+
string_constraint_generatort::string_constraint_generatort(const namespacet &ns)
32+
: array_pool(fresh_symbol), ns(ns)
3533
{
3634
}
3735

@@ -172,7 +170,6 @@ array_string_exprt string_constraint_generatort::fresh_string(
172170
symbol_exprt content = fresh_symbol("string_content", array_type);
173171
array_string_exprt str = to_array_string_expr(content);
174172
created_strings.insert(str);
175-
add_default_axioms(str);
176173
return str;
177174
}
178175

@@ -279,7 +276,7 @@ exprt string_constraint_generatort::associate_array_to_pointer(
279276

280277
const exprt &pointer_expr = f.arguments()[1];
281278
array_pool.insert(pointer_expr, array_expr);
282-
add_default_axioms(to_array_string_expr(array_expr));
279+
created_strings.emplace(to_array_string_expr(array_expr));
283280
return from_integer(0, f.type());
284281
}
285282

@@ -319,27 +316,6 @@ void string_constraint_generatort::clear_constraints()
319316
not_contains_constraints.clear();
320317
}
321318

322-
/// adds standard axioms about the length of the string and its content: * its
323-
/// length should be positive * it should not exceed max_string_length * if
324-
/// force_printable_characters is true then all characters should belong to the
325-
/// range of ASCII characters between ' ' and '~'
326-
/// \param s: a string expression
327-
/// \return a string expression that is linked to the argument through axioms
328-
/// that are added to the list
329-
void string_constraint_generatort::add_default_axioms(
330-
const array_string_exprt &s)
331-
{
332-
// If `s` was already added we do nothing.
333-
if(!created_strings.insert(s).second)
334-
return;
335-
336-
const exprt index_zero = from_integer(0, s.length().type());
337-
lemmas.push_back(s.axiom_for_length_ge(index_zero));
338-
339-
if(max_string_length!=std::numeric_limits<size_t>::max())
340-
lemmas.push_back(s.axiom_for_length_le(max_string_length));
341-
}
342-
343319
/// Add constraint on characters of a string.
344320
///
345321
/// This constraint is
@@ -409,14 +385,13 @@ array_string_exprt array_poolt::find(const exprt &pointer, const exprt &length)
409385
}
410386

411387
/// Adds creates a new array if it does not already exists
412-
/// \todo This should be replaced by associate_char_array_to_char_pointer
413-
array_string_exprt string_constraint_generatort::char_array_of_pointer(
388+
/// \todo This should be replaced
389+
/// by array_poolt.make_char_array_for_char_pointer
390+
const array_string_exprt &string_constraint_generatort::char_array_of_pointer(
414391
const exprt &pointer,
415392
const exprt &length)
416393
{
417-
const array_string_exprt array = array_pool.find(pointer, length);
418-
add_default_axioms(array);
419-
return array;
394+
return *created_strings.insert(array_pool.find(pointer, length)).first;
420395
}
421396

422397
array_string_exprt array_poolt::find(const refined_string_exprt &str)

0 commit comments

Comments
 (0)