CBMC
java_static_initializers.cpp
Go to the documentation of this file.
1 /*******************************************************************\
2 
3 Module: Java Static Initializers
4 
5 Author: Chris Smowton, chris.smowton@diffblue.com
6 
7 \*******************************************************************/
8 
10 
11 #include <util/arith_tools.h>
12 #include <util/cprover_prefix.h>
13 #include <util/json.h>
14 #include <util/std_code.h>
15 #include <util/suffix.h>
16 #include <util/symbol_table_base.h>
17 
20 
21 #include "assignments_from_json.h"
22 #include "ci_lazy_methods_needed.h" // IWYU pragma: keep
23 #include "java_object_factory.h"
25 #include "java_types.h"
26 #include "java_utils.h"
27 
49 enum class clinit_statest
50 {
51  NOT_INIT,
54 };
55 
57 {
58  return java_byte_type();
59 }
60 
61 // Disable linter here to allow a std::string constant, since that holds
62 // a length, whereas a cstr would require strlen every time.
63 const std::string clinit_wrapper_suffix = ".<clinit_wrapper>"; // NOLINT(*)
64 const std::string user_specified_clinit_suffix = ".<user_specified_clinit>"; // NOLINT(*)
65 const std::string clinit_function_suffix = ".<clinit>:()V"; // NOLINT(*)
66 
74 {
75  return id2string(class_name) + clinit_wrapper_suffix;
76 }
77 
79 {
80  return id2string(class_name) + user_specified_clinit_suffix;
81 }
82 
86 bool is_clinit_wrapper_function(const irep_idt &function_id)
87 {
88  return has_suffix(id2string(function_id), clinit_wrapper_suffix);
89 }
90 
94 bool is_clinit_function(const irep_idt &function_id)
95 {
96  return has_suffix(id2string(function_id), clinit_function_suffix);
97 }
98 
103 {
104  return has_suffix(id2string(function_id), user_specified_clinit_suffix);
105 }
106 
116  symbol_table_baset &symbol_table,
117  const irep_idt &name,
118  const typet &type,
119  const exprt &value,
120  const bool is_thread_local,
121  const bool is_static_lifetime)
122 {
123  symbolt new_symbol{name, type, ID_java};
124  new_symbol.pretty_name = name;
125  new_symbol.base_name = name;
126  new_symbol.type.set(ID_C_no_nondet_initialization, true);
127  new_symbol.value = value;
128  new_symbol.is_lvalue = true;
129  new_symbol.is_state_var = true;
130  new_symbol.is_static_lifetime = is_static_lifetime;
131  new_symbol.is_thread_local = is_thread_local;
132  symbol_table.add(new_symbol);
133  return new_symbol;
134 }
135 
141 {
142  return id2string(class_name) + "::clinit_already_run";
143 }
144 
149 static irep_idt clinit_function_name(const irep_idt &class_name)
150 {
151  return id2string(class_name) + clinit_function_suffix;
152 }
153 
158 static irep_idt clinit_state_var_name(const irep_idt &class_name)
159 {
160  return id2string(class_name) + CPROVER_PREFIX "clinit_state";
161 }
162 
168 {
169  return id2string(class_name) + CPROVER_PREFIX "clinit_threadlocal_state";
170 }
171 
176 {
177  return id2string(class_name) + CPROVER_PREFIX "clinit_wrapper::init_complete";
178 }
179 
189 gen_clinit_assign(const exprt &expr, const clinit_statest state)
190 {
191  mp_integer initv(static_cast<int>(state));
193  return code_frontend_assignt(expr, init_s);
194 }
195 
204 static equal_exprt
205 gen_clinit_eqexpr(const exprt &expr, const clinit_statest state)
206 {
207  mp_integer initv(static_cast<int>(state));
209  return equal_exprt(expr, init_s);
210 }
211 
230  symbol_table_baset &symbol_table,
231  const irep_idt &class_name,
232  code_blockt &init_body,
233  const bool nondet_static,
234  const bool replace_clinit,
235  const java_object_factory_parameterst &object_factory_parameters,
236  const select_pointer_typet &pointer_type_selector,
237  message_handlert &message_handler)
238 {
239  const symbolt &class_symbol = symbol_table.lookup_ref(class_name);
240  for(const auto &base : to_class_type(class_symbol.type).bases())
241  {
242  const auto base_name = base.type().get_identifier();
243  irep_idt base_init_routine = clinit_wrapper_name(base_name);
244  if(const auto base_init_func = symbol_table.lookup(base_init_routine))
245  init_body.add(code_function_callt{base_init_func->symbol_expr()});
246  }
247 
248  const irep_idt &clinit_name = replace_clinit
249  ? user_specified_clinit_name(class_name)
250  : clinit_function_name(class_name);
251  if(const auto clinit_func = symbol_table.lookup(clinit_name))
252  init_body.add(code_function_callt{clinit_func->symbol_expr()});
253 
254  // If nondet-static option is given, add a standard nondet initialization for
255  // each non-final static field of this class. Note this is the same invocation
256  // used in get_stub_initializer_body and java_static_lifetime_init.
257  if(nondet_static)
258  {
259  java_object_factory_parameterst parameters = object_factory_parameters;
260  parameters.function_id = clinit_wrapper_name(class_name);
261 
262  std::vector<irep_idt> nondet_ids;
263  std::for_each(
264  symbol_table.symbols.begin(),
265  symbol_table.symbols.end(),
266  [&](const std::pair<irep_idt, symbolt> &symbol) {
267  if(
268  declaring_class(symbol.second) == class_name &&
269  symbol.second.is_static_lifetime &&
270  !symbol.second.type.get_bool(ID_C_constant))
271  {
272  nondet_ids.push_back(symbol.first);
273  }
274  });
275 
276  for(const auto &id : nondet_ids)
277  {
278  const symbol_exprt new_global_symbol =
279  symbol_table.lookup_ref(id).symbol_expr();
280 
281  parameters.min_null_tree_depth =
283  ? std::max(size_t(1), object_factory_parameters.min_null_tree_depth)
284  : object_factory_parameters.min_null_tree_depth;
285 
287  new_global_symbol,
288  init_body,
289  symbol_table,
291  false,
293  parameters,
294  pointer_type_selector,
296  message_handler);
297  }
298  }
299 }
300 
307  const irep_idt &class_name,
308  const symbol_table_baset &symbol_table)
309 {
310  if(symbol_table.has_symbol(clinit_function_name(class_name)))
311  return true;
312 
313  const class_typet &class_type =
314  to_class_type(symbol_table.lookup_ref(class_name).type);
315 
316  for(const class_typet::baset &base : class_type.bases())
317  {
318  if(symbol_table.has_symbol(
319  clinit_wrapper_name(base.type().get_identifier())))
320  {
321  return true;
322  }
323  }
324 
325  return false;
326 }
327 
329  const irep_idt &class_name,
330  const irep_idt &function_name,
331  const irep_idt &function_base_name,
332  const synthetic_method_typet &synthetic_method_type,
333  symbol_table_baset &symbol_table,
334  synthetic_methods_mapt &synthetic_methods)
335 {
336  symbolt function_symbol{
337  function_name, java_method_typet({}, java_void_type()), ID_java};
338  function_symbol.name = function_name;
339  function_symbol.pretty_name = function_symbol.name;
340  function_symbol.base_name = function_base_name;
341  // This provides a back-link from a method to its associated class, as is done
342  // for java_bytecode_convert_methodt::convert.
343  set_declaring_class(function_symbol, class_name);
344  bool failed = symbol_table.add(function_symbol);
345  INVARIANT(!failed, id2string(function_base_name) + " symbol should be fresh");
346 
347  auto insert_result =
348  synthetic_methods.emplace(function_symbol.name, synthetic_method_type);
349  INVARIANT(
350  insert_result.second,
351  "synthetic methods map should not already contain entry for " +
352  id2string(function_base_name));
353 }
354 
355 // Create symbol for the "clinit_wrapper"
357  const irep_idt &class_name,
358  symbol_table_baset &symbol_table,
359  synthetic_methods_mapt &synthetic_methods)
360 {
362  class_name,
363  clinit_wrapper_name(class_name),
364  "clinit_wrapper",
366  symbol_table,
367  synthetic_methods);
368 }
369 
370 // Create symbol for the "user_specified_clinit"
372  const irep_idt &class_name,
373  symbol_table_baset &symbol_table,
374  synthetic_methods_mapt &synthetic_methods)
375 {
377  class_name,
378  user_specified_clinit_name(class_name),
379  "user_specified_clinit",
381  symbol_table,
382  synthetic_methods);
383 }
384 
396  const irep_idt &class_name,
397  symbol_table_baset &symbol_table,
398  synthetic_methods_mapt &synthetic_methods,
399  const bool thread_safe)
400 {
401  if(thread_safe)
402  {
403  exprt not_init_value = from_integer(
404  static_cast<int>(clinit_statest::NOT_INIT), clinit_states_type());
405 
406  // Create two global static synthetic "fields" for the class "id"
407  // these two variables hold the state of the class initialization algorithm
408  // across calls to the clinit_wrapper
410  symbol_table,
411  clinit_state_var_name(class_name),
413  not_init_value,
414  false,
415  true);
416 
418  symbol_table,
421  not_init_value,
422  true,
423  true);
424  }
425  else
426  {
427  const irep_idt &already_run_name =
429 
431  symbol_table,
432  already_run_name,
433  bool_typet(),
434  false_exprt(),
435  false,
436  true);
437  }
438 
440  class_name, symbol_table, synthetic_methods);
441 }
442 
521  const irep_idt &function_id,
522  symbol_table_baset &symbol_table,
523  const bool nondet_static,
524  const bool replace_clinit,
525  const java_object_factory_parameterst &object_factory_parameters,
526  const select_pointer_typet &pointer_type_selector,
527  message_handlert &message_handler)
528 {
529  const symbolt &wrapper_method_symbol = symbol_table.lookup_ref(function_id);
530  const auto class_name = declaring_class(wrapper_method_symbol);
531  INVARIANT(class_name, "Wrapper function should have an owning class.");
532 
533  const symbolt &clinit_state_sym =
534  symbol_table.lookup_ref(clinit_state_var_name(*class_name));
535  const symbolt &clinit_thread_local_state_sym =
536  symbol_table.lookup_ref(clinit_thread_local_state_var_name(*class_name));
537 
538  // Create a function-local variable "init_complete". This variable is used to
539  // avoid inspecting the global state (clinit_state_sym) outside of
540  // the critical-section.
541  const symbolt &init_complete = add_new_variable_symbol(
542  symbol_table,
544  bool_typet(),
545  nil_exprt(),
546  true,
547  false);
548 
549  code_blockt function_body;
550  codet atomic_begin(ID_atomic_begin);
551  codet atomic_end(ID_atomic_end);
552 
553 #if 0
554  // This code defines source locations for every codet generated below for
555  // the static initializer wrapper. Enable this for debugging the symex going
556  // through the clinit_wrapper.
557  //
558  // java::C.<clinit_wrapper>()
559  // You will additionally need to associate the `location` with the
560  // `function_body` and then manually set lines of code for each of the
561  // statements of the function, using something along the lines of:
562  // `mycodet.then_case().add_source_location().set_line(17);`/
563 
564  source_locationt &location = function_body.add_source_location();
565  location.set_file ("<generated>");
566  location.set_line ("<generated>");
568  std::string comment =
569  "Automatically generated function. States are:\n"
570  " 0 = class not initialized, init val of clinit_state/clinit_local_state\n"
571  " 1 = class initialization in progress, by this or another thread\n"
572  " 2 = initialization finished with success, by this or another thread\n";
573  static_assert((int) clinit_statest::NOT_INIT==0, "Check commment above");
574  static_assert((int) clinit_statest::IN_PROGRESS==1, "Check comment above");
575  static_assert((int) clinit_statest::INIT_COMPLETE==2, "Check comment above");
576 #endif
577 
578  // bool init_complete;
579  {
580  code_frontend_declt decl(init_complete.symbol_expr());
581  function_body.add(decl);
582  }
583 
584  // if(C::__CPROVER_PREFIX_clinit_thread_local_state == INIT_COMPLETE) return;
585  {
586  code_ifthenelset conditional(
588  clinit_thread_local_state_sym.symbol_expr(),
591  function_body.add(std::move(conditional));
592  }
593 
594  // C::__CPROVER_PREFIX_clinit_thread_local_state = INIT_COMPLETE;
595  {
597  clinit_thread_local_state_sym.symbol_expr(),
599  function_body.add(assign);
600  }
601 
602  // ATOMIC_BEGIN
603  {
604  function_body.add(atomic_begin);
605  }
606 
607  // Assume: clinit_state_sym != IN_PROGRESS
608  {
609  exprt assumption = gen_clinit_eqexpr(
610  clinit_state_sym.symbol_expr(), clinit_statest::IN_PROGRESS);
611  assumption = not_exprt(assumption);
612  code_assumet assume(assumption);
613  function_body.add(assume);
614  }
615 
616  // If(C::__CPROVER_PREFIX_clinit_state == NOT_INIT)
617  // {
618  // C::__CPROVER_PREFIX_clinit_state = IN_PROGRESS;
619  // init_complete = false;
620  // }
621  // else If(C::__CPROVER_PREFIX_clinit_state == INIT_COMPLETE)
622  // {
623  // init_complete = true;
624  // }
625  {
626  code_ifthenelset init_conditional(
628  clinit_state_sym.symbol_expr(), clinit_statest::INIT_COMPLETE),
629  code_blockt(
630  {code_frontend_assignt(init_complete.symbol_expr(), true_exprt())}));
631 
632  code_ifthenelset not_init_conditional(
634  clinit_state_sym.symbol_expr(), clinit_statest::NOT_INIT),
635  code_blockt(
637  clinit_state_sym.symbol_expr(), clinit_statest::IN_PROGRESS),
638  code_frontend_assignt(init_complete.symbol_expr(), false_exprt())}),
639  std::move(init_conditional));
640 
641  function_body.add(std::move(not_init_conditional));
642  }
643 
644  // ATOMIC_END
645  {
646  function_body.add(atomic_end);
647  }
648 
649  // if(init_complete) return;
650  {
651  code_ifthenelset conditional(
652  init_complete.symbol_expr(), code_frontend_returnt());
653  function_body.add(std::move(conditional));
654  }
655 
656  // Initialize the super-class C' and
657  // the implemented interfaces l_1 ... l_n.
658  // see JVMS p.359 step 7, for the exact definition of
659  // the sequence l_1 to l_n.
660  // This is achieved by iterating through the base types and
661  // adding recursive calls to the clinit_wrapper()
662  //
663  // java::C'.<clinit_wrapper>();
664  // java::I1.<clinit_wrapper>();
665  // java::I2.<clinit_wrapper>();
666  // // ...
667  // java::In.<clinit_wrapper>();
668  //
669  // java::C.<clinit>(); // or nondet-initialization of all static
670  // // variables of C if nondet-static is true
671  //
672  {
673  code_blockt init_body;
675  symbol_table,
676  *class_name,
677  init_body,
679  replace_clinit,
680  object_factory_parameters,
681  pointer_type_selector,
682  message_handler);
683  function_body.append(init_body);
684  }
685 
686  // ATOMIC_START
687  // C::__CPROVER_PREFIX_clinit_state = INIT_COMPLETE;
688  // ATOMIC_END
689  // return;
690  {
691  // synchronization prologue
692  function_body.add(atomic_begin);
693  function_body.add(
695  clinit_state_sym.symbol_expr(), clinit_statest::INIT_COMPLETE));
696  function_body.add(atomic_end);
697  function_body.add(code_frontend_returnt());
698  }
699 
700  return function_body;
701 }
702 
719  const irep_idt &function_id,
720  symbol_table_baset &symbol_table,
721  const bool nondet_static,
722  const bool replace_clinit,
723  const java_object_factory_parameterst &object_factory_parameters,
724  const select_pointer_typet &pointer_type_selector,
725  message_handlert &message_handler)
726 {
727  // Assume that class C extends class C' and implements interfaces
728  // I1, ..., In. We now create the following function (possibly recursively
729  // creating the clinit_wrapper functions for C' and I1, ..., In):
730  //
731  // java::C.<clinit_wrapper>()
732  // {
733  // if (!java::C::clinit_already_run)
734  // {
735  // java::C::clinit_already_run = true; // before recursive calls!
736  //
737  // java::C'.<clinit_wrapper>();
738  // java::I1.<clinit_wrapper>();
739  // java::I2.<clinit_wrapper>();
740  // // ...
741  // java::In.<clinit_wrapper>();
742  //
743  // java::C.<clinit>(); // or nondet-initialization of all static
744  // // variables of C if nondet-static is true
745  // }
746  // }
747  const symbolt &wrapper_method_symbol = symbol_table.lookup_ref(function_id);
748  const auto class_name = declaring_class(wrapper_method_symbol);
749  INVARIANT(class_name, "Wrapper function should have an owning class.");
750 
751  const symbolt &already_run_symbol =
752  symbol_table.lookup_ref(clinit_already_run_variable_name(*class_name));
753 
754  equal_exprt check_already_run(
755  already_run_symbol.symbol_expr(),
756  false_exprt());
757 
758  // add the "already-run = false" statement
759  code_frontend_assignt set_already_run(
760  already_run_symbol.symbol_expr(), true_exprt());
761  code_blockt init_body({set_already_run});
762 
764  symbol_table,
765  *class_name,
766  init_body,
768  replace_clinit,
769  object_factory_parameters,
770  pointer_type_selector,
771  message_handler);
772 
773  // the entire body of the function is an if-then-else
774  return code_ifthenelset(std::move(check_already_run), std::move(init_body));
775 }
776 
778 std::unordered_multimap<irep_idt, symbolt>
780 {
781  std::unordered_multimap<irep_idt, symbolt> result;
782  for(const auto &symbol_pair : symbol_table)
783  {
784  const symbolt &symbol = symbol_pair.second;
785  if(std::optional<irep_idt> declaring = declaring_class(symbol))
786  result.emplace(*declaring, symbol);
787  }
788  return result;
789 }
790 
792  const irep_idt &class_id,
793  const json_objectt &static_values_json,
794  symbol_table_baset &symbol_table,
795  std::optional<ci_lazy_methods_neededt> needed_lazy_methods,
796  size_t max_user_array_length,
797  std::unordered_map<std::string, object_creation_referencet> &references,
798  const std::unordered_multimap<irep_idt, symbolt>
799  &class_to_declared_symbols_map)
800 {
801  const irep_idt &real_clinit_name = clinit_function_name(class_id);
802  const auto clinit_func = symbol_table.lookup(real_clinit_name);
803  if(clinit_func == nullptr)
804  {
805  // Case where the real clinit doesn't appear in the symbol table, even
806  // though their is user specifed one. This may occur when some class
807  // substitution happened after compilation.
808  return code_blockt{};
809  }
810  const auto class_entry =
811  static_values_json.find(id2string(strip_java_namespace_prefix(class_id)));
812  if(class_entry != static_values_json.end() && class_entry->second.is_object())
813  {
814  const auto &class_json_object = to_json_object(class_entry->second);
815  std::map<symbol_exprt, jsont> static_field_values;
816  for(const auto &symbol_pair :
817  equal_range(class_to_declared_symbols_map, class_id))
818  {
819  const symbolt &symbol = symbol_pair.second;
820  if(symbol.is_static_lifetime)
821  {
822  const symbol_exprt &static_field_expr = symbol.symbol_expr();
823  const auto &static_field_entry =
824  class_json_object.find(id2string(symbol.base_name));
825  if(static_field_entry != class_json_object.end())
826  {
827  static_field_values.insert(
828  {static_field_expr, static_field_entry->second});
829  }
830  }
831  }
832  code_with_references_listt code_with_references;
833  for(const auto &value_pair : static_field_values)
834  {
835  code_with_references.append(assign_from_json(
836  value_pair.first,
837  value_pair.second,
838  real_clinit_name,
839  symbol_table,
840  needed_lazy_methods,
841  max_user_array_length,
842  references));
843  }
844  code_with_referencest::reference_substitutiont reference_substitution =
845  [&](const std::string &reference_id) -> object_creation_referencet & {
846  auto it = references.find(reference_id);
847  INVARIANT(it != references.end(), "reference id must be present in map");
848  return it->second;
849  };
850  code_blockt body;
851  for(const auto &code_with_ref : code_with_references.list)
852  body.append(code_with_ref->to_code(reference_substitution));
853  return body;
854  }
855  return code_blockt{{code_function_callt{clinit_func->symbol_expr()}}};
856 }
857 
875  symbol_table_baset &symbol_table,
876  synthetic_methods_mapt &synthetic_methods,
877  const bool thread_safe,
878  const bool is_user_clinit_needed)
879 {
880  // Top-sort the class hierarchy, such that we visit parents before children,
881  // and can so identify parents that need static initialisation by whether we
882  // have made them a clinit_wrapper method.
883  class_hierarchy_grapht class_graph;
884  class_graph.populate(symbol_table);
885  std::list<class_hierarchy_grapht::node_indext> topsorted_nodes =
886  class_graph.topsort();
887 
888  for(const auto node : topsorted_nodes)
889  {
890  const irep_idt &class_identifier = class_graph[node].class_identifier;
891  if(needs_clinit_wrapper(class_identifier, symbol_table))
892  {
894  class_identifier, symbol_table, synthetic_methods, thread_safe);
895  if(is_user_clinit_needed)
896  {
898  class_identifier, symbol_table, synthetic_methods);
899  }
900  }
901  }
902 }
903 
907 template<class itertype>
908 static itertype advance_to_next_key(itertype in, itertype end)
909 {
910  PRECONDITION(in != end);
911  auto initial_key = in->first;
912  while(in != end && in->first == initial_key)
913  ++in;
914  return in;
915 }
916 
926  symbol_table_baset &symbol_table,
927  const std::unordered_set<irep_idt> &stub_globals_set,
928  synthetic_methods_mapt &synthetic_methods)
929 {
930  // Populate map from class id -> stub globals:
931  for(const irep_idt &stub_global : stub_globals_set)
932  {
933  const symbolt &global_symbol = symbol_table.lookup_ref(stub_global);
934  if(global_symbol.value.is_nil())
935  {
936  // This symbol is already nondet-initialised during __CPROVER_initialize
937  // (generated in java_static_lifetime_init). In future this will only
938  // be the case for primitive-typed fields, but for now reference-typed
939  // fields can also be treated this way in the exceptional case that they
940  // belong to a non-stub class. Skip the field, as it does not need a
941  // synthetic static initializer.
942  continue;
943  }
944 
945  const auto class_id = declaring_class(global_symbol);
946  INVARIANT(class_id, "Static field should have a defining class.");
947  stub_globals_by_class.insert({*class_id, stub_global});
948  }
949 
950  // For each distinct class that has stub globals, create a clinit symbol:
951 
952  for(auto it = stub_globals_by_class.begin(),
953  itend = stub_globals_by_class.end();
954  it != itend;
955  it = advance_to_next_key(it, itend))
956  {
957  const irep_idt static_init_name = clinit_function_name(it->first);
958 
959  INVARIANT(
960  to_java_class_type(symbol_table.lookup_ref(it->first).type).get_is_stub(),
961  "only stub classes should be given synthetic static initialisers");
962  INVARIANT(
963  !symbol_table.has_symbol(static_init_name),
964  "a class cannot be both incomplete, and so have stub static fields, and "
965  "also define a static initializer");
966 
967  symbolt static_init_symbol{
968  static_init_name, java_method_typet({}, java_void_type()), ID_java};
969  static_init_symbol.pretty_name = static_init_name;
970  static_init_symbol.base_name = "clinit():V";
971  // This provides a back-link from a method to its associated class, as is
972  // done for java_bytecode_convert_methodt::convert.
973  set_declaring_class(static_init_symbol, it->first);
974 
975  bool failed = symbol_table.add(static_init_symbol);
976  INVARIANT(!failed, "symbol should not already exist");
977 
978  auto insert_result = synthetic_methods.emplace(
979  static_init_symbol.name,
981  INVARIANT(
982  insert_result.second,
983  "synthetic methods map should not already contain entry for "
984  "stub static initializer");
985  }
986 }
987 
1003  const irep_idt &function_id,
1004  symbol_table_baset &symbol_table,
1005  const java_object_factory_parameterst &object_factory_parameters,
1006  const select_pointer_typet &pointer_type_selector,
1007  message_handlert &message_handler)
1008 {
1009  const symbolt &stub_initializer_symbol = symbol_table.lookup_ref(function_id);
1010  const auto class_id = declaring_class(stub_initializer_symbol);
1011  INVARIANT(
1012  class_id, "Synthetic static initializer should have an owning class.");
1013  code_blockt static_init_body;
1014 
1015  // Add a standard nondet initialisation for each global declared on this
1016  // class. Note this is the same invocation used in
1017  // java_static_lifetime_init.
1018 
1019  auto class_globals = equal_range(stub_globals_by_class, *class_id);
1020  INVARIANT(
1021  !class_globals.empty(),
1022  "class with synthetic clinit should have at least one global to init");
1023 
1024  java_object_factory_parameterst parameters = object_factory_parameters;
1025  parameters.function_id = function_id;
1026 
1027  for(const auto &pair : class_globals)
1028  {
1029  const symbol_exprt new_global_symbol =
1030  symbol_table.lookup_ref(pair.second).symbol_expr();
1031 
1032  parameters.min_null_tree_depth =
1033  is_non_null_library_global(pair.second)
1034  ? object_factory_parameters.min_null_tree_depth + 1
1035  : object_factory_parameters.min_null_tree_depth;
1036 
1037  source_locationt location;
1038  location.set_function(function_id);
1040  new_global_symbol,
1041  static_init_body,
1042  symbol_table,
1043  location,
1044  false,
1046  parameters,
1047  pointer_type_selector,
1049  message_handler);
1050  }
1051 
1052  return static_init_body;
1053 }
@ DYNAMIC
Allocate dynamic objects (using ALLOCATE)
constant_exprt from_integer(const mp_integer &int_value, const typet &type)
code_with_references_listt assign_from_json(const exprt &expr, const jsont &json, const irep_idt &function_id, symbol_table_baset &symbol_table, std::optional< ci_lazy_methods_neededt > &needed_lazy_methods, size_t max_user_array_length, std::unordered_map< std::string, object_creation_referencet > &references)
Given an expression expr representing a Java object or primitive and a JSON representation json of th...
Context-insensitive lazy methods container.
Class Hierarchy.
The Boolean type.
Definition: std_types.h:36
Class hierarchy, represented using grapht and therefore suitable for use with generic graph algorithm...
void populate(const symbol_table_baset &)
Populate the class hierarchy graph, such that there is a node for every struct type in the symbol tab...
Class type.
Definition: std_types.h:325
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 append(const code_blockt &extra_block)
Add all the codets from extra_block to the current code_blockt.
Definition: std_code.cpp:86
void add(const codet &code)
Definition: std_code.h:168
A codet representing an assignment in the program.
Definition: std_code.h:24
A codet representing the declaration of a local variable.
Definition: std_code.h:347
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
Wrapper around a list of shared pointer to code_with_referencest objects, which provides a nicer inte...
std::list< std::shared_ptr< code_with_referencest > > list
void append(code_with_references_listt &&other)
std::function< const object_creation_referencet &(const std::string &)> reference_substitutiont
Data structure for representing an arbitrary statement in a program.
Definition: std_code_base.h:29
A constant literal expression.
Definition: std_expr.h:2987
dstringt has one field, an unsigned integer no which is an index into a static table of strings.
Definition: dstring.h:38
Equality.
Definition: std_expr.h:1361
Base class for all expressions.
Definition: expr.h:56
source_locationt & add_source_location()
Definition: expr.h:236
The Boolean constant false.
Definition: std_expr.h:3064
std::list< node_indext > topsort() const
Find a topological order of the nodes if graph is DAG, return empty list for non-DAG or empty graph.
Definition: graph.h:879
const irept & find(const irep_idt &name) const
Definition: irep.cpp:93
bool is_nil() const
Definition: irep.h:364
bool get_is_stub() const
Definition: java_types.h:397
iterator find(const std::string &key)
Definition: json.h:354
iterator end()
Definition: json.h:384
The NIL expression.
Definition: std_expr.h:3073
Boolean negation.
Definition: std_expr.h:2327
void set_file(const irep_idt &file)
void set_line(const irep_idt &line)
void set_function(const irep_idt &function)
Base class or struct that a class or struct inherits from.
Definition: std_types.h:252
const basest & bases() const
Get the collection of base classes/structs.
Definition: std_types.h:262
void create_stub_global_initializer_symbols(symbol_table_baset &symbol_table, const std::unordered_set< irep_idt > &stub_globals_set, synthetic_methods_mapt &synthetic_methods)
Create static initializer symbols for each distinct class that has stub globals.
code_blockt get_stub_initializer_body(const irep_idt &function_id, symbol_table_baset &symbol_table, const java_object_factory_parameterst &object_factory_parameters, const select_pointer_typet &pointer_type_selector, message_handlert &message_handler)
Create the body of a synthetic static initializer (clinit method), which initialise stub globals in t...
stub_globals_by_classt stub_globals_by_class
Expression to hold a symbol (variable)
Definition: std_expr.h:131
The symbol table base class interface.
const symbolt * lookup(const irep_idt &name) const
Find a symbol in the symbol table for read-only access.
const symbolst & symbols
Read-only field, used to look up symbols given their names.
const symbolt & lookup_ref(const irep_idt &name) const
Find a symbol in the symbol table for read-only access.
bool has_symbol(const irep_idt &name) const
Check whether a symbol exists in the symbol table.
bool add(const symbolt &symbol)
Add a new symbol to the symbol table.
Symbol table entry.
Definition: symbol.h:28
irep_idt base_name
Base (non-scoped) name.
Definition: symbol.h:46
bool is_static_lifetime
Definition: symbol.h:70
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
exprt value
Initial value of symbol.
Definition: symbol.h:34
The Boolean constant true.
Definition: std_expr.h:3055
The type of an expression, extends irept.
Definition: type.h:29
#define CPROVER_PREFIX
const std::string & id2string(const irep_idt &d)
Definition: irep.h:40
void gen_nondet_init(const exprt &expr, code_blockt &init_code, symbol_table_baset &symbol_table, const source_locationt &loc, bool skip_classid, lifetimet lifetime, const java_object_factory_parameterst &object_factory_parameters, const select_pointer_typet &pointer_type_selector, update_in_placet update_in_place, message_handlert &log)
Initializes a primitive-typed or reference-typed object tree rooted at expr, allocating child objects...
This module is responsible for the synthesis of code (in the form of a sequence of codet statements) ...
static code_frontend_assignt gen_clinit_assign(const exprt &expr, const clinit_statest state)
Generates a code_frontend_assignt for clinit_statest /param expr: expression to be used as the LHS of...
clinit_statest
The three states in which a <clinit> method for a class can be before, after, and during static class...
code_blockt get_user_specified_clinit_body(const irep_idt &class_id, const json_objectt &static_values_json, symbol_table_baset &symbol_table, std::optional< ci_lazy_methods_neededt > needed_lazy_methods, size_t max_user_array_length, std::unordered_map< std::string, object_creation_referencet > &references, const std::unordered_multimap< irep_idt, symbolt > &class_to_declared_symbols_map)
Create the body of a user_specified_clinit function for a given class, which includes assignments for...
static void create_function_symbol(const irep_idt &class_name, const irep_idt &function_name, const irep_idt &function_base_name, const synthetic_method_typet &synthetic_method_type, symbol_table_baset &symbol_table, synthetic_methods_mapt &synthetic_methods)
void create_static_initializer_symbols(symbol_table_baset &symbol_table, synthetic_methods_mapt &synthetic_methods, const bool thread_safe, const bool is_user_clinit_needed)
Create static initializer wrappers and possibly user-specified functions for initial static field val...
static typet clinit_states_type()
static irep_idt clinit_state_var_name(const irep_idt &class_name)
Get name of the static-initialization-state global variable for a given class.
const std::string clinit_function_suffix
static void create_user_specified_clinit_function_symbol(const irep_idt &class_name, symbol_table_baset &symbol_table, synthetic_methods_mapt &synthetic_methods)
code_ifthenelset get_clinit_wrapper_body(const irep_idt &function_id, symbol_table_baset &symbol_table, const bool nondet_static, const bool replace_clinit, const java_object_factory_parameterst &object_factory_parameters, const select_pointer_typet &pointer_type_selector, message_handlert &message_handler)
Produces the static initializer wrapper body for the given function.
static void create_clinit_wrapper_function_symbol(const irep_idt &class_name, symbol_table_baset &symbol_table, synthetic_methods_mapt &synthetic_methods)
static equal_exprt gen_clinit_eqexpr(const exprt &expr, const clinit_statest state)
Generates an equal_exprt for clinit_statest /param expr: expression to be used as the LHS of generate...
static void clinit_wrapper_do_recursive_calls(symbol_table_baset &symbol_table, const irep_idt &class_name, code_blockt &init_body, const bool nondet_static, const bool replace_clinit, const java_object_factory_parameterst &object_factory_parameters, const select_pointer_typet &pointer_type_selector, message_handlert &message_handler)
Generates codet that iterates through the base types of the class specified by class_name,...
static void create_clinit_wrapper_symbols(const irep_idt &class_name, symbol_table_baset &symbol_table, synthetic_methods_mapt &synthetic_methods, const bool thread_safe)
Creates a static initializer wrapper symbol for the given class, along with a global boolean that tra...
bool is_user_specified_clinit_function(const irep_idt &function_id)
Check if function_id is a user-specified clinit.
irep_idt user_specified_clinit_name(const irep_idt &class_name)
const std::string user_specified_clinit_suffix
std::unordered_multimap< irep_idt, symbolt > class_to_declared_symbols(const symbol_table_baset &symbol_table)
code_blockt get_thread_safe_clinit_wrapper_body(const irep_idt &function_id, symbol_table_baset &symbol_table, const bool nondet_static, const bool replace_clinit, const java_object_factory_parameterst &object_factory_parameters, const select_pointer_typet &pointer_type_selector, message_handlert &message_handler)
Thread safe version of the static initializer.
static irep_idt clinit_thread_local_state_var_name(const irep_idt &class_name)
Get name of the static-initialization-state local state variable for a given class.
static itertype advance_to_next_key(itertype in, itertype end)
Advance map iterator to next distinct key.
bool is_clinit_wrapper_function(const irep_idt &function_id)
Check if function_id is a clinit wrapper.
irep_idt clinit_wrapper_name(const irep_idt &class_name)
Get the Java static initializer wrapper name for a given class (the wrapper checks if static initiali...
static irep_idt clinit_function_name(const irep_idt &class_name)
Get name of the real static initializer for a given class.
static irep_idt clinit_already_run_variable_name(const irep_idt &class_name)
Get name of the static-initialization-already-done global variable for a given class.
bool is_clinit_function(const irep_idt &function_id)
Check if function_id is a clinit.
static irep_idt clinit_local_init_complete_var_name(const irep_idt &class_name)
Get name of the static-initialization local variable for a given class.
static symbolt add_new_variable_symbol(symbol_table_baset &symbol_table, const irep_idt &name, const typet &type, const exprt &value, const bool is_thread_local, const bool is_static_lifetime)
Add a new symbol to the symbol table.
const std::string clinit_wrapper_suffix
static bool needs_clinit_wrapper(const irep_idt &class_name, const symbol_table_baset &symbol_table)
Checks whether a static initializer wrapper is needed for a given class, i.e.
empty_typet java_void_type()
Definition: java_types.cpp:37
signedbv_typet java_byte_type()
Definition: java_types.cpp:55
const java_class_typet & to_java_class_type(const typet &type)
Definition: java_types.h:581
std::optional< irep_idt > declaring_class(const symbolt &symbol)
Gets the identifier of the class which declared a given symbol.
Definition: java_utils.cpp:568
bool is_non_null_library_global(const irep_idt &symbolid)
Check if a symbol is a well-known non-null global.
Definition: java_utils.cpp:519
void set_declaring_class(symbolt &symbol, const irep_idt &declaring_class)
Sets the identifier of the class which declared a given symbol to declaring_class.
Definition: java_utils.cpp:574
irep_idt strip_java_namespace_prefix(const irep_idt &to_strip)
Strip java:: prefix from given identifier.
Definition: java_utils.cpp:407
json_objectt & to_json_object(jsont &json)
Definition: json.h:442
static void nondet_static(const namespacet &ns, goto_functionst &goto_functions, const irep_idt &fct_name)
Nondeterministically initializes global scope variables in a goto-function.
static std::string comment(const rw_set_baset::entryt &entry, bool write)
Definition: race_check.cpp:108
ranget< typename multimapt::const_iterator > equal_range(const multimapt &multimap, const typename multimapt::key_type &key)
Utility function to make equal_range method of multimap easier to use by returning a ranget object.
Definition: range.h:539
BigInt mp_integer
Definition: smt_terms.h:17
#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 class_typet & to_class_type(const typet &type)
Cast a typet to a class_typet.
Definition: std_types.h:381
Information to store when several references point to the same Java object.
irep_idt function_id
Function id, used as a prefix for identifiers of temporaries.
size_t min_null_tree_depth
To force a certain depth of non-null objects.
bool has_suffix(const std::string &s, const std::string &suffix)
Definition: suffix.h:17
Author: Diffblue Ltd.
static bool failed(bool error_indicator)
std::unordered_map< irep_idt, synthetic_method_typet > synthetic_methods_mapt
Maps method names on to a synthetic method kind.
synthetic_method_typet
Synthetic method kinds.
@ USER_SPECIFIED_STATIC_INITIALIZER
Only exists if the --static-values option was used.
@ STATIC_INITIALIZER_WRAPPER
A static initializer wrapper (code of the form if(!already_run) clinit(); already_run = true;) These ...
@ STUB_CLASS_STATIC_INITIALIZER
A generated (synthetic) static initializer function for a stub type.