CBMC
string_constraint_generator_comparison.cpp
Go to the documentation of this file.
1 /*******************************************************************\
2 
3 Module: Generates string constraints for function comparing strings,
4  such as: equals, equalsIgnoreCase, compareTo, hashCode, intern
5 
6 Author: Romain Brenguier, romain.brenguier@diffblue.com
7 
8 \*******************************************************************/
9 
13 
15 
16 #include <util/mathematical_expr.h>
17 
30 std::pair<exprt, string_constraintst>
33 {
34  PRECONDITION(f.type() == bool_typet() || f.type().id() == ID_c_bool);
35  PRECONDITION(f.arguments().size() == 2);
36 
37  string_constraintst constraints;
40  symbol_exprt eq = fresh_symbol("equal");
41  typecast_exprt tc_eq(eq, f.type());
42 
43  typet index_type = s1.length_type();
44 
45  // Axiom 1.
46  constraints.existential.push_back(implies_exprt(
47  eq,
51 
52  // Axiom 2.
53  constraints.universal.push_back([&] {
54  const symbol_exprt qvar = fresh_symbol("QA_equal", index_type);
55  return string_constraintt(
56  qvar,
58  implies_exprt(eq, equal_exprt(s1[qvar], s2[qvar])),
60  }());
61 
62  // Axiom 3.
63  constraints.existential.push_back([&] {
64  const symbol_exprt witness = fresh_symbol("witness_unequal", index_type);
65  const exprt zero = from_integer(0, index_type);
66  const and_exprt bound_witness(
68  witness, ID_lt, array_pool.get_or_create_length(s1)),
69  binary_relation_exprt(witness, ID_ge, zero));
70  const and_exprt witnessing(
71  bound_witness, notequal_exprt(s1[witness], s2[witness]));
72  const and_exprt diff_length(
76  equal_exprt(witness, from_integer(-1, index_type)));
77  return implies_exprt(not_exprt(eq), or_exprt(diff_length, witnessing));
78  }());
79 
80  return {tc_eq, std::move(constraints)};
81 }
82 
93  const exprt &char1,
94  const exprt &char2,
95  const exprt &char_a,
96  const exprt &char_A,
97  const exprt &char_Z)
98 {
99  const and_exprt is_upper_case_1(
100  binary_relation_exprt(char_A, ID_le, char1),
101  binary_relation_exprt(char1, ID_le, char_Z));
102  const and_exprt is_upper_case_2(
103  binary_relation_exprt(char_A, ID_le, char2),
104  binary_relation_exprt(char2, ID_le, char_Z));
105 
106  // Three possibilities:
107  // p1 : char1=char2
108  // p2 : (is_up1&&'a'-'A'+char1=char2)
109  // p3 : (is_up2&&'a'-'A'+char2=char1)
110  const equal_exprt p1(char1, char2);
111  const minus_exprt diff(char_a, char_A);
112 
113  // Overflow is not a problem here because is_upper_case conditions
114  // ensure that we are within a safe range.
115  const exprt p2 =
116  and_exprt(is_upper_case_1, equal_exprt(plus_exprt(diff, char1), char2));
117  const exprt p3 =
118  and_exprt(is_upper_case_2, equal_exprt(plus_exprt(diff, char2), char1));
119  return or_exprt(p1, p2, p3);
120 }
121 
135 std::pair<exprt, string_constraintst>
138 {
139  PRECONDITION(f.type() == bool_typet() || f.type().id() == ID_c_bool);
140  PRECONDITION(f.arguments().size() == 2);
141  string_constraintst constraints;
142  const symbol_exprt eq = fresh_symbol("equal_ignore_case");
145  const typet char_type = to_type_with_subtype(s1.content().type()).subtype();
146  const exprt char_a = from_integer('a', char_type);
147  const exprt char_A = from_integer('A', char_type);
148  const exprt char_Z = from_integer('Z', char_type);
149  const typet index_type = s1.length_type();
150 
151  const implies_exprt a1(
152  eq,
153  equal_exprt(
156  constraints.existential.push_back(a1);
157 
158  const symbol_exprt qvar = fresh_symbol("QA_equal_ignore_case", index_type);
159  const exprt constr2 =
160  character_equals_ignore_case(s1[qvar], s2[qvar], char_a, char_A, char_Z);
161  const string_constraintt a2(
162  qvar,
164  implies_exprt(eq, constr2),
166  constraints.universal.push_back(a2);
167 
168  const symbol_exprt witness =
169  fresh_symbol("witness_unequal_ignore_case", index_type);
170  const exprt zero = from_integer(0, witness.type());
171  const and_exprt bound_witness(
173  binary_relation_exprt(witness, ID_ge, zero));
174  const exprt witness_eq = character_equals_ignore_case(
175  s1[witness], s2[witness], char_a, char_A, char_Z);
176  const not_exprt witness_diff(witness_eq);
177  const implies_exprt a3(
178  not_exprt(eq),
179  or_exprt(
183  and_exprt(bound_witness, witness_diff)));
184  constraints.existential.push_back(a3);
185 
186  return {typecast_exprt(eq, f.type()), std::move(constraints)};
187 }
188 
208 std::pair<exprt, string_constraintst>
211 {
212  PRECONDITION(f.arguments().size() == 2);
213  const typet &return_type = f.type();
214  PRECONDITION(return_type.id() == ID_signedbv);
215  string_constraintst constraints;
218  const symbol_exprt res = fresh_symbol("compare_to", return_type);
219  const typet &index_type = s1.length_type();
220 
221  const equal_exprt res_null(res, from_integer(0, return_type));
222  const implies_exprt a1(
223  res_null,
224  equal_exprt(
227  constraints.existential.push_back(a1);
228 
229  const symbol_exprt i = fresh_symbol("QA_compare_to", index_type);
230  const string_constraintt a2(
231  i,
233  implies_exprt(res_null, equal_exprt(s1[i], s2[i])),
235  constraints.universal.push_back(a2);
236 
237  const symbol_exprt x = fresh_symbol("index_compare_to", index_type);
238  const equal_exprt ret_char_diff(
239  res,
240  minus_exprt(
241  typecast_exprt(s1[x], return_type), typecast_exprt(s2[x], return_type)));
242  const equal_exprt ret_length_diff(
243  res,
244  minus_exprt(
247  const or_exprt guard1(
248  and_exprt(
253  and_exprt(
258  const and_exprt cond1(ret_char_diff, guard1);
259  const or_exprt guard2(
260  and_exprt(
261  greater_than(
265  and_exprt(
266  greater_than(
270  const and_exprt cond2(ret_length_diff, guard2);
271 
272  const implies_exprt a3(
273  not_exprt(res_null),
274  and_exprt(
275  binary_relation_exprt(x, ID_ge, from_integer(0, return_type)),
276  or_exprt(cond1, cond2)));
277  constraints.existential.push_back(a3);
278 
279  const symbol_exprt i2 = fresh_symbol("QA_compare_to", index_type);
280  const string_constraintt a4(
281  i2,
282  zero_if_negative(x),
283  implies_exprt(not_exprt(res_null), equal_exprt(s1[i2], s2[i2])),
285  constraints.universal.push_back(a4);
286 
287  return {res, std::move(constraints)};
288 }
constant_exprt from_integer(const mp_integer &int_value, const typet &type)
array_string_exprt get_string_expr(array_poolt &array_pool, const exprt &expr)
Fetch the string_exprt corresponding to the given refined_string_exprt.
Definition: array_pool.cpp:199
int16_t s2
Definition: bytecode_info.h:60
int8_t s1
Definition: bytecode_info.h:59
bitvector_typet char_type()
Definition: c_types.cpp:106
Boolean AND.
Definition: std_expr.h:2120
exprt get_or_create_length(const array_string_exprt &s)
Get the length of an array_string_exprt from the array_pool.
Definition: array_pool.cpp:26
A base class for relations, i.e., binary predicates whose two operands have the same type.
Definition: std_expr.h:762
The Boolean type.
Definition: std_types.h:36
Equality.
Definition: std_expr.h:1361
Base class for all expressions.
Definition: expr.h:56
typet & type()
Return the type of the expression.
Definition: expr.h:84
Application of (mathematical) function.
Boolean implication.
Definition: std_expr.h:2183
const irep_idt & id() const
Definition: irep.h:384
Binary minus.
Definition: std_expr.h:1061
Boolean negation.
Definition: std_expr.h:2327
Disequality.
Definition: std_expr.h:1420
Boolean OR.
Definition: std_expr.h:2228
The plus expression Associativity is not specified.
Definition: std_expr.h:1002
std::pair< exprt, string_constraintst > add_axioms_for_compare_to(const function_application_exprt &f)
Lexicographic comparison of two strings.
std::pair< exprt, string_constraintst > add_axioms_for_equals_ignore_case(const function_application_exprt &f)
Equality of the content ignoring case of characters.
std::pair< exprt, string_constraintst > add_axioms_for_equals(const function_application_exprt &f)
Equality of the content of two strings.
Expression to hold a symbol (variable)
Definition: std_expr.h:131
const typet & subtype() const
Definition: type.h:187
Semantic type conversion.
Definition: std_expr.h:2068
The type of an expression, extends irept.
Definition: type.h:29
API to expression classes for 'mathematical' expressions.
#define PRECONDITION(CONDITION)
Definition: invariant.h:463
Generates string constraints to link results from string functions with their arguments.
exprt zero_if_negative(const exprt &expr)
Returns a non-negative version of the argument.
static exprt character_equals_ignore_case(const exprt &char1, const exprt &char2, const exprt &char_a, const exprt &char_A, const exprt &char_Z)
Returns an expression which is true when the two given characters are equal when ignoring case for AS...
binary_relation_exprt less_than_or_equal_to(exprt lhs, exprt rhs)
Definition: string_expr.h:37
binary_relation_exprt greater_or_equal_to(exprt lhs, exprt rhs)
Definition: string_expr.h:20
binary_relation_exprt greater_than(exprt lhs, exprt rhs)
Definition: string_expr.h:26
equal_exprt equal_to(exprt lhs, exprt rhs)
Definition: string_expr.h:55
Collection of constraints of different types: existential formulas, universal formulas,...
std::vector< exprt > existential
std::vector< string_constraintt > universal
const type_with_subtypet & to_type_with_subtype(const typet &type)
Definition: type.h:208