|
|
|
(*
|
|
|
|
* Copyright (c) 2009 -2013 Monoidics ltd.
|
|
|
|
* Copyright (c) 2013 - Facebook.
|
|
|
|
* All rights reserved.
|
|
|
|
*)
|
|
|
|
|
|
|
|
open Javalib_pack
|
|
|
|
|
|
|
|
module L = Logging
|
|
|
|
open Utils
|
|
|
|
|
|
|
|
let arg_desc =
|
|
|
|
let base_arg =
|
|
|
|
let options_to_keep = ["-results_dir"; "-project_root"] in
|
|
|
|
let filter arg_desc =
|
|
|
|
list_filter (fun desc -> let (option_name, _, _, _) = desc in list_mem string_equal option_name options_to_keep) arg_desc in
|
|
|
|
let desc =
|
|
|
|
(filter base_arg_desc) @
|
|
|
|
[
|
|
|
|
"-models", Arg.String (fun filename -> JClasspath.add_models filename), Some "paths", "set the path to the jar containing the models";
|
|
|
|
"-debug", Arg.Unit (fun () -> JConfig.debug_mode := true), None, "write extra translation information";
|
|
|
|
"-dependencies", Arg.Unit (fun _ -> JConfig.dependency_mode := true), None, "translate all the dependencies during the capture";
|
|
|
|
"-no-static_final", Arg.Unit (fun () -> JTrans.no_static_final := true), None, "no special treatment for static final fields";
|
|
|
|
"-tracing", Arg.Unit (fun () -> JConfig.translate_checks := true), None,
|
|
|
|
"Translate JVM checks";
|
|
|
|
"-verbose_out", Arg.String (fun path -> JClasspath.set_verbose_out path), None,
|
|
|
|
"Set the path to the javac verbose output"
|
|
|
|
] in
|
|
|
|
Arg2.create_options_desc false "Parsing Options" desc in
|
|
|
|
base_arg
|
|
|
|
|
|
|
|
let usage =
|
|
|
|
"Usage: InferJava -d compilation_dir -sources filename\n"
|
|
|
|
|
|
|
|
let print_usage_exit () =
|
|
|
|
Arg2.usage arg_desc usage;
|
|
|
|
exit(1)
|
|
|
|
|
|
|
|
let () =
|
|
|
|
Arg2.parse arg_desc (fun arg -> ()) usage;
|
|
|
|
if Config.analyze_models && !JClasspath.models_jar <> "" then
|
|
|
|
failwith "Not expecting model file when analyzing the models";
|
|
|
|
if not Config.analyze_models && !JClasspath.models_jar = "" then
|
|
|
|
failwith "Java model file is required"
|
|
|
|
|
|
|
|
|
|
|
|
let init_global_state source_file =
|
|
|
|
Sil.curr_language := Sil.Java;
|
|
|
|
DB.current_source := source_file;
|
|
|
|
DB.Results_dir.init ();
|
|
|
|
Ident.reset_name_generator ();
|
|
|
|
SymOp.reset_total ();
|
|
|
|
JContext.reset_exn_node_table ();
|
|
|
|
let nLOC = FileLOC.file_get_loc (DB.source_file_to_string source_file) in
|
|
|
|
Config.nLOC := nLOC
|
|
|
|
|
|
|
|
|
|
|
|
let store_icfg tenv cg cfg source_file =
|
|
|
|
let source_dir = DB.source_dir_from_source_file !DB.current_source in
|
|
|
|
begin
|
|
|
|
let cfg_file = DB.source_dir_get_internal_file source_dir ".cfg" in
|
|
|
|
let cg_file = DB.source_dir_get_internal_file source_dir ".cg" in
|
|
|
|
Cfg.add_removetemps_instructions cfg;
|
|
|
|
Preanal.doit cfg tenv;
|
|
|
|
Cfg.add_abstraction_instructions cfg;
|
|
|
|
Cg.store_to_file cg_file cg;
|
|
|
|
Cfg.store_cfg_to_file cfg_file true cfg;
|
|
|
|
if !JConfig.debug_mode then
|
|
|
|
begin
|
|
|
|
Config.write_dotty := true;
|
|
|
|
Config.print_types := true;
|
|
|
|
Dotty.print_icfg_dotty cfg [];
|
|
|
|
Cg.save_call_graph_dotty None Specs.get_specs cg
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
(* Given a source file, its code is translated, and the call-graph, control-flow-graph and type *)
|
|
|
|
(* environment are obtained and saved. *)
|
|
|
|
let do_source_file
|
|
|
|
never_null_matcher linereader classes program tenv source_basename source_file proc_file_map =
|
|
|
|
JUtils.log "\nfilename: %s (%s)@."
|
|
|
|
(DB.source_file_to_string source_file) source_basename;
|
|
|
|
init_global_state source_file;
|
|
|
|
let call_graph, cfg =
|
|
|
|
JFrontend.compute_source_icfg
|
|
|
|
never_null_matcher linereader classes program tenv source_basename source_file in
|
|
|
|
store_icfg tenv call_graph cfg source_file;
|
|
|
|
if JConfig.create_harness then
|
|
|
|
list_fold_left
|
|
|
|
(fun proc_file_map pdesc ->
|
|
|
|
Procname.Map.add (Cfg.Procdesc.get_proc_name pdesc) source_file proc_file_map)
|
|
|
|
proc_file_map (Cfg.get_all_procs cfg)
|
|
|
|
else proc_file_map
|
|
|
|
|
|
|
|
|
|
|
|
let capture_libs never_null_matcher linereader program tenv =
|
|
|
|
let capture_class tenv cn node =
|
|
|
|
match node with
|
|
|
|
| Javalib.JInterface _ -> ()
|
|
|
|
| Javalib.JClass _ when JFrontend.is_classname_cached cn -> ()
|
|
|
|
| Javalib.JClass _ ->
|
|
|
|
begin
|
|
|
|
let fake_source_file = JClasspath.java_source_file_from_path (JFrontend.path_of_cached_classname cn) in
|
|
|
|
init_global_state fake_source_file;
|
|
|
|
let call_graph, cfg =
|
|
|
|
JFrontend.compute_class_icfg
|
|
|
|
never_null_matcher linereader program tenv node fake_source_file in
|
|
|
|
store_icfg tenv call_graph cfg fake_source_file;
|
|
|
|
JFrontend.cache_classname cn;
|
|
|
|
end in
|
|
|
|
JBasics.ClassMap.iter (capture_class tenv) (JClasspath.get_classmap program)
|
|
|
|
|
|
|
|
|
|
|
|
(* load a stored global tenv if the file is found, and create a new one otherwise *)
|
|
|
|
let load_tenv program =
|
|
|
|
let tenv_filename = DB.global_tenv_fname () in
|
|
|
|
let tenv =
|
|
|
|
if DB.file_exists tenv_filename then
|
|
|
|
begin
|
|
|
|
match Sil.load_tenv_from_file tenv_filename with
|
|
|
|
| None -> Sil.create_tenv ()
|
|
|
|
| Some tenv -> tenv
|
|
|
|
end
|
|
|
|
else
|
|
|
|
Sil.create_tenv () in
|
|
|
|
JTransType.update_tenv tenv program;
|
|
|
|
tenv
|
|
|
|
|
|
|
|
|
|
|
|
(* Store to a file the type environment containing all the types required to perform the analysis *)
|
|
|
|
let save_tenv classpath tenv =
|
|
|
|
JTransType.saturate_tenv_with_classpath classpath tenv;
|
|
|
|
let tenv_filename = DB.global_tenv_fname () in
|
|
|
|
(* TODO: this prevents per compilation step incremental analysis at this stage *)
|
|
|
|
if DB.file_exists tenv_filename then DB.file_remove tenv_filename;
|
|
|
|
JUtils.log "writing new tenv %s@." (DB.filename_to_string tenv_filename);
|
|
|
|
Sil.store_tenv_to_file tenv_filename tenv
|
|
|
|
|
|
|
|
|
|
|
|
(* The program is loaded and translated *)
|
|
|
|
let do_all_files classpath sources classes =
|
|
|
|
JUtils.log "Translating %d source files (%d classes)@."
|
|
|
|
(StringMap.cardinal sources)
|
|
|
|
(JBasics.ClassSet.cardinal classes);
|
|
|
|
let program = JClasspath.load_program classpath classes sources in
|
|
|
|
let tenv = load_tenv program in
|
|
|
|
let linereader = Printer.LineReader.create () in
|
|
|
|
let never_null_matcher = Inferconfig.NeverReturnNull.load_matcher Sil.Java in
|
|
|
|
let proc_file_map =
|
|
|
|
StringMap.fold
|
|
|
|
(do_source_file never_null_matcher linereader classes program tenv)
|
|
|
|
sources
|
|
|
|
Procname.Map.empty in
|
|
|
|
if !JConfig.dependency_mode then
|
|
|
|
capture_libs never_null_matcher linereader program tenv;
|
|
|
|
if JConfig.create_harness then Harness.create_harness proc_file_map tenv;
|
|
|
|
save_tenv classpath tenv;
|
|
|
|
JUtils.log "done @."
|
|
|
|
|
|
|
|
|
|
|
|
(* loads the source files and translates them *)
|
|
|
|
let () =
|
|
|
|
let classpath, sources, classes = JClasspath.load_sources_and_classes () in
|
|
|
|
if StringMap.is_empty sources then
|
|
|
|
failwith "Failed to load any Java source code"
|
|
|
|
else
|
|
|
|
do_all_files classpath sources classes
|