Skip to content

Commit bb5c885

Browse files
Merge pull request #4546 from romainbrenguier/feature/string-hash-code
Use model for String.hashCode
2 parents f6c4867 + 18d1a00 commit bb5c885

File tree

11 files changed

+38
-59
lines changed

11 files changed

+38
-59
lines changed
Binary file not shown.
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
public class Test {
2+
3+
public static int check(String s, int nondet) {
4+
if(s == null)
5+
return -1;
6+
7+
if(nondet == 0) {
8+
// This is always true
9+
assert "foo".hashCode() == 101574;
10+
} else if(nondet == 1) {
11+
// This is always false
12+
assert "foo".hashCode() != 101574;
13+
} else if(nondet == 2) {
14+
// This is sometimes false
15+
assert !s.startsWith("foo") && s.hashCode() == 101574;
16+
} else if(nondet == 3) {
17+
// This is always true
18+
assert s.hashCode() == 101574 || !(s.startsWith("foo") && s.length() == 3);
19+
} else {
20+
// This is always false
21+
assert "bar".hashCode() == 101574;
22+
}
23+
24+
return s.hashCode();
25+
}
26+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
CORE
2+
Test.class
3+
--max-nondet-string-length 1000 --function Test.check --cp `../../../../scripts/format_classpath.sh . ../../../lib/java-models-library/target/core-models.jar` --unwind 10
4+
^EXIT=10$
5+
^SIGNAL=0$
6+
assertion at file Test.java line 8 function .*: SUCCESS
7+
assertion at file Test.java line 11 function .*: FAILURE
8+
assertion at file Test.java line 14 function .*: FAILURE
9+
assertion at file Test.java line 17 function .*: SUCCESS
10+
assertion at file Test.java line 20 function .*: FAILURE

jbmc/regression/strings-smoke-tests/java_hash_code/test.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
CORE
22
test_hash_code.class
3-
--max-nondet-string-length 1000 --function test_hash_code.main
3+
--max-nondet-string-length 1000 --function test_hash_code.main --cp `../../../../scripts/format_classpath.sh . ../../../lib/java-models-library/target/core-models.jar`
44
^EXIT=10$
55
^SIGNAL=0$
66
^\[.*assertion.1\].* line 8.* SUCCESS$

jbmc/src/java_bytecode/java_string_library_preprocess.cpp

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1517,9 +1517,6 @@ void java_string_library_preprocesst::initialize_conversion_table()
15171517
cprover_equivalent_to_java_string_returning_function[format_signature] =
15181518
ID_cprover_string_format_func;
15191519

1520-
cprover_equivalent_to_java_function
1521-
["java::java.lang.String.hashCode:()I"]=
1522-
ID_cprover_string_hash_code_func;
15231520
cprover_equivalent_to_java_function
15241521
["java::java.lang.String.indexOf:(I)I"]=
15251522
ID_cprover_string_index_of_func;

src/solvers/README.md

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -430,9 +430,6 @@ allocates a new string before calling a primitive.
430430
* `cprover_string_equals_ignore_case` :
431431
\copybrief add_axioms_for_equals_ignore_case(symbol_generatort &fresh_symbol,const function_application_exprt &f, array_poolt &array_pool)
432432
\link add_axioms_for_equals_ignore_case(symbol_generatort &fresh_symbol,const function_application_exprt &f, array_poolt &array_pool) More... \endlink
433-
* `cprover_string_hash_code` :
434-
\copybrief string_constraint_generatort::add_axioms_for_hash_code
435-
\link string_constraint_generatort::add_axioms_for_hash_code More... \endlink
436433
* `cprover_string_is_prefix` :
437434
\copybrief add_axioms_for_is_prefix
438435
\link add_axioms_for_is_prefix More... \endlink

src/solvers/strings/string_constraint_generator.h

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -75,18 +75,8 @@ class string_constraint_generatort final
7575

7676
exprt associate_length_to_array(const function_application_exprt &f);
7777

78-
// Add axioms corresponding to the String.hashCode java function
79-
// The specification is partial: the actual value is not actually computed
80-
// but we ensure that hash codes of equal strings are equal.
81-
std::pair<exprt, string_constraintst>
82-
add_axioms_for_hash_code(const function_application_exprt &f);
83-
8478
// MEMBERS
8579
const messaget message;
86-
87-
// To each string on which hash_code was called we associate a symbol
88-
// representing the return value of the hash_code function.
89-
std::map<array_string_exprt, exprt> hash_code_of_string;
9080
};
9181

9282
// Type used by primitives to signal errors

src/solvers/strings/string_constraint_generator_comparison.cpp

Lines changed: 0 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -176,44 +176,6 @@ std::pair<exprt, string_constraintst> add_axioms_for_equals_ignore_case(
176176
return {typecast_exprt(eq, f.type()), std::move(constraints)};
177177
}
178178

179-
/// Value that is identical for strings with the same content
180-
///
181-
/// Add axioms stating that if two strings are equal then the values
182-
/// returned by this function are equal.
183-
/// These axioms are, for each string `s` on which hash was called:
184-
/// * \f$ hash(str)=hash(s) \lor |str| \ne |s|
185-
/// \lor (|str|=|s| \land \exists i<|s|.\ s[i]\ne str[i]) \f$
186-
/// \param f: function application with argument refined_string `str`
187-
/// \return integer expression `hash(str)`
188-
std::pair<exprt, string_constraintst>
189-
string_constraint_generatort::add_axioms_for_hash_code(
190-
const function_application_exprt &f)
191-
{
192-
PRECONDITION(f.arguments().size() == 1);
193-
string_constraintst hash_constraints;
194-
const array_string_exprt str = get_string_expr(array_pool, f.arguments()[0]);
195-
const typet &return_type = f.type();
196-
const typet &index_type = str.length_type();
197-
198-
auto pair = hash_code_of_string.insert(
199-
std::make_pair(str, fresh_symbol("hash", return_type)));
200-
const exprt hash = pair.first->second;
201-
202-
for(auto it : hash_code_of_string)
203-
{
204-
const symbol_exprt i = fresh_symbol("index_hash", index_type);
205-
const equal_exprt c1(it.second, hash);
206-
const notequal_exprt c2(it.first.length(), str.length());
207-
const and_exprt c3(
208-
equal_exprt(it.first.length(), str.length()),
209-
and_exprt(
210-
notequal_exprt(str[i], it.first[i]),
211-
and_exprt(greater_than(str.length(), i), is_positive(i))));
212-
hash_constraints.existential.push_back(or_exprt(c1, or_exprt(c2, c3)));
213-
}
214-
return {hash, std::move(hash_constraints)};
215-
}
216-
217179
/// Lexicographic comparison of two strings
218180
///
219181
/// Add axioms ensuring the result corresponds to that of the `String.compareTo`

src/solvers/strings/string_constraint_generator_main.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -240,8 +240,6 @@ string_constraint_generatort::add_axioms_for_function_application(
240240
return add_axioms_for_is_suffix(fresh_symbol, expr, true, array_pool);
241241
else if(id == ID_cprover_string_contains_func)
242242
return add_axioms_for_contains(fresh_symbol, expr, array_pool);
243-
else if(id == ID_cprover_string_hash_code_func)
244-
return add_axioms_for_hash_code(expr);
245243
else if(id == ID_cprover_string_index_of_func)
246244
return add_axioms_for_index_of(fresh_symbol, expr, array_pool);
247245
else if(id == ID_cprover_string_last_index_of_func)

src/util/irep_ids.def

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -609,7 +609,6 @@ IREP_ID_ONE(cprover_string_equals_ignore_case_func)
609609
IREP_ID_ONE(cprover_string_empty_string_func)
610610
IREP_ID_ONE(cprover_string_endswith_func)
611611
IREP_ID_ONE(cprover_string_format_func)
612-
IREP_ID_ONE(cprover_string_hash_code_func)
613612
IREP_ID_ONE(cprover_string_index_of_func)
614613
IREP_ID_ONE(cprover_string_insert_func)
615614
IREP_ID_ONE(cprover_string_insert_int_func)

0 commit comments

Comments
 (0)