Revamped Timeout module to save and restore seconds and symops.

Summary:public
Revamped Timeout module by storing elapsed wallclock seconds, and the status of symops, in case of recursive calls.
Extended the API with suspend() and resume() to pause and resume the current timeout.
These are used before and after an on-demand call to the analysis functions.
This achieves the effect that each procedure, even though is interrupted, has its own time and symop counters, which are suspended and resumed as required.

Reviewed By: jeremydubreil

Differential Revision: D2976918

fb-gh-sync-id: 0ed1079
shipit-source-id: 0ed1079
master
Cristiano Calcagno 9 years ago committed by Facebook Github Bot 1
parent 2277c23c60
commit f3ba6c3906

@ -52,7 +52,8 @@ let abs_source_file_from_path fname =
(** convert a project root directory and a full path to a rooted source file *) (** convert a project root directory and a full path to a rooted source file *)
let rel_source_file_from_abs_path root fname = let rel_source_file_from_abs_path root fname =
let relative_complemented_fname = filename_to_relative root fname in let relative_complemented_fname = filename_to_relative root fname in
if Utils.string_is_prefix root fname && Filename.is_relative relative_complemented_fname then if string_is_prefix root fname &&
Filename.is_relative relative_complemented_fname then
Relative relative_complemented_fname Relative relative_complemented_fname
else else
(* The project root is not a prefix of the file name *) (* The project root is not a prefix of the file name *)

@ -936,7 +936,7 @@ let save_source_files cfg =
> >
DB.file_modified_time dest_file) in DB.file_modified_time dest_file) in
if needs_copy then if needs_copy then
match Utils.copy_file source_file_str dest_file_str with match copy_file source_file_str dest_file_str with
| Some _ -> () | Some _ -> ()
| None -> L.err "Error cannot create copy of source file %s@." source_file_str in | None -> L.err "Error cannot create copy of source file %s@." source_file_str in
Node.iter_proc_desc cfg process_proc Node.iter_proc_desc cfg process_proc

@ -180,7 +180,7 @@ module Node : sig
val get_distance_to_exit: t -> int option val get_distance_to_exit: t -> int option
(** Return a description of the node *) (** Return a description of the node *)
val get_description : Utils.printenv -> t -> string val get_description : printenv -> t -> string
(** Get the exception nodes from the current node *) (** Get the exception nodes from the current node *)
val get_exn : t -> t list val get_exn : t -> t list

@ -92,9 +92,10 @@ val handle_exception : exn -> bool
(** print a description of the exception to the html output *) (** print a description of the exception to the html output *)
val print_exception_html : string -> exn -> unit val print_exception_html : string -> exn -> unit
(** pretty print an error given its (id,key), location, kind, name, description, and optional ml location *) (** pretty print an error given its (id,key), location, kind, name, description,
and optional ml location *)
val pp_err : int * int -> Location.t -> err_kind -> Localise.t -> Localise.error_desc -> val pp_err : int * int -> Location.t -> err_kind -> Localise.t -> Localise.error_desc ->
Utils.ml_loc option -> Format.formatter -> unit -> unit ml_loc option -> Format.formatter -> unit -> unit
(** Turn an exception into an error name, error description, (** Turn an exception into an error name, error description,
location in ml source, and category *) location in ml source, and category *)

@ -251,79 +251,6 @@ let filter_max exe_env filter set priority_set =
find_max 1 filter (WeightedPnameSet.inter set priority_set) find_max 1 filter (WeightedPnameSet.inter set priority_set)
with Not_found -> find_max 1 filter set with Not_found -> find_max 1 filter set
(** Handle timeout events *)
module Timeout : sig
(** execute the function up to a given timeout given by the parameter *)
val exe_timeout : int -> ('a -> unit) -> 'a -> failure_kind option
end = struct
let set_alarm nsecs =
match Config.os_type with
| Config.Unix | Config.Cygwin ->
ignore (Unix.setitimer Unix.ITIMER_REAL
{ Unix.it_interval = 3.0; (* try again after 3 seconds if the signal is lost *)
Unix.it_value = float_of_int nsecs })
| Config.Win32 ->
SymOp.set_wallclock_alarm nsecs
let unset_alarm () =
match Config.os_type with
| Config.Unix | Config.Cygwin -> set_alarm 0
| Config.Win32 -> SymOp.unset_wallclock_alarm ()
let timeout_action _ =
unset_alarm ();
raise (Analysis_failure_exe (FKtimeout))
let () = begin
match Config.os_type with
| Config.Unix | Config.Cygwin ->
Sys.set_signal Sys.sigvtalrm (Sys.Signal_handle timeout_action);
Sys.set_signal Sys.sigalrm (Sys.Signal_handle timeout_action)
| Config.Win32 ->
SymOp.set_wallclock_timeout_handler timeout_action;
(* use the Gc alarm for periodic timeout checks *)
ignore (Gc.create_alarm SymOp.check_wallclock_alarm)
end
let current_timeouts = ref []
let exe_timeout iterations f x =
let restore_timeout () =
match !current_timeouts with
| prev_iterations :: _ ->
set_alarm prev_iterations
| [] ->
() in
let unwind () =
let pop () = match !current_timeouts with
| _ :: l -> current_timeouts := l
| [] -> () in
unset_alarm ();
SymOp.unset_alarm ();
pop () in
let before () =
current_timeouts := iterations :: !current_timeouts;
set_iterations iterations;
set_alarm (get_timeout_seconds ());
SymOp.set_alarm () in
let after () =
unwind ();
restore_timeout () in
try
before ();
f x;
after ();
None
with
| Analysis_failure_exe kind ->
after ();
Errdesc.warning_err (State.get_loc ()) "TIMEOUT: %a@." pp_failure_kind kind;
Some kind
| exe ->
after ();
raise exe
end
(** Main algorithm responsible for driving the analysis of an Exe_env (set of procedures). (** Main algorithm responsible for driving the analysis of an Exe_env (set of procedures).
The algorithm computes dependencies between procedures, The algorithm computes dependencies between procedures,
@ -341,7 +268,6 @@ let main_algorithm exe_env analyze_proc filter_out process_result : unit =
WeightedPnameSet.filter (fun (n, _) -> address_taken_of n) !G.wpnames_todo in WeightedPnameSet.filter (fun (n, _) -> address_taken_of n) !G.wpnames_todo in
G.tot_procs := WeightedPnameSet.cardinal !G.wpnames_todo; G.tot_procs := WeightedPnameSet.cardinal !G.wpnames_todo;
G.num_procs_done := 0; G.num_procs_done := 0;
let max_timeout = ref 1 in
let wpname_can_be_analyzed (pname, _) : bool = let wpname_can_be_analyzed (pname, _) : bool =
(* Return true if [pname] is not up to date and it can be analyzed right now *) (* Return true if [pname] is not up to date and it can be analyzed right now *)
Procname.Set.for_all Procname.Set.for_all
@ -365,7 +291,6 @@ let main_algorithm exe_env analyze_proc filter_out process_result : unit =
post_process_procs exe_env [pname] post_process_procs exe_env [pname]
else else
begin begin
max_timeout := max (Specs.get_iterations pname) !max_timeout;
Specs.update_dependency_map pname; Specs.update_dependency_map pname;
process_result exe_env elem (analyze_proc exe_env pname); process_result exe_env elem (analyze_proc exe_env pname);
end in end in

@ -10,15 +10,6 @@
(** Implementation of the Interprocedural Footprint Analysis Algorithm *) (** Implementation of the Interprocedural Footprint Analysis Algorithm *)
(** Handle timeout events *)
module Timeout : sig
(** execute the function up to a given timeout given by the iterations parameter *)
val exe_timeout : int -> ('a -> unit) -> 'a -> Utils.failure_kind option
end
(** {2 Algorithm} *)
val procs_become_done : Cg.t -> Procname.t -> Procname.t list val procs_become_done : Cg.t -> Procname.t -> Procname.t list
val post_process_procs : Exe_env.t -> Procname.t list -> unit val post_process_procs : Exe_env.t -> Procname.t list -> unit

@ -156,7 +156,7 @@ let arg_desc =
"analyze files captured since the last analysis plus any dependencies" "analyze files captured since the last analysis plus any dependencies"
; ;
"-iterations", "-iterations",
Arg.Set_int iterations_cmdline, Arg.Int set_iterations,
Some "n", Some "n",
"set the max number of operations for each function, \ "set the max number of operations for each function, \
expressed as a multiple of symbolic operations (default n=1)" expressed as a multiple of symbolic operations (default n=1)"
@ -281,7 +281,7 @@ let arg_desc =
"set the max number of procedures in each cluster (default n=2000)" "set the max number of procedures in each cluster (default n=2000)"
; ;
"-seconds_per_iteration", "-seconds_per_iteration",
Arg.Set_int seconds_per_iteration, Arg.Set_float seconds_per_iteration,
Some "n", Some "n",
"set the number of seconds per iteration (default n=30)" "set the number of seconds per iteration (default n=30)"
; ;
@ -890,7 +890,7 @@ let () =
else else
let filter source_dir = let filter source_dir =
let source_dir_base = Filename.basename (DB.source_dir_to_string source_dir) in let source_dir_base = Filename.basename (DB.source_dir_to_string source_dir) in
IList.exists (fun s -> Utils.string_is_prefix s source_dir_base) !only_files_cmdline in IList.exists (fun s -> string_is_prefix s source_dir_base) !only_files_cmdline in
IList.filter filter (DB.find_source_dirs ()) in IList.filter filter (DB.find_source_dirs ()) in
L.err "Found %d source files in %s@." (IList.length source_dirs) !Config.results_dir; L.err "Found %d source files in %s@." (IList.length source_dirs) !Config.results_dir;

@ -85,13 +85,13 @@ module FileContainsStringMatcher = struct
try try
DB.SourceFileMap.find source_file !source_map DB.SourceFileMap.find source_file !source_map
with Not_found -> with Not_found ->
try try
let file_in = open_in (DB.source_file_to_string source_file) in let file_in = open_in (DB.source_file_to_string source_file) in
let pattern_found = file_contains regexp file_in in let pattern_found = file_contains regexp file_in in
close_in file_in; close_in file_in;
source_map := DB.SourceFileMap.add source_file pattern_found !source_map; source_map := DB.SourceFileMap.add source_file pattern_found !source_map;
pattern_found pattern_found
with Sys_error _ -> false with Sys_error _ -> false
end end
module type MATCHABLE_JSON = sig module type MATCHABLE_JSON = sig
@ -358,20 +358,20 @@ let create_filters analyzer =
let test () = let test () =
Config.project_root := Some (Sys.getcwd ()); Config.project_root := Some (Sys.getcwd ());
let filters = let filters =
IList.map (fun analyzer -> (analyzer, create_filters analyzer)) Utils.analyzers in IList.map (fun analyzer -> (analyzer, create_filters analyzer)) analyzers in
let matching_analyzers path = let matching_analyzers path =
IList.fold_left IList.fold_left
(fun l (a, f) -> if f.path_filter path then a:: l else l) (fun l (a, f) -> if f.path_filter path then a:: l else l)
[] filters in [] filters in
Utils.directory_iter directory_iter
(fun path -> (fun path ->
if DB.is_source_file path then if DB.is_source_file path then
let source_file = (DB.source_file_from_string path) in let source_file = (DB.source_file_from_string path) in
let matching = matching_analyzers source_file in let matching = matching_analyzers source_file in
if matching <> [] then if matching <> [] then
let matching_s = let matching_s =
Utils.join_strings ", " join_strings ", "
(IList.map Utils.string_of_analyzer matching) in (IList.map string_of_analyzer matching) in
Logging.stderr "%s -> {%s}@." Logging.stderr "%s -> {%s}@."
(DB.source_file_to_rel_path source_file) (DB.source_file_to_rel_path source_file)
matching_s) matching_s)

@ -34,7 +34,7 @@ type filters =
val do_not_filter : filters val do_not_filter : filters
(** Create filters based on the config file *) (** Create filters based on the config file *)
val create_filters : Utils.analyzer -> filters val create_filters : analyzer -> filters
module NeverReturnNull : sig module NeverReturnNull : sig
type matcher = DB.source_file -> Procname.t -> bool type matcher = DB.source_file -> Procname.t -> bool

@ -457,7 +457,7 @@ module ProcsCsv = struct
pp "%s," sv.vrank; pp "%s," sv.vrank;
pp "%d," sv.vin_calls; pp "%d," sv.vin_calls;
pp "%d," sv.vout_calls; pp "%d," sv.vout_calls;
pp "%s," sv.vproof_trace; pp "%s@\n" sv.vproof_trace;
end end
module ProcsXml = struct module ProcsXml = struct
@ -540,7 +540,7 @@ module BugsCsv = struct
let qualifier_tag_xml = let qualifier_tag_xml =
let xml_node = Io_infer.Xml.create_tree Io_infer.Xml.tag_qualifier_tags [] (error_desc_to_xml_tags error_desc) in let xml_node = Io_infer.Xml.create_tree Io_infer.Xml.tag_qualifier_tags [] (error_desc_to_xml_tags error_desc) in
let p fmt () = F.fprintf fmt "%a" (Io_infer.Xml.pp_document false) xml_node in let p fmt () = F.fprintf fmt "%a" (Io_infer.Xml.pp_document false) xml_node in
let s = Utils.pp_to_string p () in let s = pp_to_string p () in
Escape.escape_csv s in Escape.escape_csv s in
let kind = Exceptions.err_kind_string ekind in let kind = Exceptions.err_kind_string ekind in
let type_str = Localise.to_string error_name in let type_str = Localise.to_string error_name in

@ -669,9 +669,7 @@ let extract_specs tenv pdesc pathset : Prop.normal Specs.spec list =
let pplist = Paths.PathSet.elements pathset in let pplist = Paths.PathSet.elements pathset in
let f (prop, path) = let f (prop, path) =
let _, prop' = Cfg.remove_locals_formals pdesc prop in let _, prop' = Cfg.remove_locals_formals pdesc prop in
(* let () = L.out "@.BEFORE abs:@.$%a@." (Prop.pp_prop Utils.pe_text) prop' in *)
let prop'' = Abs.abstract pname tenv prop' in let prop'' = Abs.abstract pname tenv prop' in
(* let () = L.out "@.AFTER abs:@.$%a@." (Prop.pp_prop Utils.pe_text) prop'' in *)
let pre, post = Prop.extract_spec prop'' in let pre, post = Prop.extract_spec prop'' in
let pre' = Prop.normalize (Prop.prop_sub sub pre) in let pre' = Prop.normalize (Prop.prop_sub sub pre) in
if !Config.curr_language = Config.Java && Cfg.Procdesc.get_access pdesc <> Sil.Private then if !Config.curr_language = Config.Java && Cfg.Procdesc.get_access pdesc <> Sil.Private then
@ -1057,7 +1055,7 @@ let report_runtime_exceptions tenv pdesc summary =
let report (pre, runtime_exception) = let report (pre, runtime_exception) =
if should_report pre then if should_report pre then
let pre_str = let pre_str =
Utils.pp_to_string (Prop.pp_prop pe_text) (Specs.Jprop.to_prop pre) in pp_to_string (Prop.pp_prop pe_text) (Specs.Jprop.to_prop pre) in
let exn_desc = Localise.java_unchecked_exn_desc pname runtime_exception pre_str in let exn_desc = Localise.java_unchecked_exn_desc pname runtime_exception pre_str in
let exn = Exceptions.Java_runtime_exception (runtime_exception, pre_str, exn_desc) in let exn = Exceptions.Java_runtime_exception (runtime_exception, pre_str, exn_desc) in
Reporting.log_error pname ~pre: (Some (Specs.Jprop.to_prop pre)) exn in Reporting.log_error pname ~pre: (Some (Specs.Jprop.to_prop pre)) exn in
@ -1116,7 +1114,7 @@ let analyze_proc exe_env (proc_name: Procname.t) : Specs.summary =
| None -> assert false in | None -> assert false in
reset_global_values proc_desc; reset_global_values proc_desc;
let go, get_results = perform_analysis_phase cfg tenv proc_name proc_desc in let go, get_results = perform_analysis_phase cfg tenv proc_name proc_desc in
let res = Fork.Timeout.exe_timeout (Specs.get_iterations proc_name) go () in let res = Timeout.exe_timeout go () in
let specs, phase = get_results () in let specs, phase = get_results () in
let elapsed = Unix.gettimeofday () -. init_time in let elapsed = Unix.gettimeofday () -. init_time in
let prev_summary = Specs.get_summary_unsafe "analyze_proc" proc_name in let prev_summary = Specs.get_summary_unsafe "analyze_proc" proc_name in

@ -11,24 +11,51 @@
(** Module to handle IO. Includes html and xml modules. *) (** Module to handle IO. Includes html and xml modules. *)
module Html : sig module Html : sig
val close : Unix.file_descr * Format.formatter -> unit (** Close an Html file *) (** Close an Html file *)
val create : DB.Results_dir.path_kind -> DB.Results_dir.path -> Unix.file_descr * Format.formatter (** Create a new html file *) val close : Unix.file_descr * Format.formatter -> unit
val modified_during_analysis : DB.Results_dir.path -> bool (** Return true if the html file was modified since the beginning of the analysis *)
val open_out : DB.Results_dir.path -> Unix.file_descr * Format.formatter (** Open an Html file to append data *)
val pp_line_link : ?with_name: bool -> ?text: (string option) -> DB.Results_dir.path -> Format.formatter -> int -> unit (** Print an html link to the given line number of the current source file *)
val pp_hline : Format.formatter -> unit -> unit (** Print a horizontal line *)
val pp_end_color : Format.formatter -> unit -> unit (** Print end color *)
(** [pp_node_link path_to_root description isvisited isproof fmt id] prints an html link to the given node. (** Create a new html file *)
val create :
DB.Results_dir.path_kind -> DB.Results_dir.path -> Unix.file_descr * Format.formatter
(** Return true if the html file was modified since the beginning of the analysis *)
val modified_during_analysis : DB.Results_dir.path -> bool
(** Open an Html file to append data *)
val open_out : DB.Results_dir.path -> Unix.file_descr * Format.formatter
(** Print an html link to the given line number of the current source file *)
val pp_line_link :
?with_name: bool -> ?text: (string option) ->
DB.Results_dir.path -> Format.formatter -> int -> unit
(** Print a horizontal line *)
val pp_hline : Format.formatter -> unit -> unit
(** Print end color *)
val pp_end_color : Format.formatter -> unit -> unit
(** [pp_node_link path_to_root description isvisited isproof fmt id]
prints an html link to the given node.
[path_to_root] is the path to the dir for the procedure in the spec db. [path_to_root] is the path to the dir for the procedure in the spec db.
[description] is a string description. [description] is a string description.
[is_visited] indicates whether the node should be active or greyed out. [is_visited] indicates whether the node should be active or greyed out.
[is_proof] indicates whether the node is part of a proof and should be green. [is_proof] indicates whether the node is part of a proof and should be green.
[id] is the node identifier. *) [id] is the node identifier. *)
val pp_node_link : DB.Results_dir.path -> string -> int list -> int list -> int list -> bool -> bool -> Format.formatter -> int -> unit val pp_node_link :
val pp_proc_link : DB.Results_dir.path -> Procname.t -> Format.formatter -> string -> unit (** Print an html link to the given proc *) DB.Results_dir.path -> string -> int list -> int list -> int list ->
val pp_session_link : ?with_name: bool -> string list -> Format.formatter -> int * int * int -> unit (** Print an html link given node id and session *) bool -> bool -> Format.formatter -> int -> unit
val pp_start_color : Format.formatter -> Utils.color -> unit (** Print start color *)
(** Print an html link to the given proc *)
val pp_proc_link :
DB.Results_dir.path -> Procname.t -> Format.formatter -> string -> unit
(** Print an html link given node id and session *)
val pp_session_link :
?with_name: bool -> string list -> Format.formatter -> int * int * int -> unit
(** Print start color *)
val pp_start_color : Format.formatter -> color -> unit
end end
(** Create and print xml trees *) (** Create and print xml trees *)

@ -20,7 +20,7 @@ val convert_string : string -> string
val pp_string : style -> Format.formatter -> string -> unit val pp_string : style -> Format.formatter -> string -> unit
(** Print color command *) (** Print color command *)
val pp_color : Format.formatter -> Utils.color -> unit val pp_color : Format.formatter -> color -> unit
(** Prelude for a latex file with the given author and title and table of contents flag *) (** Prelude for a latex file with the given author and title and table of contents flag *)
val pp_begin : Format.formatter -> (string * string * bool) -> unit val pp_begin : Format.formatter -> (string * string * bool) -> unit

@ -15,8 +15,8 @@ module F = Format
let trace () = Config.from_env_variable "INFER_TRACE_ONDEMAND" let trace () = Config.from_env_variable "INFER_TRACE_ONDEMAND"
let one_cluster_per_procedure () = false let one_cluster_per_procedure () = false
let () = Config.ondemand_enabled := let () =
Config.from_env_variable "INFER_ONDEMAND" Config.ondemand_enabled := true
let across_files () = true let across_files () = true
@ -27,7 +27,7 @@ let ondemand_file () = Config.get_env_variable "INFER_ONDEMAND_FILE"
let read_dirs_to_analyze () = let read_dirs_to_analyze () =
let lines_opt = match ondemand_file () with let lines_opt = match ondemand_file () with
| None -> None | None -> None
| Some fname -> Utils.read_file fname in | Some fname ->read_file fname in
match lines_opt with match lines_opt with
| None -> | None ->
None None
@ -98,6 +98,7 @@ type global_state =
} }
let save_global_state () = let save_global_state () =
Timeout.suspend_existing_timeout ();
{ {
abs_val = !Config.abs_val; abs_val = !Config.abs_val;
abstraction_rules = Abs.get_current_rules (); abstraction_rules = Abs.get_current_rules ();
@ -117,7 +118,8 @@ let restore_global_state st =
Config.footprint := st.footprint_mode; Config.footprint := st.footprint_mode;
Printer.html_formatter := st.html_formatter; Printer.html_formatter := st.html_formatter;
Ident.NameGenerator.set_current st.name_generator; Ident.NameGenerator.set_current st.name_generator;
State.restore_state st.symexec_state State.restore_state st.symexec_state;
Timeout.resume_previous_timeout ()
let do_analysis curr_pdesc callee_pname = let do_analysis curr_pdesc callee_pname =
let curr_pname = Cfg.Procdesc.get_proc_name curr_pdesc in let curr_pname = Cfg.Procdesc.get_proc_name curr_pdesc in
@ -164,9 +166,10 @@ let do_analysis curr_pdesc callee_pname =
postprocess (); postprocess ();
restore_global_state old_state; restore_global_state old_state;
with e -> with e ->
L.stderr "ONDEMAND EXCEPTION %a %s %s@." L.stderr "@.ONDEMAND EXCEPTION %a %s@.@.CALL STACK@.%s@.BACK TRACE@.%s@."
Procname.pp callee_pname Procname.pp callee_pname
(Printexc.to_string e) (Printexc.to_string e)
(Printexc.raw_backtrace_to_string (Printexc.get_callstack 1000))
(Printexc.get_backtrace ()); (Printexc.get_backtrace ());
restore_global_state old_state; restore_global_state old_state;
raise e in raise e in

@ -369,7 +369,8 @@ let java_is_vararg = function
let is_constructor = function let is_constructor = function
| Java_method js -> js.method_name = "<init>" | Java_method js -> js.method_name = "<init>"
| ObjC_Cpp_method name -> | ObjC_Cpp_method name ->
(name.method_name = "new") || Utils.string_is_prefix "init" name.method_name (name.method_name = "new") ||
string_is_prefix "init" name.method_name
| _ -> false | _ -> false
(** [is_objc_dealloc pname] returns true if [pname] is the dealloc method in Objective-C *) (** [is_objc_dealloc pname] returns true if [pname] is the dealloc method in Objective-C *)

@ -31,39 +31,47 @@ val edge_get_source : edge -> node
(** Return the successor nodes of the edge *) (** Return the successor nodes of the edge *)
val edge_get_succs : edge -> node list val edge_get_succs : edge -> node list
(** [edge_from_source g n footprint_part is_hpred] finds and edge with the given source [n] in prop [g]. (** [edge_from_source g n footprint_part is_hpred] finds and edge
[footprint_part] indicates whether to search the edge in the footprint part, and [is_pred] whether it is an hpred edge. *) with the given source [n] in prop [g].
[footprint_part] indicates whether to search the edge in the footprint part,
and [is_pred] whether it is an hpred edge. *)
val edge_from_source : t -> node -> bool -> bool -> edge option val edge_from_source : t -> node -> bool -> bool -> edge option
(** [get_succs g n footprint_part is_hpred] returns the successor nodes of [n] in [g]. (** [get_succs g n footprint_part is_hpred] returns the successor nodes of [n] in [g].
[footprint_part] indicates whether to search the successors in the footprint part, and [is_pred] whether to follow hpred edges. *) [footprint_part] indicates whether to search the successors in the footprint part,
and [is_pred] whether to follow hpred edges. *)
val get_succs : t -> node -> bool -> bool -> node list val get_succs : t -> node -> bool -> bool -> node list
(** [get_edges footprint_part g] returns the list of edges in [g], in the footprint part if [fotprint_part] is true *) (** [get_edges footprint_part g] returns the list of edges in [g],
in the footprint part if [fotprint_part] is true *)
val get_edges : bool -> t -> edge list val get_edges : bool -> t -> edge list
(** [contains_edge footprint_part g e] returns true if the graph [g] contains edge [e], (** [contains_edge footprint_part g e] returns true if the graph [g] contains edge [e],
searching the footprint part if [footprint_part] is true. *) searching the footprint part if [footprint_part] is true. *)
val contains_edge : bool -> t -> edge -> bool val contains_edge : bool -> t -> edge -> bool
(** [iter_edges footprint_part f g] iterates function [f] on the edges in [g] in the same order as returned by [get_edges]; (** [iter_edges footprint_part f g] iterates function [f] on the edges in [g]
in the same order as returned by [get_edges];
if [footprint_part] is true the edges are taken from the footprint part. *) if [footprint_part] is true the edges are taken from the footprint part. *)
val iter_edges : bool -> (edge -> unit) -> t -> unit val iter_edges : bool -> (edge -> unit) -> t -> unit
(** Graph annotated with the differences w.r.t. a previous graph *) (** Graph annotated with the differences w.r.t. a previous graph *)
type diff type diff
(** [compute_diff default_color oldgraph newgraph] returns the list of edges which are only in [newgraph] *) (** [compute_diff default_color oldgraph newgraph] returns the list of edges
which are only in [newgraph] *)
val compute_diff : color -> t -> t -> diff val compute_diff : color -> t -> t -> diff
(** [diff_get_colormap footprint_part diff] returns the colormap of a computed diff, (** [diff_get_colormap footprint_part diff] returns the colormap of a computed diff,
selecting the footprint colormap if [footprint_part] is true. *) selecting the footprint colormap if [footprint_part] is true. *)
val diff_get_colormap : bool -> diff -> Utils.colormap val diff_get_colormap : bool -> diff -> colormap
(** Print a list of propositions, prepending each one with the given string, (** Print a list of propositions, prepending each one with the given string,
If !Config.pring_using_diff is true, print the diff w.r.t. the given prop, If !Config.pring_using_diff is true, print the diff w.r.t. the given prop,
extracting its local stack vars if the boolean is true. *) extracting its local stack vars if the boolean is true. *)
val pp_proplist : printenv -> string -> (Prop.normal Prop.t * bool) -> Format.formatter -> Prop.normal Prop.t list -> unit val pp_proplist :
printenv -> string -> (Prop.normal Prop.t * bool) ->
Format.formatter -> Prop.normal Prop.t list -> unit
(** dump a prop list coming form the given initial prop *) (** dump a prop list coming form the given initial prop *)
val d_proplist : 'a Prop.t -> 'b Prop.t list -> unit val d_proplist : 'a Prop.t -> 'b Prop.t list -> unit

@ -693,14 +693,13 @@ let check_lt_normalized prop e1 e2 =
| Some upper1, Some lower2 -> Sil.Int.leq upper1 lower2 in | Some upper1, Some lower2 -> Sil.Int.leq upper1 lower2 in
(upper_lower_check ()) || (Inequalities.check_lt ineq e1 e2) (upper_lower_check ()) || (Inequalities.check_lt ineq e1 e2)
(* given an atom and a proposition returns a unique identifier. *) (** Given an atom and a proposition returns a unique identifier.
(* We use this to distinguish among different queries *) We use this to distinguish among different queries. *)
let get_smt_key a p = let get_smt_key a p =
let tmp_filename = Filename.temp_file "smt_query" ".cns" in let tmp_filename = Filename.temp_file "smt_query" ".cns" in
let outc_tmp = open_out tmp_filename in let outc_tmp = open_out tmp_filename in
let fmt_tmp = F.formatter_of_out_channel outc_tmp in let fmt_tmp = F.formatter_of_out_channel outc_tmp in
let pe = Utils.pe_text in let () = F.fprintf fmt_tmp "%a%a" (Sil.pp_atom pe_text) a (Prop.pp_prop pe_text) p in
let () = F.fprintf fmt_tmp "%a%a" (Sil.pp_atom pe) a (Prop.pp_prop pe) p in
close_out outc_tmp; close_out outc_tmp;
Digest.to_hex (Digest.file tmp_filename) Digest.to_hex (Digest.file tmp_filename)
@ -709,20 +708,23 @@ let check_atom prop a0 =
let a = Prop.atom_normalize_prop prop a0 in let a = Prop.atom_normalize_prop prop a0 in
let prop_no_fp = Prop.replace_sigma_footprint [] (Prop.replace_pi_footprint [] prop) in let prop_no_fp = Prop.replace_sigma_footprint [] (Prop.replace_pi_footprint [] prop) in
if !Config.smt_output then begin if !Config.smt_output then begin
let pe = Utils.pe_text in
let key = get_smt_key a prop_no_fp in let key = get_smt_key a prop_no_fp in
let key_filename = DB.Results_dir.path_to_filename DB.Results_dir.Abs_source_dir [(key ^ ".cns")] in let key_filename =
DB.Results_dir.path_to_filename DB.Results_dir.Abs_source_dir [(key ^ ".cns")] in
let outc = open_out (DB.filename_to_string key_filename) in let outc = open_out (DB.filename_to_string key_filename) in
let fmt = F.formatter_of_out_channel outc in let fmt = F.formatter_of_out_channel outc in
L.d_str ("ID: "^key); L.d_ln (); L.d_str ("ID: "^key); L.d_ln ();
L.d_str "CHECK_ATOM_BOUND: "; Sil.d_atom a; L.d_ln (); L.d_str "CHECK_ATOM_BOUND: "; Sil.d_atom a; L.d_ln ();
L.d_str "WHERE:"; L.d_ln(); Prop.d_prop prop_no_fp; L.d_ln (); L.d_ln (); L.d_str "WHERE:"; L.d_ln(); Prop.d_prop prop_no_fp; L.d_ln (); L.d_ln ();
let () = F.fprintf fmt "ID: %s @\nCHECK_ATOM_BOUND: %a@\nWHERE:@\n%a" key (Sil.pp_atom pe) a (Prop.pp_prop pe) prop_no_fp in F.fprintf fmt "ID: %s @\nCHECK_ATOM_BOUND: %a@\nWHERE:@\n%a"
key (Sil.pp_atom pe_text) a (Prop.pp_prop pe_text) prop_no_fp;
close_out outc; close_out outc;
end; end;
match a with match a with
| Sil.Aeq (Sil.BinOp (Sil.Le, e1, e2), Sil.Const (Sil.Cint i)) when Sil.Int.isone i -> check_le_normalized prop e1 e2 | Sil.Aeq (Sil.BinOp (Sil.Le, e1, e2), Sil.Const (Sil.Cint i))
| Sil.Aeq (Sil.BinOp (Sil.Lt, e1, e2), Sil.Const (Sil.Cint i)) when Sil.Int.isone i -> check_lt_normalized prop e1 e2 when Sil.Int.isone i -> check_le_normalized prop e1 e2
| Sil.Aeq (Sil.BinOp (Sil.Lt, e1, e2), Sil.Const (Sil.Cint i))
when Sil.Int.isone i -> check_lt_normalized prop e1 e2
| Sil.Aeq (e1, e2) -> check_equal prop e1 e2 | Sil.Aeq (e1, e2) -> check_equal prop e1 e2
| Sil.Aneq (e1, e2) -> check_disequal prop e1 e2 | Sil.Aneq (e1, e2) -> check_disequal prop e1 e2
@ -765,7 +767,8 @@ let check_inconsistency_two_hpreds prop =
| (Sil.Hdllseg (Sil.Lseg_NE, _, iF, _, _, iB, _) as hpred) :: sigma_rest -> | (Sil.Hdllseg (Sil.Lseg_NE, _, iF, _, _, iB, _) as hpred) :: sigma_rest ->
if Sil.exp_equal iF e || Sil.exp_equal iB e then true if Sil.exp_equal iF e || Sil.exp_equal iB e then true
else f e (hpred:: sigma_seen) sigma_rest else f e (hpred:: sigma_seen) sigma_rest
| Sil.Hlseg (Sil.Lseg_PE, _, e1, Sil.Const (Sil.Cint i), _) as hpred :: sigma_rest when Sil.Int.iszero i -> | Sil.Hlseg (Sil.Lseg_PE, _, e1, Sil.Const (Sil.Cint i), _) as hpred :: sigma_rest
when Sil.Int.iszero i ->
if Sil.exp_equal e1 e then true if Sil.exp_equal e1 e then true
else f e (hpred:: sigma_seen) sigma_rest else f e (hpred:: sigma_seen) sigma_rest
| Sil.Hlseg (Sil.Lseg_PE, _, e1, e2, _) as hpred :: sigma_rest -> | Sil.Hlseg (Sil.Lseg_PE, _, e1, e2, _) as hpred :: sigma_rest ->
@ -811,14 +814,19 @@ let check_inconsistency_base prop =
let inconsistent_ptsto _ = let inconsistent_ptsto _ =
check_allocatedness prop Sil.exp_zero in check_allocatedness prop Sil.exp_zero in
let inconsistent_this_self_var () = let inconsistent_this_self_var () =
let procdesc = Cfg.Node.get_proc_desc (State.get_node ()) in let procdesc =
let procedure_attr = Cfg.Procdesc.get_attributes procdesc in Cfg.Node.get_proc_desc (State.get_node ()) in
let is_java_this pvar = !Config.curr_language = Config.Java && Sil.pvar_is_this pvar in let procedure_attr =
let is_objc_instance_self pvar = !Config.curr_language = Config.C_CPP && Cfg.Procdesc.get_attributes procdesc in
Sil.pvar_get_name pvar = Mangled.from_string "self" && let is_java_this pvar =
procedure_attr.ProcAttributes.is_objc_instance_method in !Config.curr_language = Config.Java && Sil.pvar_is_this pvar in
let is_cpp_this pvar = !Config.curr_language = Config.C_CPP && Sil.pvar_is_this pvar && let is_objc_instance_self pvar =
procedure_attr.ProcAttributes.is_cpp_instance_method in !Config.curr_language = Config.C_CPP &&
Sil.pvar_get_name pvar = Mangled.from_string "self" &&
procedure_attr.ProcAttributes.is_objc_instance_method in
let is_cpp_this pvar =
!Config.curr_language = Config.C_CPP && Sil.pvar_is_this pvar &&
procedure_attr.ProcAttributes.is_cpp_instance_method in
let do_hpred = function let do_hpred = function
| Sil.Hpointsto (Sil.Lvar pv, Sil.Eexp (e, _), _) -> | Sil.Hpointsto (Sil.Lvar pv, Sil.Eexp (e, _), _) ->
Sil.exp_equal e Sil.exp_zero && Sil.exp_equal e Sil.exp_zero &&

@ -72,7 +72,7 @@ let pp_item_annotation fmt item_annotation =
let item_annotation_to_string ann = let item_annotation_to_string ann =
let pp fmt () = pp_item_annotation fmt ann in let pp fmt () = pp_item_annotation fmt ann in
Utils.pp_to_string pp () pp_to_string pp ()
(** Pretty print a method annotation. *) (** Pretty print a method annotation. *)
let pp_method_annotation s fmt (ia, ial) = let pp_method_annotation s fmt (ia, ial) =
@ -551,7 +551,7 @@ end = struct
else F.fprintf f "%Ld" n else F.fprintf f "%Ld" n
let to_string i = let to_string i =
Utils.pp_to_string pp i pp_to_string pp i
end end
(** Flags for a procedure call *) (** Flags for a procedure call *)
@ -2072,8 +2072,8 @@ and pp_exp_full pe f e =
and exp_to_string e = pp_to_string (pp_exp pe_text) e and exp_to_string e = pp_to_string (pp_exp pe_text) e
let typ_to_string typ = let typ_to_string typ =
let pp fmt () = pp_typ_full Utils.pe_text fmt typ in let pp fmt () = pp_typ_full pe_text fmt typ in
Utils.pp_to_string pp () pp_to_string pp ()
(** dump a type with all the details. *) (** dump a type with all the details. *)
let d_typ_full (t: typ) = L.add_print_action (L.PTtyp_full, Obj.repr t) let d_typ_full (t: typ) = L.add_print_action (L.PTtyp_full, Obj.repr t)

@ -261,7 +261,10 @@ module CallStats = struct (** module for tracing stats of function calls *)
let s2 = if in_footprint then "FP" else "RE" in let s2 = if in_footprint then "FP" else "RE" in
s1 ^ ":" ^ s2 s1 ^ ":" ^ s2
let pp_trace fmt tr = Utils.pp_seq (fun fmt x -> F.fprintf fmt "%s" (tr_elem_str x)) fmt (IList.rev tr) let pp_trace fmt tr =
pp_seq
(fun fmt x -> F.fprintf fmt "%s" (tr_elem_str x))
fmt (IList.rev tr)
let iter f t = let iter f t =
let elems = ref [] in let elems = ref [] in
@ -723,19 +726,6 @@ let get_flag proc_name key =
Some (Hashtbl.find proc_flags key) Some (Hashtbl.find proc_flags key)
with Not_found -> None with Not_found -> None
(** Get the iterations associated to the procedure if any, or the default timeout from the
command line *)
let get_iterations proc_name =
match get_summary proc_name with
| None ->
raise (Failure ("Specs.get_iterations: " ^ (Procname.to_string proc_name) ^ "Not_found"))
| Some summary ->
let proc_flags = summary.attributes.ProcAttributes.proc_flags in
try
let time_str = Hashtbl.find proc_flags proc_flag_iterations in
Pervasives.int_of_string time_str
with exn when exn_not_failure exn -> !iterations_cmdline
(** Return the specs and parameters for the proc in the spec table *) (** Return the specs and parameters for the proc in the spec table *)
let get_specs_formals proc_name = let get_specs_formals proc_name =
match get_summary proc_name with match get_summary proc_name with

@ -177,9 +177,6 @@ val get_formals : summary -> (Mangled.t * Sil.typ) list
(** Get the flag with the given key for the procedure, if any *) (** Get the flag with the given key for the procedure, if any *)
val get_flag : Procname.t -> string -> string option val get_flag : Procname.t -> string -> string option
(** Get the iterations associated to the procedure if any, or the default timeout from the command line *)
val get_iterations : Procname.t -> int
(** Return the current phase for the proc *) (** Return the current phase for the proc *)
val get_phase : Procname.t -> phase val get_phase : Procname.t -> phase

@ -16,15 +16,17 @@ type splitting
(** Remove constant string or class from a prop *) (** Remove constant string or class from a prop *)
val remove_constant_string_class : 'a Prop.t -> Prop.normal Prop.t val remove_constant_string_class : 'a Prop.t -> Prop.normal Prop.t
(** Check if the attribute change is a mismatch between a kind of allocation and a different kind of deallocation *) (** Check if the attribute change is a mismatch between a kind of allocation
and a different kind of deallocation *)
val check_attr_dealloc_mismatch : Sil.attribute -> Sil.attribute -> unit val check_attr_dealloc_mismatch : Sil.attribute -> Sil.attribute -> unit
(** Check whether a sexp contains a dereference without null check, and return the line number and path position *) (** Check whether a sexp contains a dereference without null check,
and return the line number and path position *)
val find_dereference_without_null_check_in_sexp : Sil.strexp -> (int * Sil.path_pos) option val find_dereference_without_null_check_in_sexp : Sil.strexp -> (int * Sil.path_pos) option
(** raise a cast exception *) (** raise a cast exception *)
val raise_cast_exception : val raise_cast_exception :
Utils.ml_loc -> Procname.t option -> Sil.exp -> Sil.exp -> Sil.exp -> 'a ml_loc -> Procname.t option -> Sil.exp -> Sil.exp -> Sil.exp -> 'a
(** check if a prop is an exception *) (** check if a prop is an exception *)
val prop_is_exn : Procname.t -> 'a Prop.t -> bool val prop_is_exn : Procname.t -> 'a Prop.t -> bool

@ -0,0 +1,126 @@
(*
* Copyright (c) 2016 - 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 L = Logging
module F = Format
(** Handle timeout events *)
(** status of a timeout instance *)
type status =
{
(** Seconds remaining in the current timeout *)
seconds_remaining : float;
(** Internal State of SymOp *)
symop_state : SymOp.t
}
(** stack of suspended timeout instances *)
type timeouts_stack =
status list ref
module GlobalState = struct
let stack : timeouts_stack =
ref []
let pop () =
match !stack with
| top_status :: l ->
stack := l;
Some top_status
| [] ->
None
let push status =
stack := status :: !stack
end
let set_alarm nsecs =
match Config.os_type with
| Config.Unix | Config.Cygwin ->
ignore (Unix.setitimer Unix.ITIMER_REAL
{ Unix.it_interval = 3.0; (* try again after 3 seconds if the signal is lost *)
Unix.it_value = nsecs })
| Config.Win32 ->
SymOp.set_wallclock_alarm nsecs
let unset_alarm () =
match Config.os_type with
| Config.Unix | Config.Cygwin ->
set_alarm 0.0
| Config.Win32 ->
SymOp.unset_wallclock_alarm ()
let get_seconds_remaining () =
match Config.os_type with
| Config.Unix | Config.Cygwin ->
(Unix.getitimer Unix.ITIMER_REAL).Unix.it_value
| Config.Win32 ->
SymOp.get_remaining_wallclock_time ()
let get_current_status () =
let seconds_remaining = get_seconds_remaining () in
let symop_state = SymOp.save_state () in
{
seconds_remaining;
symop_state;
}
let set_status status =
SymOp.restore_state status.symop_state;
set_alarm status.seconds_remaining
let timeout_action _ =
unset_alarm ();
raise (Analysis_failure_exe (FKtimeout))
let () = begin
match Config.os_type with
| Config.Unix | Config.Cygwin ->
Sys.set_signal Sys.sigvtalrm (Sys.Signal_handle timeout_action);
Sys.set_signal Sys.sigalrm (Sys.Signal_handle timeout_action)
| Config.Win32 ->
SymOp.set_wallclock_timeout_handler timeout_action;
(* use the Gc alarm for periodic timeout checks *)
ignore (Gc.create_alarm SymOp.check_wallclock_alarm)
end
let unwind () =
unset_alarm ();
SymOp.unset_alarm ();
GlobalState.pop ()
let suspend_existing_timeout () =
let current_status = get_current_status () in
unset_alarm ();
GlobalState.push current_status
let resume_previous_timeout () =
let status_opt = unwind () in
Option.may set_status status_opt
let exe_timeout f x =
let suspend_existing_timeout_and_start_new_one () =
suspend_existing_timeout ();
set_alarm (get_timeout_seconds ());
SymOp.set_alarm () in
try
suspend_existing_timeout_and_start_new_one ();
f x;
resume_previous_timeout ();
None
with
| Analysis_failure_exe kind ->
resume_previous_timeout ();
Errdesc.warning_err (State.get_loc ()) "TIMEOUT: %a@." pp_failure_kind kind;
Some kind
| exe ->
resume_previous_timeout ();
raise exe

@ -0,0 +1,19 @@
(*
* Copyright (c) 2016 - 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.
*)
(** Handle timeout events *)
(** Execute the function up to a given timeout. *)
val exe_timeout : ('a -> unit) -> 'a -> failure_kind option
(** Resume a previously suspended timeout. *)
val resume_previous_timeout : unit -> unit
(** Suspend the current timeout. It must be resumed later. *)
val suspend_existing_timeout : unit -> unit

@ -277,9 +277,9 @@ let pp_failure_kind fmt = function
let symops_timeout, seconds_timeout = let symops_timeout, seconds_timeout =
(* default timeout and long timeout are the same for now, but this will change shortly *) (* default timeout and long timeout are the same for now, but this will change shortly *)
let default_symops_timeout = 333 in let default_symops_timeout = 333 in
let default_seconds_timeout = 10 in let default_seconds_timeout = 10.0 in
let long_symops_timeout = 1000 in let long_symops_timeout = 1000 in
let long_seconds_timeout = 30 in let long_seconds_timeout = 30.0 in
if Config.analyze_models then if Config.analyze_models then
(* use longer timeouts when analyzing models *) (* use longer timeouts when analyzing models *)
long_symops_timeout, long_seconds_timeout long_symops_timeout, long_seconds_timeout
@ -292,9 +292,6 @@ let symops_per_iteration = ref symops_timeout
(** number of seconds to multiply by the number of iterations, after which there is a timeout *) (** number of seconds to multiply by the number of iterations, after which there is a timeout *)
let seconds_per_iteration = ref seconds_timeout let seconds_per_iteration = ref seconds_timeout
(** timeout value from the -iterations command line option *)
let iterations_cmdline = ref 1
(** Timeout in seconds for each function *) (** Timeout in seconds for each function *)
let timeout_seconds = ref !seconds_per_iteration let timeout_seconds = ref !seconds_per_iteration
@ -304,23 +301,53 @@ let timeout_symops = ref !symops_per_iteration
(** Set the timeout values in seconds and symops, computed as a multiple of the integer parameter *) (** Set the timeout values in seconds and symops, computed as a multiple of the integer parameter *)
let set_iterations n = let set_iterations n =
timeout_symops := !symops_per_iteration * n; timeout_symops := !symops_per_iteration * n;
timeout_seconds := !seconds_per_iteration * n timeout_seconds := !seconds_per_iteration *. (float_of_int n)
let get_timeout_seconds () = !timeout_seconds let get_timeout_seconds () = !timeout_seconds
(** Count the number of symbolic operations *) (** Count the number of symbolic operations *)
module SymOp = struct module SymOp = struct
(** Number of symop's *)
let symop_count = ref 0
(** Total number of symop's since the beginning *) (** Internal state of the module *)
let symop_total = ref 0 type t =
{
(** Only throw timeout exception when alarm is active *)
mutable alarm_active : bool;
(** last wallclock set by an alarm, if any *)
mutable last_wallclock : float option;
(** Number of symop's *)
mutable symop_count : int;
(** Total number of symop's since the beginning *)
mutable symop_total : int;
(** Time in the beginning *)
mutable timer : float;
}
let initial () : t =
{
alarm_active = false;
last_wallclock = None;
symop_count = 0;
symop_total = 0;
timer = Unix.gettimeofday ();
}
(** Only throw timeout exception when alarm is active *) (** Global State *)
let alarm_active = ref false let gs : t ref = ref (initial ())
(** last wallclock set by an alarm, if any *) (** Restore the old state. *)
let last_wallclock = ref None let restore_state state =
gs := state
(** Return the old state, and revert the current state to the initial one. *)
let save_state () =
let old_state = !gs in
gs := initial ();
old_state
(** handler for the wallclock timeout *) (** handler for the wallclock timeout *)
let wallclock_timeout_handler = ref None let wallclock_timeout_handler = ref None
@ -331,65 +358,66 @@ module SymOp = struct
(** Set the wallclock alarm checked at every pay() *) (** Set the wallclock alarm checked at every pay() *)
let set_wallclock_alarm nsecs = let set_wallclock_alarm nsecs =
last_wallclock := Some (Unix.gettimeofday () +. float_of_int nsecs) !gs.last_wallclock <- Some (Unix.gettimeofday () +. nsecs)
(** Unset the wallclock alarm checked at every pay() *) (** Unset the wallclock alarm checked at every pay() *)
let unset_wallclock_alarm () = let unset_wallclock_alarm () =
last_wallclock := None !gs.last_wallclock <- None
(** if the wallclock alarm has expired, raise a timeout exception *) (** if the wallclock alarm has expired, raise a timeout exception *)
let check_wallclock_alarm () = let check_wallclock_alarm () =
match !last_wallclock, !wallclock_timeout_handler with match !gs.last_wallclock, !wallclock_timeout_handler with
| Some alarm_time, Some handler when Unix.gettimeofday () >= alarm_time -> | Some alarm_time, Some handler when Unix.gettimeofday () >= alarm_time ->
unset_wallclock_alarm (); unset_wallclock_alarm ();
handler () handler ()
| _ -> () | _ -> ()
(** Return the time remaining before the wallclock alarm expires *)
let get_remaining_wallclock_time () =
match !gs.last_wallclock with
| Some alarm_time ->
max 0.0 (alarm_time -. Unix.gettimeofday ())
| None ->
0.0
(** Return the total number of symop's since the beginning *) (** Return the total number of symop's since the beginning *)
let get_total () = !symop_total let get_total () =
!gs.symop_total
(** Reset the total number of symop's *) (** Reset the total number of symop's *)
let reset_total () = symop_total := 0 let reset_total () =
!gs.symop_total <- 0
(** timer at load time *)
let initial_time = Unix.gettimeofday ()
(** Time in the beginning *)
let timer = ref initial_time
(** Count one symop *) (** Count one symop *)
let pay () = let pay () =
incr symop_count; incr symop_total; !gs.symop_count <- !gs.symop_count + 1;
if !symop_count > !timeout_symops && !alarm_active !gs.symop_total <- !gs.symop_total + 1;
then raise (Analysis_failure_exe (FKsymops_timeout !symop_count)); if !gs.symop_count > !timeout_symops &&
!gs.alarm_active
then raise (Analysis_failure_exe (FKsymops_timeout !gs.symop_count));
check_wallclock_alarm () check_wallclock_alarm ()
(** Reset the counters *) (** Reset the counters *)
let reset () = let reset () =
symop_count := 0; !gs.symop_count <- 0;
timer := Unix.gettimeofday () !gs.timer <- Unix.gettimeofday ()
(** Reset the counter and activate the alarm *) (** Reset the counter and activate the alarm *)
let set_alarm () = let set_alarm () =
reset (); reset ();
alarm_active := true !gs.alarm_active <- true
(** De-activate the alarm *) (** De-activate the alarm *)
let unset_alarm () = let unset_alarm () =
alarm_active := false !gs.alarm_active <- false
let report_stats f symops elapsed = let report_stats f symops elapsed =
F.fprintf f "SymOp stats -- symops:%d time:%f symops/sec:%f" symops elapsed ((float_of_int symops) /. elapsed) F.fprintf f "SymOp stats -- symops:%d time:%f symops/sec:%f" symops elapsed ((float_of_int symops) /. elapsed)
(** Report the stats since the last reset *) (** Report the stats since the last reset *)
let report f () = let report f () =
let elapsed = Unix.gettimeofday () -. !timer in let elapsed = Unix.gettimeofday () -. !gs.timer in
report_stats f !symop_count elapsed report_stats f !gs.symop_count elapsed
(** Report the stats since the loading of this module *)
let report_total f () =
let elapsed = Unix.gettimeofday () -. initial_time in
report_stats f !symop_total elapsed
end end
(** Check if the lhs is a substring of the rhs. *) (** Check if the lhs is a substring of the rhs. *)
@ -879,7 +907,6 @@ type proc_flags = (string, string) Hashtbl.t
let proc_flags_empty () : proc_flags = Hashtbl.create 1 let proc_flags_empty () : proc_flags = Hashtbl.create 1
let proc_flag_iterations = "iterations"
let proc_flag_skip = "skip" let proc_flag_skip = "skip"
let proc_flag_ignore_return = "ignore_return" let proc_flag_ignore_return = "ignore_return"

@ -160,13 +160,10 @@ val initial_analysis_time : float
val symops_per_iteration : int ref val symops_per_iteration : int ref
(** number of seconds to multiply by the number of iterations, after which there is a timeout *) (** number of seconds to multiply by the number of iterations, after which there is a timeout *)
val seconds_per_iteration : int ref val seconds_per_iteration : float ref
(** timeout value from the -iterations command line option *)
val iterations_cmdline : int ref
(** Timeout in seconds for each function *) (** Timeout in seconds for each function *)
val get_timeout_seconds : unit -> int val get_timeout_seconds : unit -> float
(** Set the timeout values in seconds and symops, computed as a multiple of the integer parameter *) (** Set the timeout values in seconds and symops, computed as a multiple of the integer parameter *)
val set_iterations : int -> unit val set_iterations : int -> unit
@ -187,38 +184,47 @@ val pp_failure_kind : Format.formatter -> failure_kind -> unit
(** Count the number of symbolic operations *) (** Count the number of symbolic operations *)
module SymOp : sig module SymOp : sig
(** Internal state of the module *)
type t
(** if the wallclock alarm has expired, raise a timeout exception *)
val check_wallclock_alarm : unit -> unit
(** Return the time remaining before the wallclock alarm expires *)
val get_remaining_wallclock_time : unit -> float
(** Return the total number of symop's since the beginning *)
val get_total : unit -> int
(** Count one symop *) (** Count one symop *)
val pay : unit -> unit val pay : unit -> unit
(** Report the stats since the last reset *)
val report : Format.formatter -> unit -> unit
(** Reset the total number of symop's *)
val reset_total : unit -> unit
(** Restore the old state. *)
val restore_state : t -> unit
(** Return the old state, and revert the current state to the initial one. *)
val save_state : unit -> t
(** Reset the counter and activate the alarm *) (** Reset the counter and activate the alarm *)
val set_alarm : unit -> unit val set_alarm : unit -> unit
(** De-activate the alarm *) (** Set the wallclock alarm checked at every pay() *)
val unset_alarm : unit -> unit val set_wallclock_alarm : float -> unit
(** set the handler for the wallclock timeout *) (** set the handler for the wallclock timeout *)
val set_wallclock_timeout_handler : (unit -> unit) -> unit val set_wallclock_timeout_handler : (unit -> unit) -> unit
(** Set the wallclock alarm checked at every pay() *) (** De-activate the alarm *)
val set_wallclock_alarm : int -> unit val unset_alarm : unit -> unit
(** Unset the wallclock alarm checked at every pay() *) (** Unset the wallclock alarm checked at every pay() *)
val unset_wallclock_alarm : unit -> unit val unset_wallclock_alarm : unit -> unit
(** if the wallclock alarm has expired, raise a timeout exception *)
val check_wallclock_alarm : unit -> unit
(** Return the total number of symop's since the beginning *)
val get_total : unit -> int
(** Reset the total number of symop's *)
val reset_total : unit -> unit
(** Report the stats since the last reset *)
val report : Format.formatter -> unit -> unit
(** Report the stats since the loading of this module *)
val report_total : Format.formatter -> unit -> unit
end end
module Arg : sig module Arg : sig
@ -328,7 +334,6 @@ end
type proc_flags = (string, string) Hashtbl.t type proc_flags = (string, string) Hashtbl.t
(** keys for proc_flags *) (** keys for proc_flags *)
val proc_flag_iterations : string (** key to specify procedure-specific iterations *)
val proc_flag_skip : string (** key to specify that a function should be treated as a skip function *) val proc_flag_skip : string (** key to specify that a function should be treated as a skip function *)
val proc_flag_ignore_return : string (** key to specify that it is OK to ignore the return value *) val proc_flag_ignore_return : string (** key to specify that it is OK to ignore the return value *)

@ -14,7 +14,7 @@ let patch = @INFER_PATCH@
let commit = "@INFER_GIT_COMMIT@" let commit = "@INFER_GIT_COMMIT@"
let branch = "@INFER_GIT_BRANCH@" let branch = "@INFER_GIT_BRANCH@"
let is_release = Utils.string_equal "@INFER_IS_RELEASE@" "yes" let is_release = string_equal "@INFER_IS_RELEASE@" "yes"
let tag = Printf.sprintf "v%d.%d.%d" major minor patch let tag = Printf.sprintf "v%d.%d.%d" major minor patch
let versionString = let versionString =

@ -95,7 +95,7 @@ let curr_class_compare curr_class1 curr_class2 =
| ContextCls (_, _, _), _ -> -1 | ContextCls (_, _, _), _ -> -1
| _, ContextCls (_, _, _) -> 1 | _, ContextCls (_, _, _) -> 1
| ContextCategory (name1, cls1), ContextCategory (name2, cls2) -> | ContextCategory (name1, cls1), ContextCategory (name2, cls2) ->
Utils.pair_compare String.compare String.compare (name1, cls1) (name2, cls2) pair_compare String.compare String.compare (name1, cls1) (name2, cls2)
| ContextCategory (_, _), _ -> -1 | ContextCategory (_, _), _ -> -1
| _, ContextCategory (_, _) -> 1 | _, ContextCategory (_, _) -> 1
| ContextProtocol name1, ContextProtocol name2 -> | ContextProtocol name1, ContextProtocol name2 ->

@ -94,10 +94,10 @@ struct
L.err "AST Element> %s IN FILE> %s @.@." pointer !CFrontend_config.json L.err "AST Element> %s IN FILE> %s @.@." pointer !CFrontend_config.json
let print_nodes nodes = let print_nodes nodes =
IList.iter (fun node -> print_endline (Cfg.Node.get_description Utils.pe_text node)) nodes IList.iter (fun node -> print_endline (Cfg.Node.get_description pe_text node)) nodes
let instrs_to_string instrs = let instrs_to_string instrs =
let pp fmt () = Format.fprintf fmt "%a" (Sil.pp_instr_list Utils.pe_text) instrs in let pp fmt () = Format.fprintf fmt "%a" (Sil.pp_instr_list pe_text) instrs in
pp_to_string pp () pp_to_string pp ()
end end

@ -88,7 +88,7 @@ let should_translate (loc_start, loc_end) =
DB.source_file_equal file !DB.current_source DB.source_file_equal file !DB.current_source
in in
let file_in_project file = match !Config.project_root with let file_in_project file = match !Config.project_root with
| Some root -> Utils.string_is_prefix root file | Some root -> string_is_prefix root file
| None -> false | None -> false
in in
let file_in_project = map_path_of file_in_project loc_end let file_in_project = map_path_of file_in_project loc_end

@ -17,7 +17,7 @@ open CFrontend_utils
let arg_desc = let arg_desc =
let desc = let desc =
(Utils.arg_desc_filter ["-results_dir"] Utils.base_arg_desc) @ (Utils.arg_desc_filter ["-results_dir"] base_arg_desc) @
[ [
"-c", "-c",
Arg.String (fun cfile -> CFrontend_config.source_file := Some cfile), Arg.String (fun cfile -> CFrontend_config.source_file := Some cfile),
@ -53,7 +53,7 @@ let arg_desc =
Arg.Unit (fun _ -> CFrontend_config.testing_mode := true), Arg.Unit (fun _ -> CFrontend_config.testing_mode := true),
None, None,
"Mode for testing, where no libraries are translated, \ "Mode for testing, where no libraries are translated, \
including enums defined in the libraries" including enums defined in the libraries"
; ;
"-debug", "-debug",
Arg.Unit (fun _ -> CFrontend_config.debug_mode := true), Arg.Unit (fun _ -> CFrontend_config.debug_mode := true),
@ -82,17 +82,17 @@ let arg_desc =
"Mode for computing the models" "Mode for computing the models"
; ;
] in ] in
Utils.Arg.create_options_desc false "Parsing Options" desc Arg.create_options_desc false "Parsing Options" desc
let usage = let usage =
"\nUsage: InferClang -c C Files -ast AST Files -results_dir <output-dir> [options] \n" "\nUsage: InferClang -c C Files -ast AST Files -results_dir <output-dir> [options] \n"
let print_usage_exit () = let print_usage_exit () =
Utils.Arg.usage arg_desc usage; Arg.usage arg_desc usage;
exit(1) exit(1)
let () = let () =
Utils.Arg.parse arg_desc (fun _ -> ()) usage Arg.parse arg_desc (fun _ -> ()) usage
let buffer_len = 16384 let buffer_len = 16384

@ -1551,8 +1551,9 @@ struct
IList.map (fun (e, t) -> IList.flatten (collect_left_hand_exprs e t tns)) (zip lh_exprs lh_types) IList.map (fun (e, t) -> IList.flatten (collect_left_hand_exprs e t tns)) (zip lh_exprs lh_types)
| _ -> [ [(e, typ)] ] in | _ -> [ [(e, typ)] ] in
let trans_state_pri = PriorityNode.try_claim_priority_node trans_state stmt_info in let trans_state_pri = PriorityNode.try_claim_priority_node trans_state stmt_info in
let var_type = CTypes_decl.type_ptr_to_sil_type context.CContext.tenv expr_info.Clang_ast_t.ei_type_ptr in let var_type =
let lh = IList.flatten (collect_left_hand_exprs var_exp var_type Utils.StringSet.empty) in CTypes_decl.type_ptr_to_sil_type context.CContext.tenv expr_info.Clang_ast_t.ei_type_ptr in
let lh = IList.flatten (collect_left_hand_exprs var_exp var_type StringSet.empty) in
let rh = IList.flatten (IList.map (collect_right_hand_exprs trans_state_pri) stmts ) in let rh = IList.flatten (IList.map (collect_right_hand_exprs trans_state_pri) stmts ) in
if IList.length rh != IList.length lh then ( if IList.length rh != IList.length lh then (
(* If the right hand expressions are not as many as the left hand expressions something's wrong *) (* If the right hand expressions are not as many as the left hand expressions something's wrong *)

@ -250,7 +250,7 @@ let typecheck_instr ext calls_this checks (node: Cfg.Node.t) idenv get_proc_desc
let handle_field_access_via_temporary typestate exp = let handle_field_access_via_temporary typestate exp =
let name_is_temporary name = let name_is_temporary name =
let prefix = "$T" in let prefix = "$T" in
Utils.string_is_prefix prefix name in string_is_prefix prefix name in
let pvar_get_origin pvar = let pvar_get_origin pvar =
match TypeState.lookup_pvar pvar typestate with match TypeState.lookup_pvar pvar typestate with
| Some (_, ta, _) -> | Some (_, ta, _) ->

@ -16,7 +16,8 @@ val models_jar : string ref
(** Type environment of the models *) (** Type environment of the models *)
val models_tenv : Sil.tenv ref val models_tenv : Sil.tenv ref
(** Adds the set of procnames for the models of Java libraries so that methods with similar names are skipped during the capture *) (** Adds the set of procnames for the models of Java libraries so that methods
with similar names are skipped during the capture *)
val add_models : string -> unit val add_models : string -> unit
(** Check if there is a model for the given procname *) (** Check if there is a model for the given procname *)
@ -24,7 +25,8 @@ val is_model : Procname.t -> bool
val set_verbose_out: string -> unit val set_verbose_out: string -> unit
(** create a source file from an absolute path. Source files are relative if the project root is specified and absolute otherwise *) (** create a source file from an absolute path.
Source files are relative if the project root is specified and absolute otherwise *)
val java_source_file_from_path : string -> DB.source_file val java_source_file_from_path : string -> DB.source_file
val split_classpath : string -> string list val split_classpath : string -> string list
@ -36,7 +38,7 @@ type file_entry =
(** load the list of source files and the list of classes from the javac verbose file *) (** load the list of source files and the list of classes from the javac verbose file *)
val load_sources_and_classes : unit -> val load_sources_and_classes : unit ->
string * file_entry Utils.StringMap.t * JBasics.ClassSet.t string * file_entry StringMap.t * JBasics.ClassSet.t
type classmap = JCode.jcode Javalib.interface_or_class JBasics.ClassMap.t type classmap = JCode.jcode Javalib.interface_or_class JBasics.ClassMap.t

@ -9,7 +9,7 @@
(** Representation of LLVM constructs *) (** Representation of LLVM constructs *)
module MetadataMap = Utils.IntMap;; module MetadataMap = IntMap;;
type variable_id = type variable_id =
| Name of string | Name of string

@ -28,7 +28,7 @@ let arg_desc =
let usage = "Usage: InferLLVM -c <cfile> [options]\n" let usage = "Usage: InferLLVM -c <cfile> [options]\n"
let print_usage_exit () = let print_usage_exit () =
Utils.Arg.usage arg_desc usage; Arg.usage arg_desc usage;
exit(1) exit(1)
let init_global_state source_filename = let init_global_state source_filename =

@ -162,7 +162,7 @@ let copyright_has_changed mono fb_year com_style prefix cstart cend lines_arr =
!r in !r in
let new_copyright = let new_copyright =
let pp fmt () = pp_copyright mono fb_year com_style fmt prefix in let pp fmt () = pp_copyright mono fb_year com_style fmt prefix in
Utils.pp_to_string pp () in pp_to_string pp () in
old_copyright <> new_copyright old_copyright <> new_copyright
let update_file fname mono fb_year com_style prefix cstart cend lines_arr = let update_file fname mono fb_year com_style prefix cstart cend lines_arr =

Loading…
Cancel
Save