You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
319 lines
10 KiB
319 lines
10 KiB
10 years ago
|
(*
|
||
10 years ago
|
* 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.
|
||
|
*)
|
||
10 years ago
|
|
||
8 years ago
|
open! IStd
|
||
10 years ago
|
module F = Format
|
||
7 years ago
|
open PolyVariantEqual
|
||
10 years ago
|
|
||
|
type stats =
|
||
8 years ago
|
{ stats_failure: SymOp.failure_kind option
|
||
7 years ago
|
; symops: int
|
||
|
; mutable nodes_visited_fp: IntSet.t
|
||
|
; mutable nodes_visited_re: IntSet.t }
|
||
10 years ago
|
|
||
8 years ago
|
type status = Pending | Analyzed [@@deriving compare]
|
||
8 years ago
|
|
||
8 years ago
|
let string_of_status = function Pending -> "Pending" | Analyzed -> "Analyzed"
|
||
8 years ago
|
|
||
7 years ago
|
let pp_status fmt status = F.pp_print_string fmt (string_of_status status)
|
||
10 years ago
|
|
||
8 years ago
|
let equal_status = [%compare.equal : status]
|
||
|
|
||
10 years ago
|
type payload =
|
||
7 years ago
|
{ annot_map: AnnotReachabilityDomain.astate option
|
||
7 years ago
|
; biabduction: BiabductionSummary.t option
|
||
7 years ago
|
; buffer_overrun: BufferOverrunDomain.Summary.t option
|
||
8 years ago
|
; crashcontext_frame: Stacktree_t.stacktree option
|
||
7 years ago
|
; litho: LithoDomain.astate option
|
||
8 years ago
|
; quandary: QuandarySummary.t option
|
||
7 years ago
|
; racerd: RacerDDomain.summary option
|
||
8 years ago
|
; resources: ResourceLeakDomain.summary option
|
||
|
; siof: SiofDomain.astate option
|
||
7 years ago
|
; typestate: unit TypeState.t option
|
||
7 years ago
|
; uninit: UninitDomain.summary option
|
||
7 years ago
|
; cost: CostDomain.summary option
|
||
7 years ago
|
; starvation: StarvationDomain.summary option }
|
||
8 years ago
|
|
||
7 years ago
|
type t = {payload: payload; sessions: int ref; stats: stats; status: status; proc_desc: Procdesc.t}
|
||
7 years ago
|
|
||
|
let get_status summary = summary.status
|
||
|
|
||
|
let get_proc_desc summary = summary.proc_desc
|
||
|
|
||
|
let get_attributes summary = Procdesc.get_attributes summary.proc_desc
|
||
|
|
||
|
let get_proc_name summary = (get_attributes summary).ProcAttributes.proc_name
|
||
|
|
||
|
let get_ret_type summary = (get_attributes summary).ProcAttributes.ret_type
|
||
|
|
||
|
let get_formals summary = (get_attributes summary).ProcAttributes.formals
|
||
|
|
||
|
let get_err_log summary = (get_attributes summary).ProcAttributes.err_log
|
||
|
|
||
|
let get_loc summary = (get_attributes summary).ProcAttributes.loc
|
||
|
|
||
7 years ago
|
type cache = t Typ.Procname.Hash.t
|
||
10 years ago
|
|
||
7 years ago
|
let cache : cache = Typ.Procname.Hash.create 128
|
||
10 years ago
|
|
||
7 years ago
|
let clear_cache () = Typ.Procname.Hash.clear cache
|
||
10 years ago
|
|
||
8 years ago
|
let pp_failure_kind_opt fmt failure_kind_opt =
|
||
|
match failure_kind_opt with
|
||
7 years ago
|
| Some failure_kind ->
|
||
|
SymOp.pp_failure_kind fmt failure_kind
|
||
|
| None ->
|
||
7 years ago
|
F.pp_print_string fmt "NONE"
|
||
7 years ago
|
|
||
10 years ago
|
|
||
9 years ago
|
let pp_errlog fmt err_log =
|
||
8 years ago
|
F.fprintf fmt "ERRORS: @[<h>%a@]@\n%!" Errlog.pp_errors err_log ;
|
||
9 years ago
|
F.fprintf fmt "WARNINGS: @[<h>%a@]" Errlog.pp_warnings err_log
|
||
10 years ago
|
|
||
7 years ago
|
|
||
8 years ago
|
let pp_stats fmt stats =
|
||
|
F.fprintf fmt "FAILURE:%a SYMOPS:%d@\n" pp_failure_kind_opt stats.stats_failure stats.symops
|
||
9 years ago
|
|
||
7 years ago
|
|
||
10 years ago
|
(** Return the signature of a procedure declaration as a string *)
|
||
|
let get_signature summary =
|
||
|
let s = ref "" in
|
||
8 years ago
|
List.iter
|
||
|
~f:(fun (p, typ) ->
|
||
8 years ago
|
let pp f = F.fprintf f "%a %a" (Typ.pp_full Pp.text) typ Mangled.pp p in
|
||
|
let decl = F.asprintf "%t" pp in
|
||
7 years ago
|
s := if String.equal !s "" then decl else !s ^ ", " ^ decl )
|
||
7 years ago
|
(get_formals summary) ;
|
||
7 years ago
|
F.asprintf "%a %a(%s)" (Typ.pp_full Pp.text) (get_ret_type summary) Typ.Procname.pp
|
||
|
(get_proc_name summary) !s
|
||
10 years ago
|
|
||
7 years ago
|
|
||
7 years ago
|
let pp_no_stats_specs fmt summary =
|
||
8 years ago
|
F.fprintf fmt "%s@\n" (get_signature summary) ;
|
||
7 years ago
|
F.fprintf fmt "%a@\n" pp_status summary.status
|
||
10 years ago
|
|
||
7 years ago
|
|
||
8 years ago
|
let pp_payload pe fmt
|
||
7 years ago
|
{ biabduction
|
||
8 years ago
|
; typestate
|
||
|
; crashcontext_frame
|
||
|
; quandary
|
||
|
; siof
|
||
7 years ago
|
; racerd
|
||
7 years ago
|
; litho
|
||
8 years ago
|
; buffer_overrun
|
||
7 years ago
|
; annot_map
|
||
7 years ago
|
; uninit
|
||
7 years ago
|
; cost
|
||
7 years ago
|
; starvation } =
|
||
8 years ago
|
let pp_opt prefix pp fmt = function
|
||
7 years ago
|
| Some x ->
|
||
|
F.fprintf fmt "%s: %a@\n" prefix pp x
|
||
|
| None ->
|
||
|
()
|
||
8 years ago
|
in
|
||
7 years ago
|
F.fprintf fmt "%a%a%a%a%a%a%a%a%a%a%a%a@\n"
|
||
7 years ago
|
(pp_opt "Biabduction" (BiabductionSummary.pp pe))
|
||
|
biabduction
|
||
8 years ago
|
(pp_opt "TypeState" (TypeState.pp TypeState.unit_ext))
|
||
7 years ago
|
typestate
|
||
|
(pp_opt "CrashContext" Crashcontext.pp_stacktree)
|
||
|
crashcontext_frame
|
||
|
(pp_opt "Quandary" QuandarySummary.pp)
|
||
|
quandary (pp_opt "Siof" SiofDomain.pp) siof
|
||
|
(pp_opt "RacerD" RacerDDomain.pp_summary)
|
||
7 years ago
|
racerd (pp_opt "Litho" LithoDomain.pp) litho
|
||
7 years ago
|
(pp_opt "BufferOverrun" BufferOverrunDomain.Summary.pp)
|
||
|
buffer_overrun
|
||
|
(pp_opt "AnnotationReachability" AnnotReachabilityDomain.pp)
|
||
|
annot_map
|
||
|
(pp_opt "Uninitialised" UninitDomain.pp_summary)
|
||
|
uninit
|
||
7 years ago
|
(pp_opt "Cost" CostDomain.pp_summary)
|
||
|
cost
|
||
7 years ago
|
(pp_opt "Starvation" StarvationDomain.pp_summary)
|
||
|
starvation
|
||
7 years ago
|
|
||
8 years ago
|
|
||
7 years ago
|
let pp_text fmt summary =
|
||
8 years ago
|
let pe = Pp.text in
|
||
7 years ago
|
pp_no_stats_specs fmt summary ;
|
||
7 years ago
|
F.fprintf fmt "%a@\n%a%a" pp_errlog (get_err_log summary) pp_stats summary.stats (pp_payload pe)
|
||
8 years ago
|
summary.payload
|
||
8 years ago
|
|
||
7 years ago
|
|
||
7 years ago
|
let pp_html source color fmt summary =
|
||
8 years ago
|
let pe = Pp.html color in
|
||
8 years ago
|
Io_infer.Html.pp_start_color fmt Black ;
|
||
7 years ago
|
F.fprintf fmt "@\n%a" pp_no_stats_specs summary ;
|
||
8 years ago
|
Io_infer.Html.pp_end_color fmt () ;
|
||
|
F.fprintf fmt "<br />%a<br />@\n" pp_stats summary.stats ;
|
||
7 years ago
|
Errlog.pp_html source [] fmt (get_err_log summary) ;
|
||
8 years ago
|
Io_infer.Html.pp_hline fmt () ;
|
||
|
F.fprintf fmt "<LISTING>@\n" ;
|
||
|
pp_payload pe fmt summary.payload ;
|
||
8 years ago
|
F.fprintf fmt "</LISTING>@\n"
|
||
10 years ago
|
|
||
7 years ago
|
|
||
7 years ago
|
let empty_stats =
|
||
7 years ago
|
{stats_failure= None; symops= 0; nodes_visited_fp= IntSet.empty; nodes_visited_re= IntSet.empty}
|
||
10 years ago
|
|
||
7 years ago
|
|
||
8 years ago
|
(** Add the summary to the table for the given function *)
|
||
7 years ago
|
let add (proc_name: Typ.Procname.t) (summary: t) : unit =
|
||
|
Typ.Procname.Hash.replace cache proc_name summary
|
||
10 years ago
|
|
||
7 years ago
|
|
||
10 years ago
|
let specs_filename pname =
|
||
8 years ago
|
let pname_file = Typ.Procname.to_filename pname in
|
||
9 years ago
|
pname_file ^ Config.specs_files_suffix
|
||
10 years ago
|
|
||
7 years ago
|
|
||
10 years ago
|
(** path to the .specs file for the given procedure in the current results directory *)
|
||
|
let res_dir_specs_filename pname =
|
||
8 years ago
|
DB.Results_dir.path_to_filename DB.Results_dir.Abs_root
|
||
|
[Config.specs_dir_name; specs_filename pname]
|
||
10 years ago
|
|
||
7 years ago
|
|
||
10 years ago
|
(** paths to the .specs file for the given procedure in the current spec libraries *)
|
||
7 years ago
|
let specs_library_filename specs_dir pname =
|
||
|
DB.filename_from_string (Filename.concat specs_dir (specs_filename pname))
|
||
10 years ago
|
|
||
7 years ago
|
|
||
10 years ago
|
(** paths to the .specs file for the given procedure in the models folder *)
|
||
|
let specs_models_filename pname =
|
||
|
DB.filename_from_string (Filename.concat Config.models_dir (specs_filename pname))
|
||
|
|
||
7 years ago
|
|
||
7 years ago
|
let has_model pname = Sys.file_exists (DB.filename_to_string (specs_models_filename pname)) = `Yes
|
||
10 years ago
|
|
||
7 years ago
|
let summary_serializer : t Serialization.serializer =
|
||
8 years ago
|
Serialization.create_serializer Serialization.Key.summary
|
||
10 years ago
|
|
||
7 years ago
|
|
||
10 years ago
|
(** Load procedure summary from the given file *)
|
||
7 years ago
|
let load_from_file specs_file = Serialization.read_from_file summary_serializer specs_file
|
||
10 years ago
|
|
||
|
(** Load procedure summary for the given procedure name and update spec table *)
|
||
7 years ago
|
let load_summary_to_spec_table =
|
||
|
let rec or_load_summary_libs specs_dirs proc_name summ_opt =
|
||
|
match (summ_opt, specs_dirs) with
|
||
|
| Some _, _ | _, [] ->
|
||
|
summ_opt
|
||
|
| None, specs_dir :: specs_dirs ->
|
||
7 years ago
|
load_from_file (specs_library_filename specs_dir proc_name)
|
||
7 years ago
|
|> or_load_summary_libs specs_dirs proc_name
|
||
8 years ago
|
in
|
||
9 years ago
|
let load_summary_ziplibs zip_specs_filename =
|
||
|
let zip_specs_path = Filename.concat Config.specs_dir_name zip_specs_filename in
|
||
7 years ago
|
ZipLib.load summary_serializer zip_specs_path
|
||
8 years ago
|
in
|
||
7 years ago
|
let or_from f_load f_filenames proc_name summ_opt =
|
||
|
match summ_opt with Some _ -> summ_opt | None -> f_load (f_filenames proc_name)
|
||
|
in
|
||
|
fun proc_name ->
|
||
|
let summ_opt =
|
||
7 years ago
|
load_from_file (res_dir_specs_filename proc_name)
|
||
|
|> or_from load_from_file specs_models_filename proc_name
|
||
7 years ago
|
|> or_from load_summary_ziplibs specs_filename proc_name
|
||
|
|> or_load_summary_libs Config.specs_library proc_name
|
||
|
in
|
||
7 years ago
|
Option.iter ~f:(add proc_name) summ_opt ;
|
||
7 years ago
|
summ_opt
|
||
7 years ago
|
|
||
10 years ago
|
|
||
7 years ago
|
let get proc_name =
|
||
|
try Some (Typ.Procname.Hash.find cache proc_name) with Caml.Not_found ->
|
||
7 years ago
|
load_summary_to_spec_table proc_name
|
||
10 years ago
|
|
||
7 years ago
|
|
||
7 years ago
|
let get_unsafe proc_name = Option.value_exn (get proc_name)
|
||
10 years ago
|
|
||
|
(** Check if the procedure is from a library:
|
||
9 years ago
|
It's not defined, and there is no spec file for it. *)
|
||
|
let proc_is_library proc_attributes =
|
||
|
if not proc_attributes.ProcAttributes.is_defined then
|
||
7 years ago
|
match get proc_attributes.ProcAttributes.proc_name with None -> true | Some _ -> false
|
||
10 years ago
|
else false
|
||
|
|
||
7 years ago
|
|
||
9 years ago
|
(** Try to find the attributes for a defined proc.
|
||
|
First look at specs (to get attributes computed by analysis)
|
||
|
then look at the attributes table.
|
||
9 years ago
|
If no attributes can be found, return None.
|
||
|
*)
|
||
9 years ago
|
let proc_resolve_attributes proc_name =
|
||
7 years ago
|
match get proc_name with
|
||
7 years ago
|
| Some summary ->
|
||
|
Some (get_attributes summary)
|
||
7 years ago
|
| None ->
|
||
7 years ago
|
Attributes.load proc_name
|
||
7 years ago
|
|
||
9 years ago
|
|
||
|
(** Like proc_resolve_attributes but start from a proc_desc. *)
|
||
|
let pdesc_resolve_attributes proc_desc =
|
||
8 years ago
|
let proc_name = Procdesc.get_proc_name proc_desc in
|
||
9 years ago
|
match proc_resolve_attributes proc_name with
|
||
7 years ago
|
| Some proc_attributes ->
|
||
|
proc_attributes
|
||
|
| None ->
|
||
|
(* this should not happen *)
|
||
9 years ago
|
assert false
|
||
10 years ago
|
|
||
7 years ago
|
|
||
8 years ago
|
(** Save summary for the procedure into the spec database *)
|
||
7 years ago
|
let store (summ: t) =
|
||
7 years ago
|
let final_summary = {summ with status= Analyzed} in
|
||
8 years ago
|
let proc_name = get_proc_name final_summary in
|
||
|
(* Make sure the summary in memory is identical to the saved one *)
|
||
7 years ago
|
add proc_name final_summary ;
|
||
7 years ago
|
Serialization.write_to_file summary_serializer
|
||
|
(res_dir_specs_filename proc_name)
|
||
8 years ago
|
~data:final_summary
|
||
|
|
||
7 years ago
|
|
||
9 years ago
|
let empty_payload =
|
||
7 years ago
|
{ biabduction= None
|
||
8 years ago
|
; typestate= None
|
||
|
; annot_map= None
|
||
|
; crashcontext_frame= None
|
||
|
; quandary= None
|
||
|
; resources= None
|
||
|
; siof= None
|
||
7 years ago
|
; racerd= None
|
||
7 years ago
|
; litho= None
|
||
7 years ago
|
; buffer_overrun= None
|
||
7 years ago
|
; uninit= None
|
||
7 years ago
|
; cost= None
|
||
7 years ago
|
; starvation= None }
|
||
9 years ago
|
|
||
7 years ago
|
|
||
9 years ago
|
(** [init_summary (depend_list, nodes,
|
||
9 years ago
|
proc_flags, calls, in_out_calls_opt, proc_attributes)]
|
||
10 years ago
|
initializes the summary for [proc_name] given dependent procs in list [depend_list]. *)
|
||
7 years ago
|
let init_summary proc_desc =
|
||
10 years ago
|
let summary =
|
||
7 years ago
|
{sessions= ref 0; payload= empty_payload; stats= empty_stats; status= Pending; proc_desc}
|
||
8 years ago
|
in
|
||
7 years ago
|
Typ.Procname.Hash.replace cache (Procdesc.get_proc_name proc_desc) summary ;
|
||
7 years ago
|
summary
|
||
|
|
||
10 years ago
|
|
||
8 years ago
|
let dummy =
|
||
7 years ago
|
let dummy_attributes = ProcAttributes.default Typ.Procname.empty_block in
|
||
7 years ago
|
let dummy_proc_desc = Procdesc.from_proc_attributes dummy_attributes in
|
||
7 years ago
|
init_summary dummy_proc_desc
|
||
8 years ago
|
|
||
7 years ago
|
|
||
9 years ago
|
(** Reset a summary rebuilding the dependents and preserving the proc attributes if present. *)
|
||
7 years ago
|
let reset proc_desc = init_summary proc_desc
|
||
7 years ago
|
|
||
10 years ago
|
(* =============== END of support for spec tables =============== *)
|