CBMC
array_pool.cpp
Go to the documentation of this file.
1 /*******************************************************************\
2 
3 Module: String solver
4 
5 Author: Romain Brenguier, romain.brenguier@diffblue.com
6 
7 \*******************************************************************/
8 
9 #include "array_pool.h"
10 
11 #include <util/pointer_expr.h>
12 
14 operator()(const irep_idt &prefix, const typet &type)
15 {
16  std::ostringstream buf;
17  buf << "string_refinement#" << prefix << "#" << ++symbol_count;
18  irep_idt name(buf.str());
19  symbol_exprt result(name, type);
20 #ifdef DEBUG
21  created_symbols.push_back(result);
22 #endif
23  return result;
24 }
25 
27 {
28  if(const auto &if_expr = expr_try_dynamic_cast<if_exprt>((exprt)s))
29  {
30  return if_exprt{
31  if_expr->cond(),
32  get_or_create_length(to_array_string_expr(if_expr->true_case())),
33  get_or_create_length(to_array_string_expr(if_expr->false_case()))};
34  }
35 
36  auto emplace_result =
37  length_of_array.emplace(s, symbol_exprt(s.length_type()));
38  if(emplace_result.second)
39  {
40  emplace_result.first->second =
41  fresh_symbol("string_length", s.length_type());
42  }
43 
44  return emplace_result.first->second;
45 }
46 
47 std::optional<exprt>
49 {
50  auto find_result = length_of_array.find(s);
51  if(find_result != length_of_array.end())
52  return find_result->second;
53  return {};
54 }
55 
57 array_poolt::fresh_string(const typet &index_type, const typet &char_type)
58 {
59  array_typet array_type{char_type, infinity_exprt(index_type)};
60  symbol_exprt content = fresh_symbol("string_content", array_type);
62  arrays_of_pointers.emplace(
63  address_of_exprt(index_exprt(str, from_integer(0, index_type))), str);
64 
65  // add length to length_of_array map
67 
68  return str;
69 }
70 
75  const exprt &char_pointer,
76  const typet &char_array_type)
77 {
78  PRECONDITION(char_pointer.type().id() == ID_pointer);
79  PRECONDITION(char_array_type.id() == ID_array);
81  to_array_type(char_array_type).element_type().id() == ID_unsignedbv ||
82  to_array_type(char_array_type).element_type().id() == ID_signedbv);
83 
84  if(char_pointer.id() == ID_if)
85  {
86  const if_exprt &if_expr = to_if_expr(char_pointer);
87  const array_string_exprt t =
88  make_char_array_for_char_pointer(if_expr.true_case(), char_array_type);
89  const array_string_exprt f =
90  make_char_array_for_char_pointer(if_expr.false_case(), char_array_type);
91  const array_typet array_type(
92  to_array_type(char_array_type).element_type(),
93  if_exprt(
94  if_expr.cond(),
95  to_array_type(t.type()).size(),
96  to_array_type(f.type()).size()));
97  // BEWARE: this expression is possibly type-inconsistent and must not be
98  // used for any purposes other than passing it to concretization.
99  // Array if-exprts must be replaced (using substitute_array_access) before
100  // passing the lemmas to the solver.
101  return to_array_string_expr(if_exprt(if_expr.cond(), t, f, array_type));
102  }
103 
104  const bool is_constant_array =
105  char_pointer.id() == ID_address_of &&
106  to_address_of_expr(char_pointer).object().id() == ID_index &&
107  to_index_expr(to_address_of_expr(char_pointer).object()).array().id() ==
108  ID_array;
109 
110  if(is_constant_array)
111  {
112  return to_array_string_expr(
113  to_index_expr(to_address_of_expr(char_pointer).object()).array());
114  }
115  const std::string symbol_name = "char_array_" + id2string(char_pointer.id());
116  const auto array_sym =
117  to_array_string_expr(fresh_symbol(symbol_name, char_array_type));
118  const auto insert_result =
119  arrays_of_pointers.insert({char_pointer, array_sym});
120 
121  // add length to length_of_array map
122  get_or_create_length(array_sym);
123 
124  return to_array_string_expr(insert_result.first->second);
125 }
126 
136  const array_string_exprt &array_expr,
137  std::unordered_map<array_string_exprt, exprt, irep_hash> &length_of_array,
138  symbol_generatort &symbol_generator)
139 {
141  array_expr.id() != ID_if,
142  "attempt_assign_length_from_type does not handle if exprts");
143  // This invariant seems always true, but I don't know why.
144  // If we find a case where this is violated, try calling
145  // attempt_assign_length_from_type on the true and false cases.
146  const exprt &size_from_type = to_array_type(array_expr.type()).size();
147  const exprt &size_to_assign =
148  size_from_type != infinity_exprt(size_from_type.type())
149  ? size_from_type
150  : symbol_generator("string_length", array_expr.length_type());
151 
152  const auto emplace_result =
153  length_of_array.emplace(array_expr, size_to_assign);
154  INVARIANT(
155  emplace_result.second,
156  "attempt_assign_length_from_type should only be called when no entry"
157  "for the array_string_exprt exists in the length_of_array map");
158 }
159 
161  const exprt &pointer_expr,
162  const array_string_exprt &array_expr)
163 {
164  const auto it_bool =
165  arrays_of_pointers.insert(std::make_pair(pointer_expr, array_expr));
166 
167  INVARIANT(
168  it_bool.second, "should not associate two arrays to the same pointer");
169 
170  if(length_of_array.find(array_expr) == length_of_array.end())
171  {
173  }
174 }
175 
178 const std::unordered_map<array_string_exprt, exprt, irep_hash> &
180 {
181  return length_of_array;
182 }
183 
184 array_string_exprt array_poolt::find(const exprt &pointer, const exprt &length)
185 {
186  const array_typet array_type(
187  to_pointer_type(pointer.type()).base_type(), length);
188  const array_string_exprt array =
189  make_char_array_for_char_pointer(pointer, array_type);
190  return array;
191 }
192 
194 {
195  const auto string_argument = expr_checked_cast<struct_exprt>(arg);
196  return array_pool.find(string_argument.op1(), string_argument.op0());
197 }
198 
200 {
202  const refined_string_exprt &str = to_string_expr(expr);
203  return array_pool.find(str.content(), str.length());
204 }
constant_exprt from_integer(const mp_integer &int_value, const typet &type)
static void attempt_assign_length_from_type(const array_string_exprt &array_expr, std::unordered_map< array_string_exprt, exprt, irep_hash > &length_of_array, symbol_generatort &symbol_generator)
Given an array_string_exprt, get the size of the underlying array.
Definition: array_pool.cpp:135
array_string_exprt of_argument(array_poolt &array_pool, const exprt &arg)
Converts a struct containing a length and pointer to an array.
Definition: array_pool.cpp:193
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
Associates arrays and length to pointers, so that the string refinement can transform builtin functio...
bitvector_typet char_type()
Definition: c_types.cpp:106
Operator to return the address of an object.
Definition: pointer_expr.h:540
exprt & object()
Definition: pointer_expr.h:549
Correspondance between arrays and pointers string representations.
Definition: array_pool.h:42
std::unordered_map< exprt, array_string_exprt, irep_hash > arrays_of_pointers
Associate arrays to char pointers Invariant: Each array_string_exprt in this map has a corresponding ...
Definition: array_pool.h:95
std::optional< exprt > get_length_if_exists(const array_string_exprt &s) const
As opposed to get_length(), do not create a new symbol if the length of the array_string_exprt does n...
Definition: array_pool.cpp:48
std::unordered_map< array_string_exprt, exprt, irep_hash > length_of_array
Associate length to arrays of infinite size.
Definition: array_pool.h:98
array_string_exprt make_char_array_for_char_pointer(const exprt &char_pointer, const typet &char_array_type)
Helper function for find.
Definition: array_pool.cpp:74
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
void insert(const exprt &pointer_expr, const array_string_exprt &array)
Definition: array_pool.cpp:160
array_string_exprt fresh_string(const typet &index_type, const typet &char_type)
Construct a string expression whose length and content are new variables.
Definition: array_pool.cpp:57
array_string_exprt find(const exprt &pointer, const exprt &length)
Creates a new array if the pointer is not pointing to an array.
Definition: array_pool.cpp:184
symbol_generatort & fresh_symbol
Generate fresh symbols.
Definition: array_pool.h:101
const std::unordered_map< array_string_exprt, exprt, irep_hash > & created_strings() const
Return a map mapping all array_string_exprt of the array_pool to their length.
Definition: array_pool.cpp:179
const typet & length_type() const
Definition: string_expr.h:70
Arrays with given size.
Definition: std_types.h:807
const exprt & size() const
Definition: std_types.h:840
dstringt has one field, an unsigned integer no which is an index into a static table of strings.
Definition: dstring.h:38
Base class for all expressions.
Definition: expr.h:56
typet & type()
Return the type of the expression.
Definition: expr.h:84
The trinary if-then-else operator.
Definition: std_expr.h:2370
exprt & true_case()
Definition: std_expr.h:2397
exprt & false_case()
Definition: std_expr.h:2407
exprt & cond()
Definition: std_expr.h:2387
Array index operator.
Definition: std_expr.h:1465
exprt & array()
Definition: std_expr.h:1495
An expression denoting infinity.
Definition: std_expr.h:3089
const irep_idt & id() const
Definition: irep.h:384
const typet & base_type() const
The type of the data what we point to.
Definition: pointer_expr.h:35
const exprt & length() const
Definition: string_expr.h:129
const exprt & content() const
Definition: string_expr.h:139
Expression to hold a symbol (variable)
Definition: std_expr.h:131
Generation of fresh symbols of a given type.
Definition: array_pool.h:22
symbol_exprt operator()(const irep_idt &prefix, const typet &type=bool_typet())
Generate a new symbol expression of the given type with some prefix.
Definition: array_pool.cpp:14
unsigned symbol_count
Definition: array_pool.h:31
The type of an expression, extends irept.
Definition: type.h:29
const std::string & id2string(const irep_idt &d)
Definition: irep.h:40
API to expression classes for Pointers.
const pointer_typet & to_pointer_type(const typet &type)
Cast a typet to a pointer_typet.
Definition: pointer_expr.h:93
const address_of_exprt & to_address_of_expr(const exprt &expr)
Cast an exprt to an address_of_exprt.
Definition: pointer_expr.h:577
bool is_refined_string_type(const typet &type)
#define DATA_INVARIANT(CONDITION, REASON)
This condition should be used to document that assumptions that are made on goto_functions,...
Definition: invariant.h:534
#define PRECONDITION(CONDITION)
Definition: invariant.h:463
#define INVARIANT(CONDITION, REASON)
This macro uses the wrapper function 'invariant_violated_string'.
Definition: invariant.h:423
const if_exprt & to_if_expr(const exprt &expr)
Cast an exprt to an if_exprt.
Definition: std_expr.h:2450
const index_exprt & to_index_expr(const exprt &expr)
Cast an exprt to an index_exprt.
Definition: std_expr.h:1533
const array_typet & to_array_type(const typet &type)
Cast a typet to an array_typet.
Definition: std_types.h:888
array_string_exprt & to_array_string_expr(exprt &expr)
Definition: string_expr.h:96
refined_string_exprt & to_string_expr(exprt &expr)
Definition: string_expr.h:151