CBMC
java_bytecode_language.cpp
Go to the documentation of this file.
1 /*******************************************************************\
2 
3 Module:
4 
5 Author: Daniel Kroening, kroening@kroening.com
6 
7 \*******************************************************************/
8 
10 
11 #include <util/cmdline.h>
12 #include <util/config.h>
13 #include <util/expr_iterator.h>
14 #include <util/invariant.h>
16 #include <util/options.h>
17 #include <util/suffix.h>
19 
21 
22 #include <json/json_parser.h>
24 
25 #include "ci_lazy_methods.h"
27 #include "expr2java.h"
32 #include "java_bytecode_language.h"
34 #include "java_class_loader.h"
36 #include "java_entry_point.h"
39 #include "java_string_literals.h"
40 #include "java_utils.h"
41 #include "lambda_synthesis.h"
42 #include "lift_clinit_calls.h"
43 #include "load_method_by_regex.h"
44 
45 #include <fstream>
46 #include <string>
47 
51 void parse_java_language_options(const cmdlinet &cmd, optionst &options)
52 {
53  options.set_option(
54  "java-assume-inputs-non-null", cmd.isset("java-assume-inputs-non-null"));
55  options.set_option(
56  "throw-runtime-exceptions", cmd.isset("throw-runtime-exceptions"));
57  options.set_option(
58  "uncaught-exception-check", !cmd.isset("disable-uncaught-exception-check"));
59  options.set_option(
60  "throw-assertion-error", cmd.isset("throw-assertion-error"));
61  options.set_option(
62  "assert-no-exceptions-thrown", cmd.isset("assert-no-exceptions-thrown"));
63  options.set_option("java-threading", cmd.isset("java-threading"));
64 
65  if(cmd.isset("java-max-vla-length"))
66  {
67  options.set_option(
68  "java-max-vla-length", cmd.get_value("java-max-vla-length"));
69  }
70 
71  options.set_option(
72  "symex-driven-lazy-loading", cmd.isset("symex-driven-lazy-loading"));
73 
74  options.set_option(
75  "ignore-manifest-main-class", cmd.isset("ignore-manifest-main-class"));
76 
77  if(cmd.isset("context-include"))
78  options.set_option("context-include", cmd.get_values("context-include"));
79 
80  if(cmd.isset("context-exclude"))
81  options.set_option("context-exclude", cmd.get_values("context-exclude"));
82 
83  if(cmd.isset("java-load-class"))
84  options.set_option("java-load-class", cmd.get_values("java-load-class"));
85 
86  if(cmd.isset("java-no-load-class"))
87  {
88  options.set_option(
89  "java-no-load-class", cmd.get_values("java-no-load-class"));
90  }
91  if(cmd.isset("lazy-methods-extra-entry-point"))
92  {
93  options.set_option(
94  "lazy-methods-extra-entry-point",
95  cmd.get_values("lazy-methods-extra-entry-point"));
96  }
97  if(cmd.isset("java-cp-include-files"))
98  {
99  options.set_option(
100  "java-cp-include-files", cmd.get_value("java-cp-include-files"));
101  }
102  if(cmd.isset("static-values"))
103  {
104  options.set_option("static-values", cmd.get_value("static-values"));
105  }
106  options.set_option(
107  "java-lift-clinit-calls", cmd.isset("java-lift-clinit-calls"));
108 
109  options.set_option("lazy-methods", !cmd.isset("no-lazy-methods"));
110 }
111 
113 {
114  std::vector<std::string> context_include;
115  std::vector<std::string> context_exclude;
116  for(const auto &include : options.get_list_option("context-include"))
117  context_include.push_back("java::" + include);
118  for(const auto &exclude : options.get_list_option("context-exclude"))
119  context_exclude.push_back("java::" + exclude);
120  return prefix_filtert(std::move(context_include), std::move(context_exclude));
121 }
122 
123 std::unordered_multimap<irep_idt, symbolt> &
125 {
126  if(!initialized)
127  {
128  map = class_to_declared_symbols(symbol_table);
129  initialized = true;
130  }
131  return map;
132 }
133 
135 {
136  initialized = false;
137  map.clear();
138 }
139 
141  const optionst &options,
142  message_handlert &message_handler)
143 {
145  options.get_bool_option("java-assume-inputs-non-null");
146  string_refinement_enabled = options.get_bool_option("refine-strings");
148  options.get_bool_option("throw-runtime-exceptions");
150  options.get_bool_option("uncaught-exception-check");
151  throw_assertion_error = options.get_bool_option("throw-assertion-error");
153  options.get_bool_option("assert-no-exceptions-thrown");
154  threading_support = options.get_bool_option("java-threading");
156  options.get_unsigned_int_option("java-max-vla-length");
157 
158  if(options.get_bool_option("symex-driven-lazy-loading"))
160  else if(options.get_bool_option("lazy-methods"))
162  else
164 
166  {
167  java_load_classes.insert(
168  java_load_classes.end(),
169  exception_needed_classes.begin(),
171  }
172 
173  if(options.is_set("java-load-class"))
174  {
175  const auto &load_values = options.get_list_option("java-load-class");
176  java_load_classes.insert(
177  java_load_classes.end(), load_values.begin(), load_values.end());
178  }
179  if(options.is_set("java-no-load-class"))
180  {
181  const auto &no_load_values = options.get_list_option("java-no-load-class");
182  no_load_classes = {no_load_values.begin(), no_load_values.end()};
183  }
184  const std::list<std::string> &extra_entry_points =
185  options.get_list_option("lazy-methods-extra-entry-point");
187  extra_entry_points.begin(),
188  extra_entry_points.end(),
189  std::back_inserter(extra_methods),
191 
192  java_cp_include_files = options.get_option("java-cp-include-files");
193  if(!java_cp_include_files.empty())
194  {
195  // load file list from JSON file
196  if(java_cp_include_files[0]=='@')
197  {
198  jsont json_cp_config;
199  if(parse_json(
200  java_cp_include_files.substr(1), message_handler, json_cp_config))
201  {
202  throw "cannot read JSON input configuration for JAR loading";
203  }
204 
205  if(!json_cp_config.is_object())
206  throw "the JSON file has a wrong format";
207  jsont include_files=json_cp_config["jar"];
208  if(!include_files.is_array())
209  throw "the JSON file has a wrong format";
210 
211  // add jars from JSON config file to classpath
212  for(const jsont &file_entry : to_json_array(include_files))
213  {
215  file_entry.is_string() && has_suffix(file_entry.value, ".jar"),
216  "classpath entry must be jar filename, but '" + file_entry.value +
217  "' found");
218  config.java.classpath.push_back(file_entry.value);
219  }
220  }
221  }
222  else
224 
225  nondet_static = options.get_bool_option("nondet-static");
226  if(options.is_set("static-values"))
227  {
228  const std::string filename = options.get_option("static-values");
229  jsont tmp_json;
230  messaget log{message_handler};
231  if(parse_json(filename, message_handler, tmp_json))
232  {
233  log.warning()
234  << "Provided JSON file for static-values cannot be parsed; it"
235  << " will be ignored." << messaget::eom;
236  }
237  else
238  {
239  if(!tmp_json.is_object())
240  {
241  log.warning() << "Provided JSON file for static-values is not a JSON "
242  << "object; it will be ignored." << messaget::eom;
243  }
244  else
245  static_values_json = std::move(to_json_object(tmp_json));
246  }
247  }
248 
250  options.get_bool_option("ignore-manifest-main-class");
251 
252  if(options.is_set("context-include") || options.is_set("context-exclude"))
253  method_context = get_context(options);
254 
255  should_lift_clinit_calls = options.get_bool_option("java-lift-clinit-calls");
256 }
257 
260  const optionst &options,
261  message_handlert &message_handler)
262 {
264  language_options = java_bytecode_language_optionst{options, message_handler};
265  const auto &new_points = build_extra_entry_points(options);
266  language_options->extra_methods.insert(
267  language_options->extra_methods.end(),
268  new_points.begin(),
269  new_points.end());
270 }
271 
272 std::set<std::string> java_bytecode_languaget::extensions() const
273 {
274  return { "class", "jar" };
275 }
276 
277 void java_bytecode_languaget::modules_provided(std::set<std::string> &)
278 {
279  // modules.insert(translation_unit(parse_path));
280 }
281 
284  std::istream &,
285  const std::string &,
286  std::ostream &,
288 {
289  // there is no preprocessing!
290  return true;
291 }
292 
294  message_handlert &message_handler)
295 {
297 
298  for(const auto &p : config.java.classpath)
299  java_class_loader.add_classpath_entry(p, message_handler);
300 
302  language_options->java_cp_include_files);
304  if(language_options->string_refinement_enabled)
305  {
307 
308  auto get_string_base_classes = [this](const irep_idt &id) {
310  };
311 
312  java_class_loader.set_extra_class_refs_function(get_string_base_classes);
313  }
314 }
315 
316 static void throwMainClassLoadingError(const std::string &main_class)
317 {
318  throw system_exceptiont(
319  "Error: Could not find or load main class " + main_class);
320 }
321 
323  message_handlert &message_handler)
324 {
325  messaget log{message_handler};
326 
327  if(!main_class.empty())
328  {
329  // Try to load class
330  log.status() << "Trying to load Java main class: " << main_class
331  << messaget::eom;
332  if(!java_class_loader.can_load_class(main_class, message_handler))
333  {
334  // Try to extract class name and load class
335  const auto maybe_class_name =
337  if(!maybe_class_name)
338  {
340  return;
341  }
342  log.status() << "Trying to load Java main class: "
343  << maybe_class_name.value() << messaget::eom;
345  maybe_class_name.value(), message_handler))
346  {
348  return;
349  }
350  // Everything went well. We have a loadable main class.
351  // The entry point ('main') will be checked later.
353  main_class = maybe_class_name.value();
354  }
355  log.status() << "Found Java main class: " << main_class << messaget::eom;
356  // Now really load it.
357  const auto &parse_trees = java_class_loader(main_class, message_handler);
358  if(parse_trees.empty() || !parse_trees.front().loading_successful)
359  {
361  }
362  }
363 }
364 
368 {
369  PRECONDITION(language_options.has_value());
370  initialize_class_loader(message_handler);
372  parse_from_main_class(message_handler);
373  return false;
374 }
375 
383  std::istream &instream,
384  const std::string &path,
385  message_handlert &message_handler)
386 {
387  PRECONDITION(language_options.has_value());
388  initialize_class_loader(message_handler);
389 
390  // look at extension
391  if(has_suffix(path, ".jar"))
392  {
393  std::ifstream jar_file(path);
394  if(!jar_file.good())
395  {
396  throw system_exceptiont("Error: Unable to access jarfile " + path);
397  }
398 
399  // build an object to potentially limit which classes are loaded
400  java_class_loader_limitt class_loader_limit(
401  message_handler, language_options->java_cp_include_files);
403  {
404  // If we have an entry method, we can derive a main class.
405  if(config.main.has_value())
406  {
407  const std::string &entry_method = config.main.value();
408  const auto last_dot_position = entry_method.find_last_of('.');
409  main_class = entry_method.substr(0, last_dot_position);
410  }
411  else
412  {
413  auto manifest = java_class_loader.jar_pool(path).get_manifest();
414  std::string manifest_main_class = manifest["Main-Class"];
415 
416  // if the manifest declares a Main-Class line, we got a main class
417  if(
418  !manifest_main_class.empty() &&
419  !language_options->ignore_manifest_main_class)
420  {
421  main_class = manifest_main_class;
422  }
423  }
424  }
425  else
427 
428  // do we have one now?
429  if(main_class.empty())
430  {
431  messaget log{message_handler};
432  log.status() << "JAR file without entry point: loading class files"
433  << messaget::eom;
434  const auto classes =
435  java_class_loader.load_entire_jar(path, message_handler);
436  for(const auto &c : classes)
437  main_jar_classes.push_back(c);
438  }
439  else
440  java_class_loader.add_classpath_entry(path, message_handler);
441  }
442  else
444 
445  parse_from_main_class(message_handler);
446  return false;
447 }
448 
459  const java_bytecode_parse_treet &parse_tree,
460  symbol_table_baset &symbol_table)
461 {
462  namespacet ns(symbol_table);
463  for(const auto &method : parse_tree.parsed_class.methods)
464  {
465  for(const java_bytecode_parse_treet::instructiont &instruction :
466  method.instructions)
467  {
468  const std::string statement =
469  bytecode_info[instruction.bytecode].mnemonic;
470  if(statement == "getfield" || statement == "putfield")
471  {
472  const fieldref_exprt &fieldref =
473  expr_dynamic_cast<fieldref_exprt>(instruction.args[0]);
474  irep_idt class_symbol_id = fieldref.class_name();
475  const symbolt *class_symbol = symbol_table.lookup(class_symbol_id);
476  INVARIANT(
477  class_symbol != nullptr,
478  "all types containing fields should have been loaded");
479 
480  const java_class_typet *class_type =
481  &to_java_class_type(class_symbol->type);
482  const irep_idt &component_name = fieldref.component_name();
483  while(!class_type->has_component(component_name))
484  {
485  if(class_type->get_is_stub())
486  {
487  // Accessing a field of an incomplete (opaque) type.
488  symbolt &writable_class_symbol =
489  symbol_table.get_writeable_ref(class_symbol_id);
490  auto &components =
491  to_java_class_type(writable_class_symbol.type).components();
492  components.emplace_back(component_name, fieldref.type());
493  components.back().set_base_name(component_name);
494  components.back().set_pretty_name(component_name);
495  components.back().set_is_final(true);
496  break;
497  }
498  else
499  {
500  // Not present here: check the superclass.
501  INVARIANT(
502  !class_type->bases().empty(),
503  "class '" + id2string(class_symbol->name) +
504  "' (which was missing a field '" + id2string(component_name) +
505  "' referenced from method '" + id2string(method.name) +
506  "' of class '" + id2string(parse_tree.parsed_class.name) +
507  "') should have an opaque superclass");
508  const auto &superclass_type = class_type->bases().front().type();
509  class_symbol_id = superclass_type.get_identifier();
510  class_type = &to_java_class_type(ns.follow(superclass_type));
511  }
512  }
513  }
514  }
515  }
516 }
517 
524  const irep_idt &class_id,
525  symbol_table_baset &symbol_table)
526 {
527  struct_tag_typet java_lang_Class("java::java.lang.Class");
528  symbol_exprt symbol_expr(
530  java_lang_Class);
531  if(!symbol_table.has_symbol(symbol_expr.get_identifier()))
532  {
533  symbolt new_class_symbol{
534  symbol_expr.get_identifier(), symbol_expr.type(), ID_java};
535  INVARIANT(
536  new_class_symbol.name.starts_with("java::"),
537  "class identifier should have 'java::' prefix");
538  new_class_symbol.base_name =
539  id2string(new_class_symbol.name).substr(6);
540  new_class_symbol.is_lvalue = true;
541  new_class_symbol.is_state_var = true;
542  new_class_symbol.is_static_lifetime = true;
543  new_class_symbol.type.set(ID_C_no_nondet_initialization, true);
544  symbol_table.add(new_class_symbol);
545  }
546 
547  return symbol_expr;
548 }
549 
565  const exprt &ldc_arg0,
566  symbol_table_baset &symbol_table,
567  bool string_refinement_enabled)
568 {
569  if(ldc_arg0.id() == ID_type)
570  {
571  const irep_idt &class_id = ldc_arg0.type().get(ID_identifier);
572  return
574  get_or_create_class_literal_symbol(class_id, symbol_table));
575  }
576  else if(
577  const auto &literal =
578  expr_try_dynamic_cast<java_string_literal_exprt>(ldc_arg0))
579  {
581  *literal, symbol_table, string_refinement_enabled));
582  }
583  else
584  {
585  INVARIANT(
586  ldc_arg0.is_constant(),
587  "ldc argument should be constant, string literal or class literal");
588  return ldc_arg0;
589  }
590 }
591 
602  java_bytecode_parse_treet &parse_tree,
603  symbol_table_baset &symbol_table,
604  bool string_refinement_enabled)
605 {
606  for(auto &method : parse_tree.parsed_class.methods)
607  {
608  for(java_bytecode_parse_treet::instructiont &instruction :
609  method.instructions)
610  {
611  // ldc* instructions are Java bytecode "load constant" ops, which can
612  // retrieve a numeric constant, String literal, or Class literal.
613  const std::string statement =
614  bytecode_info[instruction.bytecode].mnemonic;
615  // clang-format off
616  if(statement == "ldc" ||
617  statement == "ldc2" ||
618  statement == "ldc_w" ||
619  statement == "ldc2_w")
620  {
621  // clang-format on
622  INVARIANT(
623  instruction.args.size() != 0,
624  "ldc instructions should have an argument");
625  instruction.args[0] =
627  instruction.args[0],
628  symbol_table,
629  string_refinement_enabled);
630  }
631  }
632  }
633 }
634 
647  symbol_table_baset &symbol_table,
648  const irep_idt &symbol_id,
649  const irep_idt &symbol_basename,
650  const typet &symbol_type,
651  const irep_idt &class_id,
652  bool force_nondet_init)
653 {
654  symbolt new_symbol{symbol_id, symbol_type, ID_java};
655  new_symbol.is_static_lifetime = true;
656  new_symbol.is_lvalue = true;
657  new_symbol.is_state_var = true;
658  new_symbol.base_name = symbol_basename;
659  set_declaring_class(new_symbol, class_id);
660  // Public access is a guess; it encourages merging like-typed static fields,
661  // whereas a more restricted visbility would encourage separating them.
662  // Neither is correct, as without the class file we can't know the truth.
663  new_symbol.type.set(ID_C_access, ID_public);
664  // We set the field as final to avoid assuming they can be overridden.
665  new_symbol.type.set(ID_C_constant, true);
666  new_symbol.pretty_name = new_symbol.name;
667  // If pointer-typed, initialise to null and a static initialiser will be
668  // created to initialise on first reference. If primitive-typed, specify
669  // nondeterministic initialisation by setting a nil value.
670  if(symbol_type.id() == ID_pointer && !force_nondet_init)
671  new_symbol.value = null_pointer_exprt(to_pointer_type(symbol_type));
672  else
673  new_symbol.value.make_nil();
674  bool add_failed = symbol_table.add(new_symbol);
675  INVARIANT(
676  !add_failed, "caller should have checked symbol not already in table");
677 }
678 
688  const irep_idt &start_class_id,
689  const symbol_table_baset &symbol_table,
690  const class_hierarchyt &class_hierarchy)
691 {
692  // Depth-first search: return the first stub ancestor, or irep_idt() if none
693  // found.
694  std::vector<irep_idt> classes_to_check;
695  classes_to_check.push_back(start_class_id);
696 
697  while(!classes_to_check.empty())
698  {
699  irep_idt to_check = classes_to_check.back();
700  classes_to_check.pop_back();
701 
702  // Exclude java.lang.Object because it can
703  if(
704  to_java_class_type(symbol_table.lookup_ref(to_check).type)
705  .get_is_stub() &&
706  to_check != "java::java.lang.Object")
707  {
708  return to_check;
709  }
710 
711  const class_hierarchyt::idst &parents =
712  class_hierarchy.class_map.at(to_check).parents;
713  classes_to_check.insert(
714  classes_to_check.end(), parents.begin(), parents.end());
715  }
716 
717  return irep_idt();
718 }
719 
730  const java_bytecode_parse_treet &parse_tree,
731  symbol_table_baset &symbol_table,
732  const class_hierarchyt &class_hierarchy,
733  messaget &log)
734 {
735  namespacet ns(symbol_table);
736  for(const auto &method : parse_tree.parsed_class.methods)
737  {
738  for(const java_bytecode_parse_treet::instructiont &instruction :
739  method.instructions)
740  {
741  const std::string statement =
742  bytecode_info[instruction.bytecode].mnemonic;
743  if(statement == "getstatic" || statement == "putstatic")
744  {
745  INVARIANT(
746  instruction.args.size() > 0,
747  "get/putstatic should have at least one argument");
748  const fieldref_exprt &field_ref =
749  expr_dynamic_cast<fieldref_exprt>(instruction.args[0]);
750  irep_idt component = field_ref.component_name();
751  irep_idt class_id = field_ref.class_name();
752 
753  // The final 'true' parameter here includes interfaces, as they can
754  // define static fields.
755  const auto referred_component =
756  get_inherited_component(class_id, component, symbol_table, true);
757  if(!referred_component)
758  {
759  // Create a new stub global on an arbitrary incomplete ancestor of the
760  // class that was referred to. This is just a guess, but we have no
761  // better information to go on.
762  irep_idt add_to_class_id =
764  class_id, symbol_table, class_hierarchy);
765 
766  // If there are no incomplete ancestors to ascribe the missing field
767  // to, we must have an incomplete model of a class or simply a
768  // version mismatch of some kind. Normally this would be an error, but
769  // our models library currently triggers this error in some cases
770  // (notably java.lang.System, which is missing System.in/out/err).
771  // Therefore for this case we ascribe the missing field to the class
772  // it was directly referenced from, and fall back to initialising the
773  // field in __CPROVER_initialize, rather than try to create or augment
774  // a clinit method for a non-stub class.
775 
776  bool no_incomplete_ancestors = add_to_class_id.empty();
777  if(no_incomplete_ancestors)
778  {
779  add_to_class_id = class_id;
780 
781  // TODO forbid this again once the models library has been checked
782  // for missing static fields.
783  log.warning() << "Stub static field " << component << " found for "
784  << "non-stub type " << class_id << ". In future this "
785  << "will be a fatal error." << messaget::eom;
786  }
787 
788  irep_idt identifier =
789  id2string(add_to_class_id) + "." + id2string(component);
790 
792  symbol_table,
793  identifier,
794  component,
795  instruction.args[0].type(),
796  add_to_class_id,
797  no_incomplete_ancestors);
798  }
799  }
800  }
801  }
802 }
803 
805  symbol_table_baset &symbol_table,
806  const std::string &,
807  message_handlert &message_handler)
808 {
809  PRECONDITION(language_options.has_value());
810  // There are various cases in the Java front-end where pre-existing symbols
811  // from a previous load are not handled. We just rule this case out for now;
812  // a user wishing to ensure a particular class is loaded should use
813  // --java-load-class (to force class-loading) or
814  // --lazy-methods-extra-entry-point (to ensure a method body is loaded)
815  // instead of creating two instances of the front-end.
816  INVARIANT(
817  symbol_table.begin() == symbol_table.end(),
818  "the Java front-end should only be used with an empty symbol table");
819 
820  java_internal_additions(symbol_table);
821  create_java_initialize(symbol_table);
822 
823  if(language_options->string_refinement_enabled)
825 
826  // Must load java.lang.Object first to avoid stubbing
827  // This ordering could alternatively be enforced by
828  // moving the code below to the class loader.
829  java_class_loadert::parse_tree_with_overridest_mapt::const_iterator it =
830  java_class_loader.get_class_with_overlays_map().find("java.lang.Object");
832  {
834  it->second,
835  symbol_table,
836  message_handler,
837  language_options->max_user_array_length,
840  language_options->no_load_classes))
841  {
842  return true;
843  }
844  }
845 
846  // first generate a new struct symbol for each class and a new function symbol
847  // for every method
848  for(const auto &class_trees : java_class_loader.get_class_with_overlays_map())
849  {
850  if(class_trees.second.front().parsed_class.name.empty())
851  continue;
852 
854  class_trees.second,
855  symbol_table,
856  message_handler,
857  language_options->max_user_array_length,
860  language_options->no_load_classes))
861  {
862  return true;
863  }
864  }
865 
866  // Register synthetic method that replaces a real definition if one is
867  // available:
868  if(symbol_table.has_symbol(get_create_array_with_type_name()))
869  {
872  }
873 
874  // Now add synthetic classes for every invokedynamic instruction found (it
875  // makes this easier that all interface types and their methods have been
876  // created above):
877  {
878  std::vector<irep_idt> methods_to_check;
879 
880  // Careful not to add to the symtab while iterating over it:
881  for(const auto &id_and_symbol : symbol_table)
882  {
883  const auto &symbol = id_and_symbol.second;
884  const auto &id = symbol.name;
885  if(can_cast_type<code_typet>(symbol.type) && method_bytecode.get(id))
886  {
887  methods_to_check.push_back(id);
888  }
889  }
890 
891  for(const auto &id : methods_to_check)
892  {
894  id,
895  method_bytecode.get(id)->get().method.instructions,
896  symbol_table,
898  message_handler);
899  }
900  }
901 
902  // Now that all classes have been created in the symbol table we can populate
903  // the class hierarchy:
904  class_hierarchy(symbol_table);
905 
906  // find and mark all implicitly generic class types
907  // this can only be done once all the class symbols have been created
908  for(const auto &c : java_class_loader.get_class_with_overlays_map())
909  {
910  if(c.second.front().parsed_class.name.empty())
911  continue;
912  try
913  {
915  c.second.front().parsed_class.name, symbol_table);
916  }
918  {
919  messaget log(message_handler);
920  log.warning() << "Not marking class " << c.first
921  << " implicitly generic due to missing outer class symbols"
922  << messaget::eom;
923  }
924  }
925 
926  // Infer fields on opaque types based on the method instructions just loaded.
927  // For example, if we don't have bytecode for field x of class A, but we can
928  // see an int-typed getfield instruction referring to it, add that field now.
929  for(auto &class_to_trees : java_class_loader.get_class_with_overlays_map())
930  {
931  for(const java_bytecode_parse_treet &parse_tree : class_to_trees.second)
932  infer_opaque_type_fields(parse_tree, symbol_table);
933  }
934 
935  // Create global variables for constants (String and Class literals) up front.
936  // This means that when running with lazy loading, we will be aware of these
937  // literal globals' existence when __CPROVER_initialize is generated in
938  // `generate_support_functions`.
939  const std::size_t before_constant_globals_size = symbol_table.symbols.size();
940  for(auto &class_to_trees : java_class_loader.get_class_with_overlays_map())
941  {
942  for(java_bytecode_parse_treet &parse_tree : class_to_trees.second)
943  {
945  parse_tree, symbol_table, language_options->string_refinement_enabled);
946  }
947  }
948 
949  messaget log(message_handler);
950  log.status() << "Java: added "
951  << (symbol_table.symbols.size() - before_constant_globals_size)
952  << " String or Class constant symbols" << messaget::eom;
953 
954  // For each reference to a stub global (that is, a global variable declared on
955  // a class we don't have bytecode for, and therefore don't know the static
956  // initialiser for), create a synthetic static initialiser (clinit method)
957  // to nondet initialise it.
958  // Note this must be done before making static initialiser wrappers below, as
959  // this makes a Classname.clinit method, then the next pass makes a wrapper
960  // that ensures it is only run once, and that static initialisation happens
961  // in class-graph topological order.
962 
963  {
964  journalling_symbol_tablet symbol_table_journal =
965  journalling_symbol_tablet::wrap(symbol_table);
966  for(auto &class_to_trees : java_class_loader.get_class_with_overlays_map())
967  {
968  for(const java_bytecode_parse_treet &parse_tree : class_to_trees.second)
969  {
971  parse_tree, symbol_table_journal, class_hierarchy, log);
972  }
973  }
974 
976  symbol_table, symbol_table_journal.get_inserted(), synthetic_methods);
977  }
978 
980  symbol_table,
982  language_options->threading_support,
983  language_options->static_values_json.has_value());
984 
986 
987  // Now incrementally elaborate methods
988  // that are reachable from this entry point.
989  switch(language_options->lazy_methods_mode)
990  {
992  // ci = context-insensitive
993  if(do_ci_lazy_method_conversion(symbol_table, message_handler))
994  return true;
995  break;
997  {
998  symbol_table_buildert symbol_table_builder =
999  symbol_table_buildert::wrap(symbol_table);
1000 
1001  journalling_symbol_tablet journalling_symbol_table =
1002  journalling_symbol_tablet::wrap(symbol_table_builder);
1003 
1004  // Convert all synthetic methods:
1005  for(const auto &function_id_and_type : synthetic_methods)
1006  {
1008  function_id_and_type.first,
1009  journalling_symbol_table,
1011  message_handler);
1012  }
1013  // Convert all methods for which we have bytecode now
1014  for(const auto &method_sig : method_bytecode)
1015  {
1017  method_sig.first,
1018  journalling_symbol_table,
1020  message_handler);
1021  }
1024  journalling_symbol_table,
1026  message_handler);
1027  // Now convert all newly added string methods
1028  for(const auto &fn_name : journalling_symbol_table.get_inserted())
1029  {
1032  fn_name, symbol_table, class_to_declared_symbols, message_handler);
1033  }
1034  }
1035  break;
1037  // Our caller is in charge of elaborating methods on demand.
1038  break;
1039  }
1040 
1041  // now instrument runtime exceptions
1043  symbol_table, language_options->throw_runtime_exceptions, message_handler);
1044 
1045  // now typecheck all
1046  bool res = java_bytecode_typecheck(
1047  symbol_table, message_handler, language_options->string_refinement_enabled);
1048 
1049  // now instrument thread-blocks and synchronized methods.
1050  if(language_options->threading_support)
1051  {
1052  convert_threadblock(symbol_table);
1053  convert_synchronized_methods(symbol_table, message_handler);
1054  }
1055 
1056  return res;
1057 }
1058 
1060  symbol_table_baset &symbol_table,
1061  message_handlert &message_handler)
1062 {
1063  PRECONDITION(language_options.has_value());
1064 
1065  symbol_table_buildert symbol_table_builder =
1066  symbol_table_buildert::wrap(symbol_table);
1067 
1068  main_function_resultt res =
1069  get_main_symbol(symbol_table, main_class, message_handler);
1070  if(!res.is_success())
1071  return res.is_error();
1072 
1073  // Load the main function into the symbol table to get access to its
1074  // parameter names
1076  res.main_function.name, symbol_table_builder, message_handler);
1077 
1078  const symbolt &symbol =
1079  symbol_table_builder.lookup_ref(res.main_function.name);
1080  if(symbol.value.is_nil())
1081  {
1083  "the program has no entry point",
1084  "function",
1085  "Check that the specified entry point is included by your "
1086  "--context-include or --context-exclude options");
1087  }
1088 
1089  // generate the test harness in __CPROVER__start and a call the entry point
1090  return java_entry_point(
1091  symbol_table_builder,
1092  main_class,
1093  message_handler,
1094  language_options->assume_inputs_non_null,
1095  language_options->assert_uncaught_exceptions,
1098  language_options->string_refinement_enabled,
1099  [&](const symbolt &function, symbol_table_baset &symbol_table) {
1100  return java_build_arguments(
1101  function,
1102  symbol_table,
1103  language_options->assume_inputs_non_null,
1104  object_factory_parameters,
1105  get_pointer_type_selector(),
1106  message_handler);
1107  });
1108 }
1109 
1123  symbol_table_baset &symbol_table,
1124  message_handlert &message_handler)
1125 {
1126  symbol_table_buildert symbol_table_builder =
1127  symbol_table_buildert::wrap(symbol_table);
1128 
1130 
1131  const method_convertert method_converter =
1132  [this, &symbol_table_builder, &class_to_declared_symbols, &message_handler](
1133  const irep_idt &function_id,
1134  ci_lazy_methods_neededt lazy_methods_needed) {
1135  return convert_single_method(
1136  function_id,
1137  symbol_table_builder,
1138  std::move(lazy_methods_needed),
1140  message_handler);
1141  };
1142 
1143  ci_lazy_methodst method_gather(
1144  symbol_table,
1145  main_class,
1147  language_options->extra_methods,
1149  language_options->java_load_classes,
1152 
1153  return method_gather(
1154  symbol_table, method_bytecode, method_converter, message_handler);
1155 }
1156 
1157 const select_pointer_typet &
1159 {
1160  PRECONDITION(pointer_type_selector.get()!=nullptr);
1161  return *pointer_type_selector;
1162 }
1163 
1170  std::unordered_set<irep_idt> &methods) const
1171 {
1172  const std::string cprover_class_prefix = "java::org.cprover.CProver.";
1173 
1174  // Add all string solver methods to map
1176  // Add all concrete methods to map
1177  for(const auto &kv : method_bytecode)
1178  methods.insert(kv.first);
1179  // Add all synthetic methods to map
1180  for(const auto &kv : synthetic_methods)
1181  methods.insert(kv.first);
1182  methods.insert(INITIALIZE_FUNCTION);
1183 }
1184 
1195  const irep_idt &function_id,
1196  symbol_table_baset &symtab,
1197  message_handlert &message_handler)
1198 {
1199  const symbolt &symbol = symtab.lookup_ref(function_id);
1200  if(symbol.value.is_not_nil())
1201  return;
1202 
1203  journalling_symbol_tablet symbol_table=
1205 
1208  function_id, symbol_table, class_to_declared_symbols, message_handler);
1209 
1210  // Instrument runtime exceptions (unless symbol is a stub or is the
1211  // INITIALISE_FUNCTION).
1212  if(symbol.value.is_not_nil() && function_id != INITIALIZE_FUNCTION)
1213  {
1215  symbol_table,
1216  symbol_table.get_writeable_ref(function_id),
1217  language_options->throw_runtime_exceptions,
1218  message_handler);
1219  }
1220 
1221  // now typecheck this function
1223  symbol_table, message_handler, language_options->string_refinement_enabled);
1224 }
1225 
1237  const codet &function_body,
1238  std::optional<ci_lazy_methods_neededt> needed_lazy_methods)
1239 {
1240  if(needed_lazy_methods)
1241  {
1242  for(const_depth_iteratort it = function_body.depth_cbegin();
1243  it != function_body.depth_cend();
1244  ++it)
1245  {
1246  if(it->id() == ID_code)
1247  {
1248  const auto fn_call = expr_try_dynamic_cast<code_function_callt>(*it);
1249  if(!fn_call)
1250  continue;
1251  const symbol_exprt *fn_sym =
1252  expr_try_dynamic_cast<symbol_exprt>(fn_call->function());
1253  if(fn_sym)
1254  needed_lazy_methods->add_needed_method(fn_sym->get_identifier());
1255  }
1256  else if(
1257  it->id() == ID_side_effect &&
1258  to_side_effect_expr(*it).get_statement() == ID_function_call)
1259  {
1260  const auto &call_expr = to_side_effect_expr_function_call(*it);
1261  const symbol_exprt *fn_sym =
1262  expr_try_dynamic_cast<symbol_exprt>(call_expr.function());
1263  if(fn_sym)
1264  {
1265  INVARIANT(
1266  false,
1267  "Java synthetic methods are not "
1268  "expected to produce side_effect_expr_function_callt. If "
1269  "that has changed, remove this invariant. Also note that "
1270  "as of the time of writing remove_virtual_functions did "
1271  "not support this form of function call.");
1272  // needed_lazy_methods->add_needed_method(fn_sym->get_identifier());
1273  }
1274  }
1275  }
1276  }
1277 }
1278 
1293  const irep_idt &function_id,
1294  symbol_table_baset &symbol_table,
1295  std::optional<ci_lazy_methods_neededt> needed_lazy_methods,
1297  message_handlert &message_handler)
1298 {
1299  const symbolt &symbol = symbol_table.lookup_ref(function_id);
1300 
1301  // Nothing to do if body is already loaded
1302  if(symbol.value.is_not_nil())
1303  return false;
1304 
1305  if(function_id == INITIALIZE_FUNCTION)
1306  {
1308  symbol_table,
1309  symbol.location,
1310  language_options->assume_inputs_non_null,
1313  language_options->string_refinement_enabled,
1314  message_handler);
1315  return false;
1316  }
1317 
1318  INVARIANT(declaring_class(symbol), "Method must have a declaring class.");
1319 
1320  bool ret = convert_single_method_code(
1321  function_id,
1322  symbol_table,
1323  needed_lazy_methods,
1325  message_handler);
1326 
1327  if(symbol.value.is_not_nil() && language_options->should_lift_clinit_calls)
1328  {
1329  auto &writable_symbol = symbol_table.get_writeable_ref(function_id);
1330  writable_symbol.value =
1331  lift_clinit_calls(std::move(to_code(writable_symbol.value)));
1332  }
1333 
1334  INVARIANT(declaring_class(symbol), "Method must have a declaring class.");
1335 
1336  return ret;
1337 }
1338 
1352  const irep_idt &function_id,
1353  symbol_table_baset &symbol_table,
1354  std::optional<ci_lazy_methods_neededt> needed_lazy_methods,
1356  message_handlert &message_handler)
1357 {
1358  const auto &symbol = symbol_table.lookup_ref(function_id);
1359  PRECONDITION(symbol.value.is_nil());
1360 
1361  // Get bytecode for specified function if we have it
1362  method_bytecodet::opt_reft cmb = method_bytecode.get(function_id);
1363 
1364  synthetic_methods_mapt::iterator synthetic_method_it;
1365 
1366  // Check if have a string solver implementation
1367  if(string_preprocess.implements_function(function_id))
1368  {
1369  symbolt &writable_symbol = symbol_table.get_writeable_ref(function_id);
1370  // Load parameter names from any extant bytecode before filling in body
1371  if(cmb)
1372  {
1374  writable_symbol, cmb->get().method.local_variable_table, symbol_table);
1375  }
1376  // Populate body of the function with code generated by string preprocess
1377  codet generated_code = string_preprocess.code_for_function(
1378  writable_symbol, symbol_table, message_handler);
1379  // String solver can make calls to functions that haven't yet been seen.
1380  // Add these to the needed_lazy_methods collection
1381  notify_static_method_calls(generated_code, needed_lazy_methods);
1382  writable_symbol.value = std::move(generated_code);
1383  return false;
1384  }
1385  else if(
1386  (synthetic_method_it = synthetic_methods.find(function_id)) !=
1387  synthetic_methods.end())
1388  {
1389  // Synthetic method (i.e. one generated by the Java frontend and which
1390  // doesn't occur in the source bytecode):
1391  symbolt &writable_symbol = symbol_table.get_writeable_ref(function_id);
1392  switch(synthetic_method_it->second)
1393  {
1395  if(language_options->threading_support)
1396  writable_symbol.value = get_thread_safe_clinit_wrapper_body(
1397  function_id,
1398  symbol_table,
1399  language_options->nondet_static,
1400  language_options->static_values_json.has_value(),
1403  message_handler);
1404  else
1405  writable_symbol.value = get_clinit_wrapper_body(
1406  function_id,
1407  symbol_table,
1408  language_options->nondet_static,
1409  language_options->static_values_json.has_value(),
1412  message_handler);
1413  break;
1415  {
1416  const auto class_name =
1417  declaring_class(symbol_table.lookup_ref(function_id));
1418  INVARIANT(
1419  class_name, "user_specified_clinit must be declared by a class.");
1420  INVARIANT(
1421  language_options->static_values_json.has_value(),
1422  "static-values JSON must be available");
1423  writable_symbol.value = get_user_specified_clinit_body(
1424  *class_name,
1425  *language_options->static_values_json,
1426  symbol_table,
1427  needed_lazy_methods,
1428  language_options->max_user_array_length,
1429  references,
1430  class_to_declared_symbols.get(symbol_table));
1431  break;
1432  }
1434  writable_symbol.value =
1436  function_id,
1437  symbol_table,
1440  message_handler);
1441  break;
1443  writable_symbol.value = invokedynamic_synthetic_constructor(
1444  function_id, symbol_table, message_handler);
1445  break;
1447  writable_symbol.value = invokedynamic_synthetic_method(
1448  function_id, symbol_table, message_handler);
1449  break;
1451  {
1452  INVARIANT(
1453  cmb,
1454  "CProver.createArrayWithType should only be registered if "
1455  "we have a real implementation available");
1457  writable_symbol, cmb->get().method.local_variable_table, symbol_table);
1458  writable_symbol.value =
1459  create_array_with_type_body(function_id, symbol_table, message_handler);
1460  break;
1461  }
1462  }
1463  // Notify lazy methods of static calls made from the newly generated
1464  // function:
1466  to_code(writable_symbol.value), needed_lazy_methods);
1467  return false;
1468  }
1469 
1470  // No string solver or static init wrapper implementation;
1471  // check if have bytecode for it
1472  if(cmb)
1473  {
1475  symbol_table.lookup_ref(cmb->get().class_id),
1476  cmb->get().method,
1477  symbol_table,
1478  message_handler,
1479  language_options->max_user_array_length,
1480  language_options->throw_assertion_error,
1481  std::move(needed_lazy_methods),
1484  language_options->threading_support,
1485  language_options->method_context,
1486  language_options->assert_no_exceptions_thrown);
1487  return false;
1488  }
1489 
1490  if(needed_lazy_methods)
1491  {
1492  // The return of an opaque function is a source of an otherwise invisible
1493  // instantiation, so here we ensure we've loaded the appropriate classes.
1494  const java_method_typet function_type = to_java_method_type(symbol.type);
1495  if(
1496  const pointer_typet *pointer_return_type =
1497  type_try_dynamic_cast<pointer_typet>(function_type.return_type()))
1498  {
1499  // If the return type is abstract, we won't forcibly instantiate it here
1500  // otherwise this can cause abstract methods to be explictly called
1501  // TODO(tkiley): Arguably no abstract class should ever be added to
1502  // TODO(tkiley): ci_lazy_methods_neededt, but this needs further
1503  // TODO(tkiley): investigation
1504  namespacet ns{symbol_table};
1505  const java_class_typet &underlying_type =
1506  to_java_class_type(ns.follow(pointer_return_type->base_type()));
1507 
1508  if(!underlying_type.is_abstract())
1509  needed_lazy_methods->add_all_needed_classes(*pointer_return_type);
1510  }
1511  }
1512 
1513  return true;
1514 }
1515 
1517 {
1518  PRECONDITION(language_options.has_value());
1519  return false;
1520 }
1521 
1523  std::ostream &out,
1524  message_handlert &message_handler)
1525 {
1527  java_class_loader(main_class, message_handler);
1528  parse_trees.front().output(out);
1529  if(parse_trees.size() > 1)
1530  {
1531  out << "\n\nClass has the following overlays:\n\n";
1532  for(auto parse_tree_it = std::next(parse_trees.begin());
1533  parse_tree_it != parse_trees.end();
1534  ++parse_tree_it)
1535  {
1536  parse_tree_it->output(out);
1537  }
1538  out << "End of class overlays.\n";
1539  }
1540 }
1541 
1542 std::unique_ptr<languaget> new_java_bytecode_language()
1543 {
1544  return std::make_unique<java_bytecode_languaget>();
1545 }
1546 
1548  const exprt &expr,
1549  std::string &code,
1550  const namespacet &ns)
1551 {
1552  code=expr2java(expr, ns);
1553  return false;
1554 }
1555 
1557  const typet &type,
1558  std::string &code,
1559  const namespacet &ns)
1560 {
1561  code=type2java(type, ns);
1562  return false;
1563 }
1564 
1566  const std::string &code,
1567  const std::string &module,
1568  exprt &expr,
1569  const namespacet &ns,
1570  message_handlert &message_handler)
1571 {
1572 #if 0
1573  expr.make_nil();
1574 
1575  // no preprocessing yet...
1576 
1577  std::istringstream i_preprocessed(code);
1578 
1579  // parsing
1580 
1581  java_bytecode_parser.clear();
1582  java_bytecode_parser.filename="";
1583  java_bytecode_parser.in=&i_preprocessed;
1584  java_bytecode_parser.set_message_handler(message_handler);
1585  java_bytecode_parser.grammar=java_bytecode_parsert::EXPRESSION;
1586  java_bytecode_parser.mode=java_bytecode_parsert::GCC;
1587  java_bytecode_scanner_init();
1588 
1589  bool result=java_bytecode_parser.parse();
1590 
1591  if(java_bytecode_parser.parse_tree.items.empty())
1592  result=true;
1593  else
1594  {
1595  expr=java_bytecode_parser.parse_tree.items.front().value();
1596 
1597  result=java_bytecode_convert(expr, "", message_handler);
1598 
1599  // typecheck it
1600  if(!result)
1601  result=java_bytecode_typecheck(expr, message_handler, ns);
1602  }
1603 
1604  // save some memory
1605  java_bytecode_parser.clear();
1606 
1607  return result;
1608 #else
1609  // unused parameters
1610  (void)code;
1611  (void)module;
1612  (void)expr;
1613  (void)ns;
1614  (void)message_handler;
1615 #endif
1616 
1617  return true; // fail for now
1618 }
1619 
1621 {
1622 }
1623 
1627 std::vector<load_extra_methodst>
1629 {
1630  (void)options; // unused parameter
1631  return {};
1632 }
static abstract_object_pointert transform(const exprt &expr, const std::vector< abstract_object_pointert > &operands, const abstract_environmentt &environment, const namespacet &ns)
configt config
Definition: config.cpp:25
struct bytecode_infot const bytecode_info[]
Collect methods needed to be loaded using the lazy method.
std::function< bool(const irep_idt &function_id, ci_lazy_methods_neededt)> method_convertert
Class Hierarchy.
Operator to return the address of an object.
Definition: pointer_expr.h:540
Non-graph-based representation of the class hierarchy.
class_mapt class_map
std::vector< irep_idt > idst
bool is_abstract() const
Definition: std_types.h:358
std::string get_value(char option) const
Definition: cmdline.cpp:48
virtual bool isset(char option) const
Definition: cmdline.cpp:30
const std::list< std::string > & get_values(const std::string &option) const
Definition: cmdline.cpp:109
const typet & return_type() const
Definition: std_types.h:689
Data structure for representing an arbitrary statement in a program.
Definition: std_code_base.h:29
std::optional< std::string > main
Definition: config.h:356
struct configt::javat java
dstringt has one field, an unsigned integer no which is an index into a static table of strings.
Definition: dstring.h:38
bool empty() const
Definition: dstring.h:89
Base class for all expressions.
Definition: expr.h:56
const_depth_iteratort depth_cend() const
Definition: expr.cpp:257
typet & type()
Return the type of the expression.
Definition: expr.h:84
bool is_constant() const
Return whether the expression is a constant.
Definition: expr.h:212
const_depth_iteratort depth_cbegin() const
Definition: expr.cpp:255
Represents the argument of an instruction that uses a CONSTANT_Fieldref This is used for example as a...
irep_idt class_name() const
irep_idt component_name() const
Thrown when users pass incorrect command line arguments, for example passing no files to analysis or ...
const irep_idt & get(const irep_idt &name) const
Definition: irep.cpp:44
bool is_not_nil() const
Definition: irep.h:368
const irep_idt & id() const
Definition: irep.h:384
void make_nil()
Definition: irep.h:442
bool is_nil() const
Definition: irep.h:364
virtual void methods_provided(std::unordered_set< irep_idt > &methods) const override
Provide feedback to language_filest so that when asked for a lazy method, it can delegate to this ins...
synthetic_methods_mapt synthetic_methods
Maps synthetic method names on to the particular type of synthetic method (static initializer,...
std::vector< irep_idt > main_jar_classes
bool to_expr(const std::string &code, const std::string &module, exprt &expr, const namespacet &ns, message_handlert &message_handler) override
Parses the given string into an expression.
virtual bool final(symbol_table_baset &context) override
Final adjustments, e.g.
std::string id() const override
stub_global_initializer_factoryt stub_global_initializer_factory
std::set< std::string > extensions() const override
bool from_type(const typet &type, std::string &code, const namespacet &ns) override
Formats the given type in a language-specific way.
void set_language_options(const optionst &, message_handlert &) override
Consume options that are java bytecode specific.
virtual bool parse(message_handlert &)
We set the main class (i.e. class to start the class loading analysis, see java_class_loadert) when w...
const std::unique_ptr< const select_pointer_typet > pointer_type_selector
java_object_factory_parameterst object_factory_parameters
void show_parse(std::ostream &out, message_handlert &) override
void initialize_class_loader(message_handlert &)
java_string_library_preprocesst string_preprocess
void modules_provided(std::set< std::string > &modules) override
java_class_loadert java_class_loader
virtual void convert_lazy_method(const irep_idt &function_id, symbol_table_baset &symbol_table, message_handlert &message_handler) override
Promote a lazy-converted method (one whose type is known but whose body hasn't been converted) into a...
virtual std::vector< load_extra_methodst > build_extra_entry_points(const optionst &) const
This method should be overloaded to provide alternative approaches for specifying extra entry points.
std::optional< java_bytecode_language_optionst > language_options
const select_pointer_typet & get_pointer_type_selector() const
void parse_from_main_class(message_handlert &)
bool convert_single_method_code(const irep_idt &function_id, symbol_table_baset &symbol_table, std::optional< ci_lazy_methods_neededt > needed_lazy_methods, lazy_class_to_declared_symbols_mapt &class_to_declared_symbols, message_handlert &)
Convert a method (one whose type is known but whose body hasn't been converted) but don't run typeche...
bool from_expr(const exprt &expr, std::string &code, const namespacet &ns) override
Formats the given expression in a language-specific way.
void convert_single_method(const irep_idt &function_id, symbol_table_baset &symbol_table, lazy_class_to_declared_symbols_mapt &class_to_declared_symbols, message_handlert &message_handler)
std::unordered_map< std::string, object_creation_referencet > references
Map used in all calls to functions that deterministically create objects (currently only assign_from_...
bool typecheck(symbol_table_baset &context, const std::string &module, message_handlert &message_handler) override
virtual bool preprocess(std::istream &instream, const std::string &path, std::ostream &outstream, message_handlert &message_handler) override
ANSI-C preprocessing.
bool generate_support_functions(symbol_table_baset &symbol_table, message_handlert &message_handler) override
Create language-specific support functions, such as __CPROVER_start, __CPROVER_initialize and languag...
bool do_ci_lazy_method_conversion(symbol_table_baset &, message_handlert &)
Uses a simple context-insensitive ('ci') analysis to determine which methods may be reachable from th...
void add_classpath_entry(const std::string &, message_handlert &)
Appends an entry to the class path, used for loading classes.
void clear_classpath()
Clear all classpath entries.
jar_poolt jar_pool
a cache for jar_filet, by path name
Class representing a filter for class file loading.
std::vector< irep_idt > load_entire_jar(const std::string &jar_path, message_handlert &)
Load all class files from a .jar file.
bool can_load_class(const irep_idt &class_name, message_handlert &)
Checks whether class_name is parseable from the classpath, ignoring class loading limits.
void set_extra_class_refs_function(get_extra_class_refs_functiont func)
Sets a function that provides extra dependencies for a particular class.
void set_java_cp_include_files(const std::string &cp_include_files)
Set the argument of the class loader limit java_class_loader_limitt.
fixed_keys_map_wrappert< parse_tree_with_overridest_mapt > get_class_with_overlays_map()
Map from class names to the bytecode parse trees.
std::list< java_bytecode_parse_treet > parse_tree_with_overlayst
A list of parse trees supporting overlay classes.
void add_load_classes(const std::vector< irep_idt > &classes)
Adds the list of classes to the load queue, forcing them to be loaded even without explicit reference...
bool get_is_stub() const
Definition: java_types.h:397
const componentst & components() const
Definition: java_types.h:223
void get_all_function_names(std::unordered_set< irep_idt > &methods) const
bool implements_function(const irep_idt &function_id) const
std::vector< irep_idt > get_string_type_base_classes(const irep_idt &class_name)
Gets the base classes for known String and String-related types, or returns an empty list for other t...
void initialize_conversion_table()
fill maps with correspondence from java method names to conversion functions
codet code_for_function(const symbolt &symbol, symbol_table_baset &symbol_table, message_handlert &message_handler)
Should be called to provide code for string functions that are used in the code but for which no impl...
A symbol table wrapper that records which entries have been updated/removedA caller can pass a journa...
static journalling_symbol_tablet wrap(symbol_table_baset &base_symbol_table)
const changesett & get_inserted() const
Definition: json.h:27
bool is_array() const
Definition: json.h:61
bool is_object() const
Definition: json.h:56
Map classes to the symbols they declare but is only computed once it is needed and the map is then ke...
std::unordered_multimap< irep_idt, symbolt > & get(const symbol_table_baset &symbol_table)
std::unordered_multimap< irep_idt, symbolt > map
Class that provides messages with a built-in verbosity 'level'.
Definition: message.h:155
static eomt eom
Definition: message.h:297
opt_reft get(const irep_idt &method_id)
std::optional< std::reference_wrapper< const class_method_and_bytecodet > > opt_reft
An exception that is raised checking whether a class is implicitly generic if a symbol for an outer c...
const typet & follow(const typet &) const
Resolve type symbol to the type it points to.
Definition: namespace.cpp:49
A namespacet is essentially one or two symbol tables bound together, to allow for symbol lookups in t...
Definition: namespace.h:94
The null pointer constant.
Definition: pointer_expr.h:909
unsigned int get_unsigned_int_option(const std::string &option) const
Definition: options.cpp:56
bool is_set(const std::string &option) const
N.B. opts.is_set("foo") does not imply opts.get_bool_option("foo")
Definition: options.cpp:62
bool get_bool_option(const std::string &option) const
Definition: options.cpp:44
void set_option(const std::string &option, const bool value)
Definition: options.cpp:28
const std::string get_option(const std::string &option) const
Definition: options.cpp:67
const value_listt & get_list_option(const std::string &option) const
Definition: options.cpp:80
The pointer type These are both 'bitvector_typet' (they have a width) and 'type_with_subtypet' (they ...
Definition: pointer_expr.h:24
Provides filtering of strings vai inclusion/exclusion lists of prefixes.
Definition: prefix_filter.h:20
const irep_idt & get_statement() const
Definition: std_code.h:1472
A struct tag type, i.e., struct_typet with an identifier.
Definition: std_types.h:493
const basest & bases() const
Get the collection of base classes/structs.
Definition: std_types.h:262
bool has_component(const irep_idt &component_name) const
Definition: std_types.h:157
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...
Expression to hold a symbol (variable)
Definition: std_expr.h:131
const irep_idt & get_identifier() const
Definition: std_expr.h:160
The symbol table base class interface.
symbolt & get_writeable_ref(const irep_idt &name)
Find a symbol in the symbol table for read-write access.
virtual iteratort begin()=0
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.
virtual iteratort end()=0
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.
Author: Diffblue Ltd.
static symbol_table_buildert wrap(symbol_table_baset &base_symbol_table)
Symbol table entry.
Definition: symbol.h:28
source_locationt location
Source code location of definition of symbol.
Definition: symbol.h:37
typet type
Type of symbol.
Definition: symbol.h:31
irep_idt name
The unique identifier.
Definition: symbol.h:40
exprt value
Initial value of symbol.
Definition: symbol.h:34
Thrown when some external system fails unexpectedly.
The type of an expression, extends irept.
Definition: type.h:29
irep_idt get_create_array_with_type_name()
Returns the symbol name for org.cprover.CProver.createArrayWithType
codet create_array_with_type_body(const irep_idt &function_id, symbol_table_baset &symbol_table, message_handlert &message_handler)
Returns the internal implementation for org.cprover.CProver.createArrayWithType.
Implementation of CProver.createArrayWithType intrinsic.
std::string type2java(const typet &type, const namespacet &ns)
Definition: expr2java.cpp:459
std::string expr2java(const exprt &expr, const namespacet &ns)
Definition: expr2java.cpp:452
Forward depth-first search iterators These iterators' copy operations are expensive,...
const std::string & id2string(const irep_idt &d)
Definition: irep.h:40
void convert_synchronized_methods(symbol_table_baset &symbol_table, message_handlert &message_handler)
Iterate through the symbol table to find and instrument synchronized methods.
void convert_threadblock(symbol_table_baset &symbol_table)
Iterate through the symbol table to find and appropriately instrument thread-blocks.
void mark_java_implicitly_generic_class_type(const irep_idt &class_name, symbol_table_baset &symbol_table)
Checks if the class is implicitly generic, i.e., it is an inner class of any generic class.
bool java_bytecode_convert_class(const java_class_loadert::parse_tree_with_overlayst &parse_trees, symbol_table_baset &symbol_table, message_handlert &message_handler, size_t max_array_length, method_bytecodet &method_bytecode, java_string_library_preprocesst &string_preprocess, const std::unordered_set< std::string > &no_load_classes)
See class java_bytecode_convert_classt.
JAVA Bytecode Language Conversion.
void java_bytecode_initialize_parameter_names(symbolt &method_symbol, const java_bytecode_parse_treet::methodt::local_variable_tablet &local_variable_table, symbol_table_baset &symbol_table)
This uses a cut-down version of the logic in java_bytecode_convert_methodt::convert to initialize sym...
void java_bytecode_convert_method(const symbolt &class_symbol, const java_bytecode_parse_treet::methodt &method, symbol_table_baset &symbol_table, message_handlert &message_handler, size_t max_array_length, bool throw_assertion_error, std::optional< ci_lazy_methods_neededt > needed_lazy_methods, java_string_library_preprocesst &string_preprocess, const class_hierarchyt &class_hierarchy, bool threading_support, const std::optional< prefix_filtert > &method_context, bool assert_no_exceptions_thrown)
JAVA Bytecode Language Conversion.
void java_bytecode_instrument_symbol(symbol_table_baset &symbol_table, symbolt &symbol, const bool throw_runtime_exceptions, message_handlert &message_handler)
Instruments the code attached to symbol with runtime exceptions or corresponding assertions.
void java_bytecode_instrument(symbol_table_baset &symbol_table, const bool throw_runtime_exceptions, message_handlert &message_handler)
Instruments all the code in the symbol_table with runtime exceptions or corresponding assertions.
const std::vector< std::string > exception_needed_classes
void java_internal_additions(symbol_table_baset &dest)
static void generate_constant_global_variables(java_bytecode_parse_treet &parse_tree, symbol_table_baset &symbol_table, bool string_refinement_enabled)
Creates global variables for constants mentioned in a given method.
static exprt get_ldc_result(const exprt &ldc_arg0, symbol_table_baset &symbol_table, bool string_refinement_enabled)
Get result of a Java load-constant (ldc) instruction.
void parse_java_language_options(const cmdlinet &cmd, optionst &options)
Parse options that are java bytecode specific.
static symbol_exprt get_or_create_class_literal_symbol(const irep_idt &class_id, symbol_table_baset &symbol_table)
Create if necessary, then return the constant global java.lang.Class symbol for a given class id.
static void infer_opaque_type_fields(const java_bytecode_parse_treet &parse_tree, symbol_table_baset &symbol_table)
Infer fields that must exist on opaque types from field accesses against them.
static void create_stub_global_symbol(symbol_table_baset &symbol_table, const irep_idt &symbol_id, const irep_idt &symbol_basename, const typet &symbol_type, const irep_idt &class_id, bool force_nondet_init)
Add a stub global symbol to the symbol table, initialising pointer-typed symbols with null and primit...
static void throwMainClassLoadingError(const std::string &main_class)
prefix_filtert get_context(const optionst &options)
static void create_stub_global_symbols(const java_bytecode_parse_treet &parse_tree, symbol_table_baset &symbol_table, const class_hierarchyt &class_hierarchy, messaget &log)
Search for getstatic and putstatic instructions in a class' bytecode and create stub symbols for any ...
static irep_idt get_any_incomplete_ancestor_for_stub_static_field(const irep_idt &start_class_id, const symbol_table_baset &symbol_table, const class_hierarchyt &class_hierarchy)
Find any incomplete ancestor of a given class that can have a stub static field attached to it.
static void notify_static_method_calls(const codet &function_body, std::optional< ci_lazy_methods_neededt > needed_lazy_methods)
Notify ci_lazy_methods, if present, of any static function calls made by the given function body.
std::unique_ptr< languaget > new_java_bytecode_language()
@ LAZY_METHODS_MODE_EAGER
@ LAZY_METHODS_MODE_EXTERNAL_DRIVER
@ LAZY_METHODS_MODE_CONTEXT_INSENSITIVE
#define JAVA_CLASS_MODEL_SUFFIX
bool java_bytecode_typecheck(symbol_table_baset &symbol_table, message_handlert &message_handler, bool string_refinement_enabled)
void java_bytecode_typecheck_updated_symbols(journalling_symbol_tablet &symbol_table, message_handlert &message_handler, bool string_refinement_enabled)
JAVA Bytecode Language Type Checking.
limit class path loading
bool java_entry_point(symbol_table_baset &symbol_table, const irep_idt &main_class, message_handlert &message_handler, bool assume_init_pointers_not_null, bool assert_uncaught_exceptions, const java_object_factory_parameterst &object_factory_parameters, const select_pointer_typet &pointer_type_selector, bool string_refinement_enabled, const build_argumentst &build_arguments)
Given the symbol_table and the main_class to test, this function generates a new function __CPROVER__...
void create_java_initialize(symbol_table_baset &symbol_table)
Adds __cprover_initialize to the symbol_table but does not generate code for it yet.
void java_static_lifetime_init(symbol_table_baset &symbol_table, const source_locationt &source_location, bool assume_init_pointers_not_null, java_object_factory_parameterst object_factory_parameters, const select_pointer_typet &pointer_type_selector, bool string_refinement_enabled, message_handlert &message_handler)
Adds the body to __CPROVER_initialize.
main_function_resultt get_main_symbol(const symbol_table_baset &symbol_table, const irep_idt &main_class, message_handlert &message_handler)
Figures out the entry point of the code to verify.
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...
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...
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.
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.
Representation of a constant Java string.
symbol_exprt get_or_create_string_literal_symbol(const java_string_literal_exprt &string_expr, symbol_table_baset &symbol_table, bool string_refinement_enabled)
Creates or gets an existing constant global symbol for a given string literal.
const java_class_typet & to_java_class_type(const typet &type)
Definition: java_types.h:581
const java_method_typet & to_java_method_type(const typet &type)
Definition: java_types.h:183
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
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
std::optional< resolve_inherited_componentt::inherited_componentt > get_inherited_component(const irep_idt &component_class_id, const irep_idt &component_name, const symbol_table_baset &symbol_table, bool include_interfaces)
Finds an inherited component (method or field), taking component visibility into account.
Definition: java_utils.cpp:448
std::optional< std::string > class_name_from_method_name(const std::string &method_name)
Get JVM type name of the class in which method_name is defined.
Definition: java_utils.cpp:580
Author: Diffblue Ltd.
json_arrayt & to_json_array(jsont &json)
Definition: json.h:424
json_objectt & to_json_object(jsont &json)
Definition: json.h:442
bool parse_json(std::istream &in, const std::string &filename, message_handlert &message_handler, jsont &dest)
Definition: json_parser.cpp:27
void create_invokedynamic_synthetic_classes(const irep_idt &method_identifier, const java_bytecode_parse_treet::methodt::instructionst &instructions, symbol_table_baset &symbol_table, synthetic_methods_mapt &synthetic_methods, message_handlert &message_handler)
codet invokedynamic_synthetic_constructor(const irep_idt &function_id, symbol_table_baset &symbol_table, message_handlert &message_handler)
Create invokedynamic synthetic constructor.
codet invokedynamic_synthetic_method(const irep_idt &function_id, symbol_table_baset &symbol_table, message_handlert &message_handler)
Create the body for the synthetic method implementing an invokedynamic method.
Java lambda code synthesis.
codet lift_clinit_calls(codet input)
file Static initializer call lifting
std::function< std::vector< irep_idt >const symbol_table_baset &symbol_table)> build_load_method_by_regex(const std::string &pattern)
Create a lambda that returns the symbols that the given pattern should be loaded.If the pattern doesn...
Process a pattern to use as a regex for selecting extra entry points for ci_lazy_methodst.
double log(double x)
Definition: math.c:2776
Options.
const pointer_typet & to_pointer_type(const typet &type)
Cast a typet to a pointer_typet.
Definition: pointer_expr.h:93
#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
#define INITIALIZE_FUNCTION
side_effect_exprt & to_side_effect_expr(exprt &expr)
Definition: std_code.h:1506
side_effect_expr_function_callt & to_side_effect_expr_function_call(exprt &expr)
Definition: std_code.h:1739
const codet & to_code(const exprt &expr)
auto component(T &struct_expr, const irep_idt &name, const namespacet &ns) -> decltype(struct_expr.op0())
Definition: std_expr.cpp:80
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 char * mnemonic
Definition: bytecode_info.h:46
classpatht classpath
Definition: config.h:342
irep_idt main_class
Definition: config.h:343
bool assert_no_exceptions_thrown
Transform athrow bytecode instructions into assert FALSE followed by assume FALSE.
bool should_lift_clinit_calls
Should we lift clinit calls in function bodies to the top? For example, turning if(x) A....
std::optional< prefix_filtert > method_context
If set, method bodies are only elaborated if they pass the filter.
bool assume_inputs_non_null
assume inputs variables to be non-null
size_t max_user_array_length
max size for user code created arrays
std::vector< irep_idt > java_load_classes
list of classes to force load even without reference from the entry point
std::unordered_set< std::string > no_load_classes
List of classes to never load.
std::vector< load_extra_methodst > extra_methods
std::optional< json_objectt > static_values_json
JSON which contains initial values of static fields (right after the static initializer of the class ...
void set(const optionst &)
Assigns the parameters from given options.
bool has_suffix(const std::string &s, const std::string &suffix)
Definition: suffix.h:17
@ INVOKEDYNAMIC_METHOD
A generated method for a class capturing the parameters of an invokedynamic instruction.
@ 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.
@ CREATE_ARRAY_WITH_TYPE
Our internal implementation of CProver.createArrayWithType, which needs to access internal type-id fi...
@ INVOKEDYNAMIC_CAPTURE_CONSTRUCTOR
A generated constructor for a class capturing the parameters of an invokedynamic instruction.
dstringt irep_idt