CBMC
recursive_initialization.cpp
Go to the documentation of this file.
1 /******************************************************************\
2 
3 Module: recursive_initialization
4 
5 Author: Diffblue Ltd.
6 
7 \******************************************************************/
8 
10 
12 
13 #include <util/arith_tools.h>
14 #include <util/c_types.h>
15 #include <util/fresh_symbol.h>
16 #include <util/irep.h>
17 #include <util/optional_utils.h>
18 #include <util/pointer_expr.h>
20 #include <util/rename.h>
21 #include <util/std_code.h>
22 #include <util/string2int.h>
23 #include <util/string_utils.h>
24 
25 #include <iterator>
26 
28 #include "goto_harness_generator.h"
29 
31  const std::string &option,
32  const std::list<std::string> &values)
33 {
35  {
36  auto const value =
38  auto const user_min_null_tree_depth =
39  string2optional<std::size_t>(value, 10);
40  if(user_min_null_tree_depth.has_value())
41  {
42  min_null_tree_depth = user_min_null_tree_depth.value();
43  }
44  else
45  {
47  "failed to convert '" + value + "' to integer",
49  }
50  return true;
51  }
53  {
54  auto const value =
56  auto const user_max_nondet_tree_depth =
57  string2optional<std::size_t>(value, 10);
58  if(user_max_nondet_tree_depth.has_value())
59  {
60  max_nondet_tree_depth = user_max_nondet_tree_depth.value();
61  }
62  else
63  {
65  "failed to convert '" + value + "' to integer",
67  }
68  return true;
69  }
71  {
74  return true;
75  }
77  {
80  return true;
81  }
83  {
85  values.begin(),
86  values.end(),
87  std::inserter(
90  [](const std::string &opt) -> irep_idt { return irep_idt{opt}; });
91  return true;
92  }
94  {
95  const auto list_of_members_string =
98  const auto list_of_members = split_string(list_of_members_string, ',');
99  for(const auto &member : list_of_members)
100  {
101  const auto selection_spec_strings = split_string(member, '.');
102 
103  selection_specs.push_back({});
104  auto &selection_spec = selection_specs.back();
106  selection_spec_strings.begin(),
107  selection_spec_strings.end(),
108  std::back_inserter(selection_spec),
109  [](const std::string &member_name_string) {
110  return irep_idt{member_name_string};
111  });
112  }
113  return true;
114  }
115  return false;
116 }
117 
119  recursive_initialization_configt initialization_config,
120  goto_modelt &goto_model)
121  : initialization_config(std::move(initialization_config)),
122  goto_model(goto_model),
123  max_depth_var_name(get_fresh_global_name(
124  "max_depth",
125  from_integer(
126  initialization_config.max_nondet_tree_depth,
127  signed_int_type()))),
128  min_depth_var_name(get_fresh_global_name(
129  "min_depth",
130  from_integer(
131  initialization_config.min_null_tree_depth,
132  signed_int_type())))
133 {
135  this->initialization_config.pointers_to_treat_equal.size());
136 }
137 
139  const exprt &lhs,
140  const exprt &depth,
141  code_blockt &body)
142 {
143  if(lhs.id() == ID_symbol && !initialization_config.selection_specs.empty())
144  {
145  auto lhs_id = to_symbol_expr(lhs).get_identifier();
146  for(const auto &selection_spec : initialization_config.selection_specs)
147  {
148  if(selection_spec.front() == lhs_id)
149  {
150  initialize_selected_member(lhs, depth, body, selection_spec);
151  return;
152  }
153  }
154  }
155  // special handling for the case that pointer arguments should be treated
156  // equal: if the equality is enforced (rather than the pointers may be equal),
157  // then we don't even build the constructor functions
158  if(lhs.id() == ID_symbol)
159  {
160  const auto maybe_cluster_index =
161  find_equal_cluster(to_symbol_expr(lhs).get_identifier());
162  if(maybe_cluster_index.has_value())
163  {
164  if(common_arguments_origins[*maybe_cluster_index].has_value())
165  {
166  const auto set_equal_case =
167  code_assignt{lhs, *common_arguments_origins[*maybe_cluster_index]};
169  {
170  const irep_idt &fun_name = build_constructor(lhs);
171  const symbolt &fun_symbol =
173  const auto proper_init_case = code_function_callt{
174  fun_symbol.symbol_expr(), {depth, address_of_exprt{lhs}}};
175  const auto should_make_equal =
176  get_fresh_local_typed_symexpr("should_make_equal", bool_typet{});
177  body.add(code_declt{should_make_equal});
178  body.add(code_ifthenelset{
179  should_make_equal, set_equal_case, proper_init_case});
180  }
181  else
182  {
183  body.add(set_equal_case);
184  }
185  return;
186  }
187  else
188  {
189  common_arguments_origins[*maybe_cluster_index] = lhs;
190  }
191  }
192  }
193 
194  const irep_idt &fun_name = build_constructor(lhs);
195  const symbolt &fun_symbol = goto_model.symbol_table.lookup_ref(fun_name);
196 
197  if(lhs.id() == ID_symbol)
198  {
199  const irep_idt &lhs_name = to_symbol_expr(lhs).get_identifier();
200  if(should_be_treated_as_array(lhs_name))
201  {
202  auto size_var = get_associated_size_variable(lhs_name);
203  if(size_var.has_value())
204  {
205  const symbol_exprt &size_symbol =
206  goto_model.symbol_table.lookup_ref(size_var.value()).symbol_expr();
208  fun_symbol.symbol_expr(),
209  {depth, address_of_exprt{lhs}, address_of_exprt{size_symbol}}});
210  }
211  else
212  {
213  const auto &fun_type_params =
214  to_code_type(fun_symbol.type).parameters();
215  const pointer_typet *size_var_type =
216  type_try_dynamic_cast<pointer_typet>(fun_type_params.back().type());
217  INVARIANT(size_var_type, "Size parameter must have pointer type.");
219  fun_symbol.symbol_expr(),
220  {depth, address_of_exprt{lhs}, null_pointer_exprt{*size_var_type}}});
221  }
222  return;
223  }
224  for(const auto &irep_pair :
226  {
227  // skip initialisation of array-size variables
228  if(irep_pair.second == lhs_name)
229  return;
230  }
231  }
232  body.add(code_function_callt{fun_symbol.symbol_expr(),
233  {depth, address_of_exprt{lhs}}});
234 }
235 
237 {
238  const typet &type_to_construct =
240  const null_pointer_exprt nullptr_expr{to_pointer_type(type_to_construct)};
241  const code_assignt assign_null{dereference_exprt{result_symbol},
242  nullptr_expr};
243  return code_blockt{{assign_null, code_frontend_returnt{}}};
244 }
245 
247  const exprt &depth_symbol,
249  const std::optional<exprt> &size_symbol,
250  const std::optional<irep_idt> &lhs_name,
251  const bool is_nullable)
252 {
253  PRECONDITION(result_symbol.type().id() == ID_pointer);
254  const typet &type = to_pointer_type(result_symbol.type()).base_type();
255  if(type.id() == ID_struct_tag)
256  {
257  return build_struct_constructor(depth_symbol, result_symbol);
258  }
259  else if(type.id() == ID_pointer)
260  {
261  if(to_pointer_type(type).base_type().id() == ID_code)
262  {
264  }
265  if(to_pointer_type(type).base_type().id() == ID_empty)
266  {
267  // always initalize void* pointers as NULL
269  }
270  if(lhs_name.has_value())
271  {
272  if(should_be_treated_as_array(*lhs_name))
273  {
274  CHECK_RETURN(size_symbol.has_value());
276  depth_symbol, result_symbol, *size_symbol, lhs_name);
277  }
278  }
279  return build_pointer_constructor(depth_symbol, result_symbol);
280  }
281  else if(type.id() == ID_array)
282  {
283  return build_array_constructor(depth_symbol, result_symbol);
284  }
285  else
286  {
288  }
289 }
290 
292 {
293  // for `expr` of type T builds a declaration of a function:
294  //
295  // void type_constructor_T(int depth_T, T *result);
296  //
297  // or in case a `size` is associated with the `expr`
298  //
299  // void type_constructor_T(int depth_T, T *result_T, int *size);
300  std::optional<irep_idt> size_var;
301  std::optional<irep_idt> expr_name;
302  bool is_nullable = false;
303  bool has_size_param = false;
304  if(expr.id() == ID_symbol)
305  {
306  expr_name = to_symbol_expr(expr).get_identifier();
308  expr_name.value());
309  if(should_be_treated_as_array(*expr_name))
310  {
311  size_var = get_associated_size_variable(*expr_name);
312  has_size_param = true;
313  }
314  }
315  const typet &type = expr.type();
316  const constructor_keyt key{type, is_nullable, has_size_param};
317  if(type_constructor_names.find(key) != type_constructor_names.end())
318  return type_constructor_names[key];
319 
320  const std::string &pretty_type = type2id(type);
321  symbolt &depth_symbol =
322  get_fresh_param_symbol("depth_" + pretty_type, signed_int_type());
323  depth_symbol.value = from_integer(0, signed_int_type());
324 
325  code_typet::parameterst fun_params;
326  code_typet::parametert depth_parameter{signed_int_type()};
327  depth_parameter.set_identifier(depth_symbol.name);
328  fun_params.push_back(depth_parameter);
329 
330  const typet &result_type = pointer_type(type);
331  const symbolt &result_symbol =
332  get_fresh_param_symbol("result_" + pretty_type, result_type);
333  code_typet::parametert result_parameter{result_type};
334  result_parameter.set_identifier(result_symbol.name);
335  fun_params.push_back(result_parameter);
336 
337  auto &symbol_table = goto_model.symbol_table;
338  std::optional<exprt> size_symbol_expr;
339  if(expr_name.has_value() && should_be_treated_as_array(*expr_name))
340  {
341  typet size_var_type;
342  if(size_var.has_value())
343  {
344  const symbol_exprt &size_var_symbol_expr =
345  symbol_table.lookup_ref(*size_var).symbol_expr();
346  size_var_type = pointer_type(size_var_symbol_expr.type());
347  }
348  else
349  size_var_type = pointer_type(signed_int_type());
350 
351  const symbolt &size_symbol =
352  get_fresh_param_symbol("size_" + pretty_type, size_var_type);
353  fun_params.push_back(code_typet::parametert{size_var_type});
354  fun_params.back().set_identifier(size_symbol.name);
355  size_symbol_expr = size_symbol.symbol_expr();
356  }
357  const symbolt &function_symbol = get_fresh_fun_symbol(
358  "type_constructor_" + pretty_type, code_typet{fun_params, empty_typet{}});
359  type_constructor_names[key] = function_symbol.name;
360  symbolt *mutable_symbol = symbol_table.get_writeable(function_symbol.name);
361 
362  // the body is specific for each type of expression
363  mutable_symbol->value = build_constructor_body(
364  depth_symbol.symbol_expr(),
366  size_symbol_expr,
367  // the expression name may be needed to decide if expr should be treated as
368  // a string
369  expr_name,
370  is_nullable);
371 
372  return type_constructor_names.at(key);
373 }
374 
376 {
377  auto malloc_sym = goto_model.symbol_table.lookup("malloc");
378  if(malloc_sym == nullptr)
379  {
380  symbolt new_malloc_sym{
381  "malloc",
382  code_typet{
385  new_malloc_sym.pretty_name = "malloc";
386  new_malloc_sym.base_name = "malloc";
387  goto_model.symbol_table.insert(new_malloc_sym);
388  return new_malloc_sym.symbol_expr();
389  }
390  return malloc_sym->symbol_expr();
391 }
392 
394  const irep_idt &array_name) const
395 {
398 }
399 
400 std::optional<recursive_initializationt::equal_cluster_idt>
402 {
403  for(equal_cluster_idt index = 0;
405  ++index)
406  {
407  if(initialization_config.pointers_to_treat_equal[index].count(name) != 0)
408  return index;
409  }
410  return {};
411 }
412 
414  const irep_idt &cmdline_arg) const
415 {
417  cmdline_arg) !=
419 }
420 
422  const irep_idt &array_name) const
423 {
424  return optional_lookup(
426  array_name);
427 }
428 
430  const irep_idt &pointer_name) const
431 {
433  pointer_name) != 0;
434 }
435 
437 {
438  std::ostringstream out{};
439  out << "recursive_initialization_config {"
440  << "\n min_null_tree_depth = " << min_null_tree_depth
441  << "\n max_nondet_tree_depth = " << max_nondet_tree_depth
442  << "\n mode = " << mode
443  << "\n max_dynamic_array_size = " << max_dynamic_array_size
444  << "\n min_dynamic_array_size = " << min_dynamic_array_size
445  << "\n pointers_to_treat_as_arrays = [";
446  for(auto const &pointer : pointers_to_treat_as_arrays)
447  {
448  out << "\n " << pointer;
449  }
450  out << "\n ]"
451  << "\n variables_that_hold_array_sizes = [";
452  for(auto const &array_size : variables_that_hold_array_sizes)
453  {
454  out << "\n " << array_size;
455  }
456  out << "\n ]";
457  out << "\n array_name_to_associated_size_variable = [";
458  for(auto const &associated_array_size :
460  {
461  out << "\n " << associated_array_size.first << " -> "
462  << associated_array_size.second;
463  }
464  out << "\n ]";
465  out << "\n pointers_to_treat_as_cstrings = [";
466  for(const auto &pointer_to_treat_as_string_name :
468  {
469  out << "\n " << pointer_to_treat_as_string_name << std::endl;
470  }
471  out << "\n ]";
472  out << "\n}";
473  return out.str();
474 }
475 
477  symbol_tablet &symbol_table,
478  const std::string &symbol_base_name,
479  typet symbol_type,
480  irep_idt mode)
481 {
482  source_locationt source_location{};
483  source_location.set_file(GOTO_HARNESS_PREFIX "harness.c");
484  symbolt &fresh_symbol = get_fresh_aux_symbol(
485  std::move(symbol_type),
487  symbol_base_name,
489  mode,
490  symbol_table);
491  fresh_symbol.base_name = fresh_symbol.pretty_name = symbol_base_name;
492  fresh_symbol.is_static_lifetime = true;
493  fresh_symbol.is_lvalue = true;
494  fresh_symbol.is_auxiliary = false;
495  fresh_symbol.is_file_local = false;
496  fresh_symbol.is_thread_local = false;
497  fresh_symbol.is_state_var = false;
498  fresh_symbol.module = GOTO_HARNESS_PREFIX "harness";
499  fresh_symbol.location = std::move(source_location);
500  return fresh_symbol;
501 }
502 
504  const std::string &symbol_name,
505  const exprt &initial_value) const
506 {
507  auto &fresh_symbol = get_fresh_global_symbol(
509  symbol_name,
510  signed_int_type(), // FIXME why always signed_int_type???
512  fresh_symbol.value = initial_value;
513  return fresh_symbol.name;
514 }
515 
517  const std::string &symbol_name) const
518 {
519  auto &fresh_symbol = get_fresh_global_symbol(
521  symbol_name,
522  signed_int_type(),
524  fresh_symbol.value = from_integer(0, signed_int_type());
525  return fresh_symbol.symbol_expr();
526 }
527 
529  const std::string &symbol_name) const
530 {
531  symbolt &fresh_symbol = get_fresh_aux_symbol(
532  signed_int_type(),
534  symbol_name,
538  fresh_symbol.is_lvalue = true;
539  fresh_symbol.value = from_integer(0, signed_int_type());
540  return fresh_symbol.symbol_expr();
541 }
542 
544  const std::string &symbol_name,
545  const typet &type) const
546 {
547  symbolt &fresh_symbol = get_fresh_aux_symbol(
548  type,
550  symbol_name,
554  fresh_symbol.is_lvalue = true;
555  fresh_symbol.mode = initialization_config.mode;
556  return fresh_symbol.symbol_expr();
557 }
558 
560  const std::string &fun_name,
561  const typet &fun_type)
562 {
563  irep_idt fresh_name =
565 
566  // create the function symbol
567  symbolt function_symbol{};
568  function_symbol.name = function_symbol.base_name =
569  function_symbol.pretty_name = fresh_name;
570 
571  function_symbol.is_lvalue = true;
572  function_symbol.mode = initialization_config.mode;
573  function_symbol.type = fun_type;
574 
575  auto r = goto_model.symbol_table.insert(function_symbol);
576  CHECK_RETURN(r.second);
577  return *goto_model.symbol_table.lookup(fresh_name);
578 }
579 
581  const std::string &symbol_name,
582  const typet &symbol_type)
583 {
584  symbolt &param_symbol = get_fresh_aux_symbol(
585  symbol_type,
587  symbol_name,
591  param_symbol.is_parameter = true;
592  param_symbol.is_lvalue = true;
593  param_symbol.mode = initialization_config.mode;
594 
595  return param_symbol;
596 }
597 
600 {
601  auto maybe_symbol = goto_model.symbol_table.lookup(symbol_name);
602  CHECK_RETURN(maybe_symbol != nullptr);
603  return maybe_symbol->symbol_expr();
604 }
605 
606 std::string recursive_initializationt::type2id(const typet &type) const
607 {
608  if(type.id() == ID_struct_tag)
609  {
610  auto st_tag = id2string(to_struct_tag_type(type).get_identifier());
611  std::replace(st_tag.begin(), st_tag.end(), '-', '_');
612  return st_tag;
613  }
614  else if(type.id() == ID_pointer)
615  return "ptr_" + type2id(to_pointer_type(type).base_type());
616  else if(type.id() == ID_array)
617  {
618  const auto array_size =
619  numeric_cast_v<std::size_t>(to_constant_expr(to_array_type(type).size()));
620  return "arr_" + type2id(to_array_type(type).element_type()) + "_" +
621  std::to_string(array_size);
622  }
623  else if(type == char_type())
624  return "char";
625  else if(type.id() == ID_signedbv)
626  return "int";
627  else if(type.id() == ID_unsignedbv)
628  return "uint";
629  else
630  return "";
631 }
632 
634 {
635  auto free_sym = goto_model.symbol_table.lookup("free");
636  if(free_sym == nullptr)
637  {
638  symbolt new_free_sym{
639  "free",
640  code_typet{
643  new_free_sym.pretty_name = "free";
644  new_free_sym.base_name = "free";
645  goto_model.symbol_table.insert(new_free_sym);
646  return new_free_sym.symbol_expr();
647  }
648  return free_sym->symbol_expr();
649 }
650 
652  const exprt &depth,
653  const symbol_exprt &result)
654 {
655  PRECONDITION(result.type().id() == ID_pointer);
656  const typet &type = to_pointer_type(result.type()).base_type();
657  PRECONDITION(type.id() == ID_pointer);
658  PRECONDITION(to_pointer_type(type).base_type().id() != ID_empty);
659 
660  code_blockt body{};
661  // build:
662  // void type_constructor_ptr_T(int depth, T** result)
663  // {
664  // if(has_seen && depth >= max_depth)
665  // *result=NULL;
666  // return
667  // if(nondet()) {
668  // size_t has_seen_prev;
669  // has_seen_prev = T_has_seen;
670  // T_has_seen = 1;
671  // *result = malloc(sizeof(T));
672  // type_constructor_T(depth+1, *result);
673  // T_has_seen=has_seen_prev;
674  // }
675  // else
676  // *result=NULL;
677  // }
678 
679  binary_predicate_exprt depth_gt_max_depth{
680  depth, ID_ge, get_symbol_expr(max_depth_var_name)};
681  exprt::operandst should_not_recurse{depth_gt_max_depth};
682 
683  std::optional<symbol_exprt> has_seen;
684  if(can_cast_type<struct_tag_typet>(to_pointer_type(type).base_type()))
685  has_seen = get_fresh_global_symexpr(
686  "has_seen_" + type2id(to_pointer_type(type).base_type()));
687 
688  if(has_seen.has_value())
689  {
690  equal_exprt has_seen_expr{*has_seen, from_integer(1, has_seen->type())};
691  should_not_recurse.push_back(has_seen_expr);
692  }
693 
694  null_pointer_exprt nullptr_expr{
695  pointer_type(to_pointer_type(type).base_type())};
696  const code_assignt assign_null{dereference_exprt{result}, nullptr_expr};
697  code_blockt null_and_return{{assign_null, code_frontend_returnt{}}};
698  body.add(code_ifthenelset{conjunction(should_not_recurse), null_and_return});
699 
700  const auto should_recurse_nondet =
701  get_fresh_local_typed_symexpr("should_recurse_nondet", bool_typet{});
702  body.add(code_declt{should_recurse_nondet});
703  exprt::operandst should_recurse_ops{
705  should_recurse_nondet};
706  code_blockt then_case{};
707 
708  code_assignt seen_assign_prev{};
709  if(has_seen.has_value())
710  {
711  const symbol_exprt &has_seen_prev = get_fresh_local_symexpr(
712  "has_seen_prev_" + type2id(to_pointer_type(type).base_type()));
713  then_case.add(code_declt{has_seen_prev});
714  then_case.add(code_assignt{has_seen_prev, *has_seen});
715  then_case.add(code_assignt{*has_seen, from_integer(1, has_seen->type())});
716  seen_assign_prev = code_assignt{*has_seen, has_seen_prev};
717  }
718 
719  // we want to initialize the pointee as non-const even for pointer to const
720  const pointer_typet non_const_pointer_type =
721  pointer_type(remove_const(to_pointer_type(type).base_type()));
722  const symbol_exprt &local_result =
723  get_fresh_local_typed_symexpr("local_result", non_const_pointer_type);
724 
725  then_case.add(code_declt{local_result});
727  then_case.add(code_function_callt{
728  local_result,
730  {*size_of_expr(non_const_pointer_type.base_type(), ns)}});
731  initialize(
732  dereference_exprt{local_result},
733  plus_exprt{depth, from_integer(1, depth.type())},
734  then_case);
735  then_case.add(code_assignt{dereference_exprt{result}, local_result});
736 
737  if(has_seen.has_value())
738  {
739  then_case.add(seen_assign_prev);
740  }
741 
742  body.add(
743  code_ifthenelset{disjunction(should_recurse_ops), then_case, assign_null});
744  return body;
745 }
746 
748  const exprt &depth,
749  const symbol_exprt &result)
750 {
751  PRECONDITION(result.type().id() == ID_pointer);
752  const typet &type = to_pointer_type(result.type()).base_type();
753  PRECONDITION(type.id() == ID_array);
754  const array_typet &array_type = to_array_type(type);
755  const auto array_size =
756  numeric_cast_v<std::size_t>(to_constant_expr(array_type.size()));
757  code_blockt body{};
758 
759  for(std::size_t index = 0; index < array_size; index++)
760  {
761  initialize(
763  depth,
764  body);
765  }
766  return body;
767 }
768 
770  const exprt &depth,
771  const symbol_exprt &result)
772 {
773  PRECONDITION(result.type().id() == ID_pointer);
774  const typet &struct_type = to_pointer_type(result.type()).base_type();
775  PRECONDITION(struct_type.id() == ID_struct_tag);
776  code_blockt body{};
778  for(const auto &component :
779  ns.follow_tag(to_struct_tag_type(struct_type)).components())
780  {
781  if(component.get_is_padding())
782  {
783  continue;
784  }
785  // if the struct component is const we need to cast away the const
786  // for initialisation purposes.
787  // As far as I'm aware that's the closest thing to a 'correct' way
788  // to initialize dynamically allocated structs with const components
789  exprt component_initialisation_lhs = [&result, &component]() -> exprt {
790  auto member_expr = member_exprt{dereference_exprt{result}, component};
791  if(component.type().get_bool(ID_C_constant))
792  {
793  return dereference_exprt{
794  typecast_exprt{address_of_exprt{std::move(member_expr)},
796  }
797  else
798  {
799  return std::move(member_expr);
800  }
801  }();
802  initialize(component_initialisation_lhs, depth, body);
803  }
804  return body;
805 }
806 
808  const symbol_exprt &result) const
809 {
810  PRECONDITION(result.type().id() == ID_pointer);
811  code_blockt body{};
812  auto const nondet_symbol = get_fresh_local_typed_symexpr(
813  "nondet", to_pointer_type(result.type()).base_type());
814  body.add(code_declt{nondet_symbol});
815  body.add(code_assignt{dereference_exprt{result}, nondet_symbol});
816  return body;
817 }
818 
820  const exprt &depth,
821  const symbol_exprt &result,
822  const exprt &size,
823  const std::optional<irep_idt> &lhs_name)
824 {
825  PRECONDITION(result.type().id() == ID_pointer);
826  const typet &dynamic_array_type = to_pointer_type(result.type()).base_type();
827  PRECONDITION(dynamic_array_type.id() == ID_pointer);
828  const typet &element_type = to_pointer_type(dynamic_array_type).base_type();
829  PRECONDITION(element_type.id() != ID_empty);
830 
831  // builds:
832  // void type_constructor_ptr_T(int depth, T** result, int* size)
833  // {
834  // int nondet_size;
835  // assume(nondet_size >= min_array_size && nondet_size <= max_array_size);
836  // T* local_result = malloc(nondet_size * sizeof(T));
837  // for (int i = 0; i < nondet_size; ++i)
838  // {
839  // type_construct_T(depth+1, local_result+i);
840  // }
841  // *result = local_result;
842  // if (size!=NULL)
843  // *size = nondet_size;
844  // }
845 
846  const auto min_array_size = initialization_config.min_dynamic_array_size;
847  const auto max_array_size = initialization_config.max_dynamic_array_size;
848  PRECONDITION(max_array_size >= min_array_size);
849 
850  code_blockt body{};
851  const symbol_exprt &nondet_size = get_fresh_local_symexpr("nondet_size");
852  body.add(code_declt{nondet_size});
853 
854  body.add(code_assumet{and_exprt{
856  nondet_size, ID_ge, from_integer(min_array_size, nondet_size.type())},
858  nondet_size, ID_le, from_integer(max_array_size, nondet_size.type())}}});
859 
860  // we want the local result to be mutable so we can initialise it
861  const typet mutable_dynamic_array_type =
862  pointer_type(remove_const(element_type));
863  const symbol_exprt &local_result =
864  get_fresh_local_typed_symexpr("local_result", mutable_dynamic_array_type);
865  body.add(code_declt{local_result});
867  for(auto array_size = min_array_size; array_size <= max_array_size;
868  ++array_size)
869  {
870  body.add(code_ifthenelset{
871  equal_exprt{nondet_size, from_integer(array_size, nondet_size.type())},
872  code_function_callt{local_result,
874  {mult_exprt{from_integer(array_size, size_type()),
875  *size_of_expr(element_type, ns)}}}});
876  }
877 
878  const symbol_exprt &index_iter = get_fresh_local_symexpr("index");
879  body.add(code_declt{index_iter});
880  code_assignt for_init{index_iter, from_integer(0, index_iter.type())};
881  binary_relation_exprt for_cond{index_iter, ID_lt, nondet_size};
882  side_effect_exprt for_iter{
883  ID_preincrement, {index_iter}, typet{}, source_locationt{}};
884  code_blockt for_body{};
885  if(lhs_name.has_value() && should_be_treated_as_cstring(*lhs_name))
886  {
887  code_blockt else_case{};
888  initialize(
889  dereference_exprt{plus_exprt{local_result, index_iter}},
890  plus_exprt{depth, from_integer(1, depth.type())},
891  else_case);
892  else_case.add(code_assumet{
893  notequal_exprt{dereference_exprt{plus_exprt{local_result, index_iter}},
894  from_integer(0, char_type())}});
895 
896  for_body.add(code_ifthenelset{
897  equal_exprt{
898  index_iter,
899  minus_exprt{nondet_size, from_integer(1, nondet_size.type())}},
900  code_assignt{dereference_exprt{plus_exprt{local_result, index_iter}},
901  from_integer(0, char_type())},
902  else_case});
903  }
904  else
905  {
906  initialize(
907  dereference_exprt{plus_exprt{local_result, index_iter}},
908  plus_exprt{depth, from_integer(1, depth.type())},
909  for_body);
910  }
911 
912  body.add(code_fort{for_init, for_cond, for_iter, for_body});
913  body.add(code_assignt{dereference_exprt{result}, local_result});
914 
915  CHECK_RETURN(size.type().id() == ID_pointer);
916  body.add(code_ifthenelset{
918  code_assignt{
919  dereference_exprt{size},
921  nondet_size, to_pointer_type(size.type()).base_type())}});
922 
923  return body;
924 }
925 
927 {
928  if(
929  expr.type().id() != ID_pointer ||
930  to_pointer_type(expr.type()).base_type().id() == ID_code)
931  return false;
932  for(auto const &common_arguments_origin : common_arguments_origins)
933  {
934  if(common_arguments_origin.has_value() && expr.id() == ID_symbol)
935  {
936  auto origin_name =
937  to_symbol_expr(*common_arguments_origin).get_identifier();
938  auto expr_name = to_symbol_expr(expr).get_identifier();
939  return origin_name == expr_name;
940  }
941  }
942  return true;
943 }
944 
946  const exprt &expr,
947  code_blockt &body)
948 {
949  PRECONDITION(expr.id() == ID_symbol);
950  const auto expr_id = to_symbol_expr(expr).get_identifier();
951  const auto maybe_cluster_index = find_equal_cluster(expr_id);
952  const auto call_free = code_function_callt{get_free_function(), {expr}};
953  if(!maybe_cluster_index.has_value())
954  {
955  // not in any equality cluster -> just free
956  body.add(call_free);
957  return;
958  }
959 
960  if(
961  to_symbol_expr(*common_arguments_origins[*maybe_cluster_index])
962  .get_identifier() != expr_id &&
964  {
965  // in equality cluster but not common origin -> free if not equal to origin
966  const auto condition =
967  notequal_exprt{expr, *common_arguments_origins[*maybe_cluster_index]};
968  body.add(code_ifthenelset{condition, call_free});
969  }
970  else
971  {
972  // expr is common origin, leave freeing until the rest of the cluster is
973  // freed
974  return;
975  }
976 }
977 
979 {
980  for(auto const &origin : common_arguments_origins)
981  {
982  body.add(code_function_callt{get_free_function(), {*origin}});
983  }
984 }
985 
987  const symbol_exprt &result,
988  bool is_nullable)
989 {
991  const auto &result_type = to_pointer_type(result.type());
992  PRECONDITION(can_cast_type<pointer_typet>(result_type.base_type()));
993  const auto &function_pointer_type = to_pointer_type(result_type.base_type());
994  PRECONDITION(can_cast_type<code_typet>(function_pointer_type.base_type()));
995  const auto &function_type = to_code_type(function_pointer_type.base_type());
996 
997  std::vector<exprt> targets;
998 
999  for(const auto &sym : goto_model.get_symbol_table())
1000  {
1001  if(sym.second.type == function_type)
1002  {
1003  targets.push_back(address_of_exprt{sym.second.symbol_expr()});
1004  }
1005  }
1006 
1007  if(is_nullable)
1008  targets.push_back(null_pointer_exprt{function_pointer_type});
1009 
1010  code_blockt body{};
1011 
1012  const auto function_pointer_selector =
1013  get_fresh_local_symexpr("function_pointer_selector");
1014  body.add(code_declt{function_pointer_selector});
1015  auto function_pointer_index = std::size_t{0};
1016 
1017  for(const auto &target : targets)
1018  {
1019  auto const assign = code_assignt{dereference_exprt{result}, target};
1020  auto const sym_to_lookup =
1021  target.id() == ID_address_of
1022  ?
1023  // This is either address of or pointer; in pointer case, we don't
1024  // need to do anything. In the address of case, the operand is
1025  // a symbol representing a target function.
1027  : "";
1028  // skip referencing globals because the corresponding symbols in the symbol
1029  // table are no longer marked as file local.
1030  if(sym_to_lookup.starts_with(FILE_LOCAL_PREFIX))
1031  {
1032  continue;
1033  }
1034  else if(
1035  goto_model.get_symbol_table().lookup(sym_to_lookup) &&
1036  goto_model.get_symbol_table().lookup(sym_to_lookup)->is_file_local)
1037  {
1038  continue;
1039  }
1040 
1041  if(function_pointer_index != targets.size() - 1)
1042  {
1043  auto const condition = equal_exprt{
1044  function_pointer_selector,
1045  from_integer(function_pointer_index, function_pointer_selector.type())};
1046  auto const then = code_blockt{{assign, code_frontend_returnt{}}};
1047  body.add(code_ifthenelset{condition, then});
1048  }
1049  else
1050  {
1051  body.add(assign);
1052  }
1053  ++function_pointer_index;
1054  }
1055 
1056  return body;
1057 }
1058 
1060  const exprt &lhs,
1061  const exprt &depth,
1062  code_blockt &body,
1063  const std::vector<irep_idt> &selection_spec)
1064 {
1065  PRECONDITION(lhs.id() == ID_symbol);
1066  PRECONDITION(lhs.type().id() == ID_struct_tag);
1067  PRECONDITION(!selection_spec.empty());
1068 
1069  auto component_member = lhs;
1071 
1072  for(auto it = selection_spec.begin() + 1; it != selection_spec.end(); it++)
1073  {
1074  if(component_member.type().id() != ID_struct_tag)
1075  {
1077  "'" + id2string(*it) + "' is not a component name",
1079  }
1080  const auto &struct_tag_type = to_struct_tag_type(component_member.type());
1081  const auto &struct_type = to_struct_type(ns.follow_tag(struct_tag_type));
1082 
1083  bool found = false;
1084  for(auto const &component : struct_type.components())
1085  {
1086  const auto &component_type = component.type();
1087  const auto component_name = component.get_name();
1088 
1089  if(*it == component_name)
1090  {
1091  component_member =
1092  member_exprt{component_member, component_name, component_type};
1093  found = true;
1094  break;
1095  }
1096  }
1097  if(!found)
1098  {
1100  "'" + id2string(*it) + "' is not a component name",
1102  }
1103  }
1104  initialize(component_member, depth, body);
1105 }
static abstract_object_pointert transform(const exprt &expr, const std::vector< abstract_object_pointert > &operands, const abstract_environmentt &environment, const namespacet &ns)
constant_exprt from_integer(const mp_integer &int_value, const typet &type)
Definition: arith_tools.cpp:99
std::string array_name(const namespacet &ns, const exprt &expr)
Definition: array_name.cpp:19
static symbolt result_symbol(const irep_idt &identifier, const typet &type, const source_locationt &source_location, symbol_table_baset &symbol_table)
signedbv_typet signed_int_type()
Definition: c_types.cpp:22
pointer_typet pointer_type(const typet &subtype)
Definition: c_types.cpp:235
bitvector_typet char_type()
Definition: c_types.cpp:106
unsigned char opt
Definition: cegis.c:20
Operator to return the address of an object.
Definition: pointer_expr.h:540
Boolean AND.
Definition: std_expr.h:2125
Arrays with given size.
Definition: std_types.h:807
const exprt & size() const
Definition: std_types.h:840
A base class for expressions that are predicates, i.e., Boolean-typed, and that take exactly two argu...
Definition: std_expr.h:731
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
A goto_instruction_codet representing an assignment in the program.
An assumption, which must hold in subsequent code.
Definition: std_code.h:217
A codet representing sequential composition of program statements.
Definition: std_code.h:130
void add(const codet &code)
Definition: std_code.h:168
A goto_instruction_codet representing the declaration of a local variable.
codet representation of a for statement.
Definition: std_code.h:734
codet representation of a "return from a function" statement.
Definition: std_code.h:893
goto_instruction_codet representation of a function call statement.
codet representation of an if-then-else statement.
Definition: std_code.h:460
Base type of functions.
Definition: std_types.h:583
std::vector< parametert > parameterst
Definition: std_types.h:585
const parameterst & parameters() const
Definition: std_types.h:699
Operator to dereference a pointer.
Definition: pointer_expr.h:834
dstringt has one field, an unsigned integer no which is an index into a static table of strings.
Definition: dstring.h:38
The empty type.
Definition: std_types.h:51
Equality.
Definition: std_expr.h:1366
Base class for all expressions.
Definition: expr.h:56
std::vector< exprt > operandst
Definition: expr.h:58
typet & type()
Return the type of the expression.
Definition: expr.h:84
const symbol_tablet & get_symbol_table() const override
Accessor to get the symbol table.
Definition: goto_model.h:84
symbol_tablet symbol_table
Symbol table.
Definition: goto_model.h:31
Array index operator.
Definition: std_expr.h:1470
Thrown when users pass incorrect command line arguments, for example passing no files to analysis or ...
const irep_idt & id() const
Definition: irep.h:388
irept & add(const irep_idt &name)
Definition: irep.cpp:103
Extract member of struct or union.
Definition: std_expr.h:2854
Binary minus.
Definition: std_expr.h:1061
Binary multiplication Associativity is not specified.
Definition: std_expr.h:1107
A namespacet is essentially one or two symbol tables bound together, to allow for symbol lookups in t...
Definition: namespace.h:94
Disequality.
Definition: std_expr.h:1425
The null pointer constant.
Definition: pointer_expr.h:909
The plus expression Associativity is not specified.
Definition: std_expr.h:1002
The pointer type These are both 'bitvector_typet' (they have a width) and 'type_with_subtypet' (they ...
Definition: pointer_expr.h:24
const typet & base_type() const
The type of the data what we point to.
Definition: pointer_expr.h:35
void initialize_selected_member(const exprt &lhs, const exprt &depth, code_blockt &body, const std::vector< irep_idt > &selection_spec)
Select the specified struct-member to be non-deterministically initialized.
std::string type2id(const typet &type) const
Simple pretty-printer for typet.
void free_if_possible(const exprt &expr, code_blockt &body)
type_constructor_namest type_constructor_names
code_blockt build_dynamic_array_constructor(const exprt &depth, const symbol_exprt &result, const exprt &size, const std::optional< irep_idt > &lhs_name)
Constructor for dynamic arrays: allocate memory for n elements (n is random but bounded) and initiali...
code_blockt build_constructor_body(const exprt &depth_symbol, const symbol_exprt &result_symbol, const std::optional< exprt > &size_symbol, const std::optional< irep_idt > &lhs_name, const bool is_nullable)
Case analysis for which constructor should be used.
std::vector< std::optional< exprt > > common_arguments_origins
code_blockt build_nondet_constructor(const symbol_exprt &result) const
Default constructor: assigns non-deterministic value of the right type.
symbol_exprt get_malloc_function()
Get the malloc function as symbol exprt, and inserts it into the goto-model if it doesn't exist alrea...
std::optional< equal_cluster_idt > find_equal_cluster(const irep_idt &name) const
code_blockt build_struct_constructor(const exprt &depth, const symbol_exprt &result)
Constructor for structures: simply iterates over members and initialise each one.
irep_idt build_constructor(const exprt &expr)
Check if a constructor for the type of expr already exists and create it if not.
irep_idt get_fresh_global_name(const std::string &symbol_name, const exprt &initial_value) const
Construct a new global symbol of type int and set it's value to initial_value.
code_blockt build_function_pointer_constructor(const symbol_exprt &result, bool is_nullable)
Constructor for function pointers.
const recursive_initialization_configt initialization_config
symbol_exprt get_fresh_local_typed_symexpr(const std::string &symbol_name, const typet &type) const
Construct a new local symbol of type type initialised to init_value.
std::optional< irep_idt > get_associated_size_variable(const irep_idt &array_name) const
code_blockt build_array_constructor(const exprt &depth, const symbol_exprt &result)
Constructor for arrays: simply iterates over elements and initialise each one.
recursive_initializationt(recursive_initialization_configt initialization_config, goto_modelt &goto_model)
void free_cluster_origins(code_blockt &body)
bool should_be_treated_as_array(const irep_idt &pointer_name) const
void initialize(const exprt &lhs, const exprt &depth, code_blockt &body)
Generate initialisation code for lhs into body.
symbol_exprt get_free_function()
Get the free function as symbol expression, and inserts it into the goto-model if it doesn't exist al...
bool needs_freeing(const exprt &expr) const
const symbolt & get_fresh_fun_symbol(const std::string &fun_name, const typet &fun_type)
Construct a new function symbol of type fun_type.
bool should_be_treated_as_cstring(const irep_idt &pointer_name) const
symbol_exprt get_fresh_local_symexpr(const std::string &symbol_name) const
Construct a new local symbol of type int initialised to 0.
bool is_array_size_parameter(const irep_idt &cmdline_arg) const
symbol_exprt get_symbol_expr(const irep_idt &symbol_name) const
Recover the symbol expression from symbol table.
symbol_exprt get_fresh_global_symexpr(const std::string &symbol_name) const
Construct a new global symbol of type int initialised to 0.
code_blockt build_pointer_constructor(const exprt &depth, const symbol_exprt &result)
Generic constructor for all pointers: only builds one pointee (not an array) but may recourse in case...
symbolt & get_fresh_param_symbol(const std::string &param_name, const typet &param_type)
Construct a new parameter symbol of type param_type.
An expression containing a side effect.
Definition: std_code.h:1450
void set_file(const irep_idt &file)
Expression to hold a symbol (variable)
Definition: std_expr.h:131
const irep_idt & get_identifier() const
Definition: std_expr.h:160
const symbolt * lookup(const irep_idt &name) const
Find a symbol in the symbol table for read-only access.
const symbolt & lookup_ref(const irep_idt &name) const
Find a symbol in the symbol table for read-only access.
bool add(const symbolt &symbol)
Add a new symbol to the symbol table.
The symbol table.
Definition: symbol_table.h:14
virtual std::pair< symbolt &, bool > insert(symbolt symbol) override
Author: Diffblue Ltd.
Symbol table entry.
Definition: symbol.h:28
irep_idt base_name
Base (non-scoped) name.
Definition: symbol.h:46
bool is_auxiliary
Definition: symbol.h:77
bool is_file_local
Definition: symbol.h:73
irep_idt module
Name of module the symbol belongs to.
Definition: symbol.h:43
bool is_static_lifetime
Definition: symbol.h:70
bool is_parameter
Definition: symbol.h:76
bool is_thread_local
Definition: symbol.h:71
source_locationt location
Source code location of definition of symbol.
Definition: symbol.h:37
bool is_state_var
Definition: symbol.h:66
class symbol_exprt symbol_expr() const
Produces a symbol_exprt for a symbol.
Definition: symbol.cpp:121
typet type
Type of symbol.
Definition: symbol.h:31
irep_idt name
The unique identifier.
Definition: symbol.h:40
irep_idt pretty_name
Language-specific display name.
Definition: symbol.h:52
bool is_lvalue
Definition: symbol.h:72
exprt value
Initial value of symbol.
Definition: symbol.h:34
irep_idt mode
Language mode.
Definition: symbol.h:49
Semantic type conversion.
Definition: std_expr.h:2073
static exprt conditional_cast(const exprt &expr, const typet &type)
Definition: std_expr.h:2081
The type of an expression, extends irept.
Definition: type.h:29
#define COMMON_HARNESS_GENERATOR_FUNCTION_POINTER_CAN_BE_NULL_OPT
#define COMMON_HARNESS_GENERATOR_MIN_ARRAY_SIZE_OPT
#define COMMON_HARNESS_GENERATOR_MIN_NULL_TREE_DEPTH_OPT
#define COMMON_HARNESS_GENERATOR_MAX_ARRAY_SIZE_OPT
#define COMMON_HARNESS_GENERATOR_MAX_NONDET_TREE_DEPTH_OPT
#define COMMON_HARNESS_GENERATOR_HAVOC_MEMBER_OPT
symbolt & get_fresh_aux_symbol(const typet &type, const std::string &name_prefix, const std::string &basename_prefix, const source_locationt &source_location, const irep_idt &symbol_mode, const namespacet &ns, symbol_table_baset &symbol_table)
Installs a fresh-named symbol with respect to the given namespace ns with the requested name pattern ...
Fresh auxiliary symbol creation.
const std::string & id2string(const irep_idt &d)
Definition: irep.h:44
static int8_t r
Definition: irep_hash.h:60
Mangle names of file-local functions to make them unique.
#define FILE_LOCAL_PREFIX
Definition: name_mangler.h:16
std::string require_exactly_one_value(const std::string &option, const std::list< std::string > &values)
Returns the only value of a single element list, throws an exception if not passed a single element l...
std::size_t require_one_size_value(const std::string &option, const std::list< std::string > &values)
Returns the only Nat value of a single element list, throws an exception if not passed a single eleme...
auto optional_lookup(const map_like_collectiont &map, const keyt &key) -> std::optional< decltype(map.find(key) ->second)>
Lookup a key in a map, if found return the associated value, nullopt otherwise.
API to expression classes for Pointers.
bool can_cast_type< pointer_typet >(const typet &type)
Check whether a reference to a typet is a pointer_typet.
Definition: pointer_expr.h:80
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
std::optional< exprt > size_of_expr(const typet &type, const namespacet &ns)
Pointer Logic.
code_blockt build_null_pointer(const symbol_exprt &result_symbol)
static symbolt & get_fresh_global_symbol(symbol_tablet &symbol_table, const std::string &symbol_base_name, typet symbol_type, irep_idt mode)
#define GOTO_HARNESS_PREFIX
irep_idt get_new_name(const irep_idt &name, const namespacet &ns, char delimiter)
Build and identifier not yet present in the namespace ns based on name.
Definition: rename.cpp:16
#define CHECK_RETURN(CONDITION)
Definition: invariant.h:495
#define PRECONDITION(CONDITION)
Definition: invariant.h:463
exprt conjunction(const exprt::operandst &op)
1) generates a conjunction for two or more operands 2) for one operand, returns the operand 3) return...
Definition: std_expr.cpp:83
exprt disjunction(const exprt::operandst &op)
1) generates a disjunction for two or more operands 2) for one operand, returns the operand 3) return...
Definition: std_expr.cpp:71
auto component(T &struct_expr, const irep_idt &name, const namespacet &ns) -> decltype(struct_expr.op0())
Definition: std_expr.cpp:97
const constant_exprt & to_constant_expr(const exprt &expr)
Cast an exprt to a constant_exprt.
Definition: std_expr.h:3055
const symbol_exprt & to_symbol_expr(const exprt &expr)
Cast an exprt to a symbol_exprt.
Definition: std_expr.h:272
const struct_typet & to_struct_type(const typet &type)
Cast a typet to a struct_typet.
Definition: std_types.h:308
const code_typet & to_code_type(const typet &type)
Cast a typet to a code_typet.
Definition: std_types.h:788
bool can_cast_type< struct_tag_typet >(const typet &type)
Check whether a reference to a typet is a struct_tag_typet.
Definition: std_types.h:505
const array_typet & to_array_type(const typet &type)
Cast a typet to an array_typet.
Definition: std_types.h:888
bool can_cast_type< code_typet >(const typet &type)
Check whether a reference to a typet is a code_typet.
Definition: std_types.h:775
const struct_tag_typet & to_struct_tag_type(const typet &type)
Cast a typet to a struct_tag_typet.
Definition: std_types.h:518
void replace(const union_find_replacet &replace_map, string_not_contains_constraintt &constraint)
std::string to_string(const string_not_contains_constraintt &expr)
Used for debug printing.
void split_string(const std::string &s, char delim, std::vector< std::string > &result, bool strip, bool remove_empty)
std::set< irep_idt > pointers_to_treat_as_cstrings
std::vector< std::set< irep_idt > > pointers_to_treat_equal
std::map< irep_idt, irep_idt > array_name_to_associated_array_size_variable
bool handle_option(const std::string &option, const std::list< std::string > &values)
Parse the options specific for recursive initialisation.
std::vector< std::vector< irep_idt > > selection_specs
std::set< irep_idt > variables_that_hold_array_sizes
std::set< irep_idt > pointers_to_treat_as_arrays
std::unordered_set< irep_idt > potential_null_function_pointers
typet remove_const(typet type)
Remove const qualifier from type (if any).
Definition: type.cpp:32
#define size_type
Definition: unistd.c:347