CBMC
string_constraint_generator_testing.cpp
Go to the documentation of this file.
1 /*******************************************************************\
2 
3 Module: Generates string constraints for string functions that return
4  Boolean values
5 
6 Author: Romain Brenguier, romain.brenguier@diffblue.com
7 
8 \*******************************************************************/
9 
12 
14 
15 #include <util/deprecate.h>
16 #include <util/mathematical_expr.h>
17 
37 std::pair<exprt, string_constraintst>
39  const array_string_exprt &prefix,
40  const array_string_exprt &str,
41  const exprt &offset)
42 {
43  string_constraintst constraints;
44  const symbol_exprt isprefix = fresh_symbol("isprefix");
45  const typet &index_type = str.length_type();
46  const exprt offset_within_bounds = and_exprt(
47  binary_relation_exprt(offset, ID_ge, from_integer(0, offset.type())),
51  ID_ge,
53 
54  // Axiom 1.
55  constraints.existential.push_back(
56  implies_exprt(isprefix, offset_within_bounds));
57 
58  // Axiom 2.
59  constraints.universal.push_back([&] {
60  const symbol_exprt qvar = fresh_symbol("QA_isprefix", index_type);
61  const exprt body = implies_exprt(
62  isprefix, equal_exprt(str[plus_exprt(qvar, offset)], prefix[qvar]));
63  return string_constraintt(
64  qvar,
65  maximum(
66  from_integer(0, index_type), array_pool.get_or_create_length(prefix)),
67  body,
69  }());
70 
71  // Axiom 3.
72  constraints.existential.push_back([&] {
73  const exprt witness = fresh_symbol("witness_not_isprefix", index_type);
74  const exprt strings_differ_at_witness = and_exprt(
75  is_positive(witness),
77  notequal_exprt(str[plus_exprt(witness, offset)], prefix[witness]));
78  const exprt s1_does_not_start_with_s0 = or_exprt(
79  not_exprt(offset_within_bounds),
82  plus_exprt(array_pool.get_or_create_length(prefix), offset))),
83  strings_differ_at_witness);
84  return implies_exprt(not_exprt(isprefix), s1_does_not_start_with_s0);
85  }());
86 
87  return {isprefix, std::move(constraints)};
88 }
89 
95 // NOLINTNEXTLINE
105 std::pair<exprt, string_constraintst>
108  bool swap_arguments)
109 {
111  PRECONDITION(f.type() == bool_typet() || f.type().id() == ID_c_bool);
112  PRECONDITION(args.size() == 2 || args.size() == 3);
113  const array_string_exprt &s0 =
114  get_string_expr(array_pool, args[swap_arguments ? 1u : 0u]);
115  const array_string_exprt &s1 =
116  get_string_expr(array_pool, args[swap_arguments ? 0u : 1u]);
117  const exprt offset =
118  args.size() == 2 ? from_integer(0, s0.length_type()) : args[2];
119  auto pair = add_axioms_for_is_prefix(s0, s1, offset);
120  return {typecast_exprt(pair.first, f.type()), std::move(pair.second)};
121 }
122 
128 DEPRECATED(SINCE(2017, 10, 5, "should use `string_length s == 0` instead"))
129 std::pair<exprt, string_constraintst>
130 string_constraint_generatort::add_axioms_for_is_empty(
132 {
133  PRECONDITION(f.type() == bool_typet() || f.type().id() == ID_c_bool);
134  PRECONDITION(f.arguments().size() == 1);
135  // We add axioms:
136  // a1 : is_empty => |s0| = 0
137  // a2 : s0 => is_empty
138 
139  symbol_exprt is_empty = fresh_symbol("is_empty");
140  array_string_exprt s0 = get_string_expr(array_pool, f.arguments()[0]);
141  string_constraintst constraints;
142  constraints.existential = {
143  implies_exprt(is_empty, equal_to(array_pool.get_or_create_length(s0), 0)),
144  implies_exprt(equal_to(array_pool.get_or_create_length(s0), 0), is_empty)};
145  return {typecast_exprt(is_empty, f.type()), std::move(constraints)};
146 }
147 
169 DEPRECATED(SINCE(2018, 6, 6, "should use strings_startwith"))
170 std::pair<exprt, string_constraintst>
171 string_constraint_generatort::add_axioms_for_is_suffix(
173  bool swap_arguments)
174 {
175  const function_application_exprt::argumentst &args = f.arguments();
176  PRECONDITION(args.size() == 2); // bad args to string issuffix?
177  PRECONDITION(f.type() == bool_typet() || f.type().id() == ID_c_bool);
178 
179  string_constraintst constraints;
180  symbol_exprt issuffix = fresh_symbol("issuffix");
181  typecast_exprt tc_issuffix(issuffix, f.type());
182  const array_string_exprt &s0 =
183  get_string_expr(array_pool, args[swap_arguments ? 1u : 0u]);
184  const array_string_exprt &s1 =
185  get_string_expr(array_pool, args[swap_arguments ? 0u : 1u]);
186  const typet &index_type = s0.length_type();
187 
188  implies_exprt a1(
189  issuffix,
191  array_pool.get_or_create_length(s1),
192  array_pool.get_or_create_length(s0)));
193  constraints.existential.push_back(a1);
194 
195  symbol_exprt qvar = fresh_symbol("QA_suffix", index_type);
196  const plus_exprt qvar_shifted(
197  qvar,
198  minus_exprt(
199  array_pool.get_or_create_length(s1),
200  array_pool.get_or_create_length(s0)));
202  qvar,
203  zero_if_negative(array_pool.get_or_create_length(s0)),
204  implies_exprt(issuffix, equal_exprt(s0[qvar], s1[qvar_shifted])),
205  message_handler);
206  constraints.universal.push_back(a2);
207 
208  symbol_exprt witness = fresh_symbol("witness_not_suffix", index_type);
209  const plus_exprt shifted(
210  witness,
211  minus_exprt(
212  array_pool.get_or_create_length(s1),
213  array_pool.get_or_create_length(s0)));
214  or_exprt constr3(
215  and_exprt(
216  greater_than(
217  array_pool.get_or_create_length(s0),
218  array_pool.get_or_create_length(s1)),
219  equal_exprt(witness, from_integer(-1, index_type))),
220  and_exprt(
221  notequal_exprt(s0[witness], s1[shifted]),
222  and_exprt(
223  greater_than(array_pool.get_or_create_length(s0), witness),
224  is_positive(witness))));
225  implies_exprt a3(not_exprt(issuffix), constr3);
226 
227  constraints.existential.push_back(a3);
228  return {tc_issuffix, std::move(constraints)};
229 }
230 
249 std::pair<exprt, string_constraintst>
252 {
253  PRECONDITION(f.arguments().size() == 2);
254  PRECONDITION(f.type() == bool_typet() || f.type().id() == ID_c_bool);
255  string_constraintst constraints;
258  const typet &index_type = s0.length_type();
259  const symbol_exprt contains = fresh_symbol("contains");
260  const symbol_exprt startpos = fresh_symbol("startpos_contains", index_type);
261 
262  const implies_exprt a1(
263  contains,
267  constraints.existential.push_back(a1);
268 
269  minus_exprt length_diff(
271  and_exprt bounds(
272  is_positive(startpos), binary_relation_exprt(startpos, ID_le, length_diff));
273  implies_exprt a2(contains, bounds);
274  constraints.existential.push_back(a2);
275 
276  implies_exprt a3(
277  not_exprt(contains), equal_exprt(startpos, from_integer(-1, index_type)));
278  constraints.existential.push_back(a3);
279 
280  symbol_exprt qvar = fresh_symbol("QA_contains", index_type);
281  const plus_exprt qvar_shifted(qvar, startpos);
283  qvar,
285  implies_exprt(contains, equal_exprt(s1[qvar], s0[qvar_shifted])),
287  constraints.universal.push_back(a4);
288 
290  from_integer(0, index_type),
291  plus_exprt(from_integer(1, index_type), length_diff),
292  and_exprt(
297  from_integer(0, index_type),
299  s0,
300  s1};
301  constraints.not_contains.push_back(a5);
302 
303  return {typecast_exprt(contains, f.type()), std::move(constraints)};
304 }
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
int8_t s1
Definition: bytecode_info.h:59
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
const typet & length_type() const
Definition: string_expr.h:70
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:388
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_is_prefix(const array_string_exprt &prefix, const array_string_exprt &str, const exprt &offset)
Add axioms stating that the returned expression is true exactly when the offset is greater or equal t...
std::pair< exprt, string_constraintst > add_axioms_for_contains(const function_application_exprt &f)
Test whether a string contains another.
Expression to hold a symbol (variable)
Definition: std_expr.h:131
Semantic type conversion.
Definition: std_expr.h:2068
The type of an expression, extends irept.
Definition: type.h:29
#define SINCE(year, month, day, msg)
Definition: deprecate.h:26
#define DEPRECATED(msg)
Definition: deprecate.h:23
bool is_empty(const std::string &s)
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 is_positive(const exprt &x)
exprt maximum(const exprt &a, const exprt &b)
exprt zero_if_negative(const exprt &expr)
Returns a non-negative version of the argument.
static bool contains(const exprt &index, const symbol_exprt &qvar)
Look for symbol qvar in the expression index and return true if found.
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< string_not_contains_constraintt > not_contains
std::vector< exprt > existential
std::vector< string_constraintt > universal
Constraints to encode non containement of strings.