(* * Copyright (c) 2009 - 2013 Monoidics ltd. * Copyright (c) 2013 - present Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. *) module F = Format;; (* Initialization *) F.set_margin 100 let set_minor_heap_size nMb = (* increase the minor heap size to speed up gc *) let ctrl = Gc.get () in let oneMb = 1048576 in let new_size = max ctrl.Gc.minor_heap_size (nMb * oneMb) in Gc.set { ctrl with Gc.minor_heap_size = new_size };; set_minor_heap_size 1 let from_env_variable var_name = try let _ = Sys.getenv var_name in true with Not_found -> false let attributes_dir_name = "attributes" let captured_dir_name = "captured" let sources_dir_name = "sources" let specs_dir_name = "specs" let default_in_zip_results_dir = "infer" let default_buck_out = "buck-out" let proc_stats_filename = "proc_stats.json" let global_tenv_filename = "global.tenv" (** List of paths to the directories containing specs for library functions. *) let specs_library = ref [] (** path to lib/specs to retrieve the default models *) let models_dir = let bin_dir = Filename.dirname Sys.executable_name in let lib_dir = Filename.concat (Filename.concat bin_dir Filename.parent_dir_name) "lib" in let lib_specs_dir = Filename.concat lib_dir specs_dir_name in lib_specs_dir module JarCache = struct let infer_cache : string option ref = ref None let mkdir s = try Unix.mkdir s 0o700; true with Unix.Unix_error _ -> false let extract_specs dest_dir jarfile = let zip_channel = Zip.open_in jarfile in let entries = Zip.entries zip_channel in let extract_entry entry = let dest_file = Filename.concat dest_dir (Filename.basename entry.Zip.filename) in if Filename.check_suffix entry.Zip.filename ".specs" then Zip.copy_entry_to_file zip_channel entry dest_file in List.iter extract_entry entries; Zip.close_in zip_channel let handle_jar jarfile = match !infer_cache with | Some cache_dir -> let basename = Filename.basename jarfile in let key = basename ^ CRC.crc16 jarfile in let key_dir = Filename.concat cache_dir key in if (mkdir key_dir) then extract_specs key_dir jarfile; specs_library := !specs_library @ [key_dir] | None -> () end type zip_library = { zip_filename: string; zip_channel: Zip.in_file; models: bool; } let zip_filename zip_library = zip_library.zip_filename let zip_channel zip_library = zip_library.zip_channel (** list of the zip files to search for specs files *) let zip_libraries : zip_library list ref = ref [] let add_zip_library zip_filename = if !JarCache.infer_cache != None then JarCache.handle_jar zip_filename else (* The order matters, the jar files should be added following the order *) (* specs files should be searched in them *) zip_libraries := !zip_libraries @ [{ zip_filename = zip_filename; zip_channel = Zip.open_in zip_filename; models = false }] let add_models zip_filename = zip_libraries := !zip_libraries @ [{ zip_filename = zip_filename; zip_channel = Zip.open_in zip_filename; models = true }] let project_root : string option ref = ref None (** FLAGS AND GLOBAL VARIABLES *) (** Flag for abstracting fields of structs 0 = no 1 = forget some fields during matching (and so lseg abstraction) *) let abs_struct = ref 1 (** Flag for abstracting numerical values 0 = no abstraction. 1 = evaluate all expressions abstractly. 2 = 1 + abstract constant integer values during join. *) let abs_val = ref 2 (** if true, completely ignore the possibility that errors can be caused by unknown procedures * during the symbolic execution phase *) let angelic_execution = ref true (** Flag for forgetting memory leak false = no true = forget leaked memory cells during abstraction *) let allowleak = ref false (** Flag for ignoring arrays and pointer arithmetic. 0 = treats both features soundly. 1 = assumes that the size of every array is infinite. 2 = assumes that all heap dereferences via array indexing and pointer arithmetic are correct. *) let array_level = ref 0 (** Check whether to report Analysis_stops message in user mode *) let analysis_stops = ref false type os_type = Unix | Win32 | Cygwin let os_type = match Sys.os_type with | "Win32" -> Win32 | "Cygwin" -> Cygwin | _ -> Unix (** default path of the project results directory *) let default_results_dir = Filename.concat (Sys.getcwd ()) "infer-out" (** If true shows internal exceptions*) let developer_mode = ref false (** flag: dotty output filename **) let dotty_output = ref "icfg.dot" (** command line option to activate the eradicate checker. *) let eradicate = ref false (** should the checkers be run? *) let checkers_enabled () = not !eradicate (** flag to activate ondemand mode. *) let ondemand_enabled = ref false (** Flag for footprint discovery mode *) let footprint = ref true (** Set in the middle of forcing delayed prints *) let forcing_delayed_prints = ref false (** If true, treat calls to no-arg getters as idempotent w.r.t non-nullness *) let idempotent_getters = ref true (** if true, changes to code are checked at the procedure level; if false, at the file level *) let incremental_procs = ref true (** Flag to activate intraprocedural-only analysis *) let intraprocedural = ref false (** if active, join x+j and x+k for constants j and k *) let join_plus = ref true (** Flag to tune the final information-loss check used by the join 0 = use the most aggressive join for preconditions 1 = use the least aggressive join for preconditions *) let join_cond = ref 1 (** Flag for turning on the transformation that null is assigned to a program variable when it becomes dead. **) let liveness = ref true (** if true, give static procs a long name filename::procname *) let long_static_proc_names = ref false (** Number of lines of code in original file *) let nLOC = ref 0 (** max number of procedures in each cluster *) let max_cluster_size = ref 2000 (** Maximum level of recursion during the analysis, after which a timeout is generated *) let max_recursion = ref 5 (** Flag to tune the level of applying the meet operator for preconditions during the footprint analysis. 0 = do not use the meet. 1 = use the meet to generate new preconditions. *) let meet_level = ref 1 (** Monitor the size of the props, and print every time the current max is exceeded *) let monitor_prop_size = ref false (** Flag for using the nonempty lseg only **) let nelseg = ref false (** Flag to activate nonstop mode: the analysis continues after in encounters errors *) let nonstop = ref false (** Flag for the on-the-fly predicate discovery *) let on_the_fly = ref true (** if true, skip the re-execution phase *) let only_footprint = ref false (** flag: only analyze procedures which were analyzed before but have no specs *) let only_nospecs = ref false (** flag: only analyze procedures dependent on previous skips which now have a .specs file *) let only_skips = ref false (** if true, user simple pretty printing *) let pp_simple = ref true (** flag: if true print full type info *) let print_types = ref false (** if true, acrtivate color printing by diff'ing w.r.t. previous prop *) let print_using_diff = ref true (** path of the project results directory *) let results_dir = ref default_results_dir (** If not "", only consider functions recursively called by function [!slice_fun] *) let slice_fun = ref "" (** Flag to tune the level of abstracting the postconditions of specs discovered by the footprint analysis. 0 = nothing special. 1 = filter out redundant posts implied by other posts. *) let spec_abs_level = ref 1 (** Flag for test mode *) let test = ref true (** Flag set to enable detailed tracing informatin during error explanation *) let trace_error = ref false (** Flag set to enable detailed tracing information during re-arrangement *) let trace_rearrange = ref false (** Flag set to enable detailed tracing information during join *) let trace_join = ref false (** Flag set to enable detailed tracing information during array abstraction *) let trace_absarray = ref false (** Consider the size of types during analysis, e.g. cannot use an int pointer to write to a char *) let type_size = ref false (** if true, compact summaries before saving *) let save_compact_summaries = ref true (** If true, save the execution time in summaries. This makes the analysis nondeterministic. *) let save_time_in_summaries = ref false (** flag: if true enables printing proposition compatible for the SMT project *) let smt_output = ref false (** flag: if true performs taint analysis *) let taint_analysis = ref false (** set to true to printing tracing information for the analysis *) let trace_anal = ref false (** Flag for turning on the optimization based on locality 0 = no 1 = based on reachability *) let undo_join = ref true (** visit mode for the worklist: 0 depth - fist visit 1 bias towards exit node 2 least visited first *) let worklist_mode = ref 0 (** flag: if true write dot files in db dir*) let write_dotty = ref false (** flag: if true write html files in db dir *) let write_html = ref false let subtype_multirange = ref true let optimistic_cast = ref false (** if true, filter out errors in low likelyhood buckets, and only show then in developer mode *) let filter_buckets = ref false (** if true, show buckets in textual description of errors *) let show_buckets = ref false (** if true, show memory leak buckets in textual description of errors *) let show_ml_buckets = ref false (** if true, print cfg nodes in the dot file that are not defined in that file *) let dotty_cfg_libs = ref true (** if true, it deals with messages (method calls) in objective-c using the objective-c typical semantics. That is: if the receiver is nil then the method is nop and it returns 0. When the flag is false we deal with messages as standard method / function calls *) let objc_method_call_semantics = ref true (** if true, generate preconditions for runtime exceptions in Java and report errors for the public methods having preconditions to throw runtime exceptions *) let report_runtime_exceptions = ref false (** if true, sanity-check inferred preconditions against Nullable annotations and report inconsistencies *) let report_nullable_inconsistency = ref true (** true if the current objective-c source file is compiled with automatic reference counting (ARC) *) let arc_mode = ref false let objc_memory_model_on = ref false let report_assertion_failure = from_env_variable "INFER_REPORT_ASSERTION_FAILURE" let default_failure_name = "ASSERTION_FAILURE" let analyze_models = from_env_variable "INFER_ANALYZE_MODELS" module Experiment = struct (** if true, activate the subtyping routines in C++ as well, not just in Java *) let activate_subtyping_in_cpp = ref false (** if true, a precondition with e.g. index 3 in an array does not require the caller to have index 3 too this mimics what happens with direct access to the array without a procedure call, where the index is simply materialized if not there *) let allow_missing_index_in_proc_call = ref true (** if true, a procedure call succeeds even when there is a bound error this mimics what happens with a direct array access where an error is produced and the analysis continues *) let bound_error_allowed_in_procedure_call = ref true end let source_file_extentions = [".java"; ".m"; ".mm"; ".c"; ".cc"; ".cpp"; ".h"] let anonymous_block_prefix = "__objc_anonymous_block_" let anonymous_block_num_sep = "______" let property_attributes = "property_attributes" let ivar_attributes = "ivar_attributes" let unsafe_unret = "<\"Unsafe_unretained\">" let weak = "<\"Weak\">" let assign = "<\"Assign\">" (** Programming language. *) type language = C_CPP | Java (** current language *) let curr_language = ref C_CPP let string_of_language = function | Java -> "Java" | C_CPP -> "C_CPP"