[specs] move biabduction-specific stuff to BiabductionSummary.ml

Summary:
Move the biabduction-specific payloads (the "`'a spec`" stuff) from specs.ml
into a new `BiabductinoSummary` module, similar to other checkers.

Reviewed By: ngorogiannis

Differential Revision: D7935815

fbshipit-source-id: bdff3b9
master
Jules Villard 7 years ago committed by Facebook Github Bot
parent 766a16cd90
commit d207f29287

@ -101,13 +101,15 @@ let summary_values summary =
let err_log = Specs.get_err_log summary in
let proc_name = Specs.get_proc_name summary in
let vsignature = Specs.get_signature summary in
let specs = Specs.get_specs_from_payload summary in
let specs = Tabulation.get_specs_from_payload summary in
let lines_visited =
let visited = ref Specs.Visitedset.empty in
let do_spec spec = visited := Specs.Visitedset.union spec.Specs.visited !visited in
let visited = ref BiabductionSummary.Visitedset.empty in
let do_spec spec =
visited := BiabductionSummary.Visitedset.union spec.BiabductionSummary.visited !visited
in
List.iter ~f:do_spec specs ;
let visited_lines = ref Int.Set.empty in
Specs.Visitedset.iter
BiabductionSummary.Visitedset.iter
(fun (_, ls) -> List.iter ~f:(fun l -> visited_lines := Int.Set.add !visited_lines l) ls)
!visited ;
Int.Set.elements !visited_lines
@ -490,7 +492,7 @@ module Stats = struct
let process_summary error_filter summary linereader stats =
let specs = Specs.get_specs_from_payload summary in
let specs = Tabulation.get_specs_from_payload summary in
let found_errors = process_err_log error_filter linereader (Specs.get_err_log summary) stats in
let is_defective = found_errors in
let is_verified = specs <> [] && not is_defective in
@ -528,7 +530,7 @@ end
module StatsLogs = struct
let process _ (summary: Specs.summary) _ _ =
let num_preposts =
match summary.payload.preposts with Some preposts -> List.length preposts | None -> 0
match summary.payload.biabduction with Some {preposts} -> List.length preposts | None -> 0
in
let clang_method_kind =
ProcAttributes.string_of_clang_method_kind (Specs.get_attributes summary).clang_method_kind
@ -571,8 +573,10 @@ module PreconditionStats = struct
let nr_dataconstraints = ref 0
let do_summary proc_name summary =
let specs = Specs.get_specs_from_payload summary in
let preconditions = List.map ~f:(fun spec -> Specs.Jprop.to_prop spec.Specs.pre) specs in
let specs = Tabulation.get_specs_from_payload summary in
let preconditions =
List.map ~f:(fun spec -> BiabductionSummary.Jprop.to_prop spec.BiabductionSummary.pre) specs
in
match Prop.CategorizePreconditions.categorize preconditions with
| Prop.CategorizePreconditions.Empty ->
incr nr_empty ;

@ -1209,7 +1209,7 @@ let print_icfg_dotty source cfg =
(********** END of Printing dotty files ***********)
(** Dotty printing for specs *)
let pp_speclist_dotty f (splist: Prop.normal Specs.spec list) =
let pp_speclist_dotty f (splist: Prop.normal BiabductionSummary.spec list) =
let pp_simple_saved = !Config.pp_simple in
Config.pp_simple := true ;
reset_proposition_counter () ;
@ -1218,7 +1218,10 @@ let pp_speclist_dotty f (splist: Prop.normal Specs.spec list) =
F.fprintf f "@\n compound = true; @\n" ;
(* F.fprintf f "@\n size=\"12,7\"; ratio=fill; @\n"; *)
List.iter
~f:(fun s -> pp_dotty_one_spec f (Specs.Jprop.to_prop s.Specs.pre) s.Specs.posts)
~f:(fun s ->
pp_dotty_one_spec f
(BiabductionSummary.Jprop.to_prop s.BiabductionSummary.pre)
s.BiabductionSummary.posts )
splist ;
F.fprintf f "@\n}" ;
Config.pp_simple := pp_simple_saved

@ -19,5 +19,5 @@ val print_icfg_dotty : SourceFile.t -> Cfg.t -> unit
(** {2 Specs} *)
val pp_speclist_dotty_file : DB.filename -> Prop.normal Specs.spec list -> unit
val pp_speclist_dotty_file : DB.filename -> Prop.normal BiabductionSummary.spec list -> unit
(** Dotty printing for specs *)

@ -136,7 +136,12 @@ let run_proc_analysis analyze_proc ~caller_pdesc callee_pdesc =
let log_error_and_continue exn summary kind =
Reporting.log_error summary exn ;
let stats = {summary.Specs.stats with Specs.stats_failure= Some kind} in
let payload = {summary.Specs.payload with Specs.preposts= Some []} in
let payload =
let biabduction =
Some BiabductionSummary.{preposts= []; phase= Tabulation.get_phase summary}
in
{summary.Specs.payload with Specs.biabduction}
in
let new_summary = {summary with Specs.stats; payload} in
Specs.store_summary new_summary ;
remove_active callee_pname ;

@ -99,7 +99,7 @@ let pp_node_link path_to_root ?proof_cover ~description fmt node =
let isproof =
match proof_cover with
| Some proof_cover ->
Specs.Visitedset.mem (Procdesc.Node.get_id node, []) proof_cover
BiabductionSummary.Visitedset.mem (Procdesc.Node.get_id node, []) proof_cover
| None ->
false
in
@ -208,11 +208,13 @@ let force_delayed_print fmt =
il Io_infer.Html.pp_end_color ()
else Sil.pp_instr_list Pp.text fmt il
| L.PTjprop_list, shallow_jpl ->
let (shallow: bool), (jpl: Prop.normal Specs.Jprop.t list) = Obj.obj shallow_jpl in
Specs.Jprop.pp_list pe_default shallow fmt jpl
let (shallow: bool), (jpl: Prop.normal BiabductionSummary.Jprop.t list) =
Obj.obj shallow_jpl
in
BiabductionSummary.Jprop.pp_list pe_default shallow fmt jpl
| L.PTjprop_short, jp ->
let jp : Prop.normal Specs.Jprop.t = Obj.obj jp in
Specs.Jprop.pp_short pe_default fmt jp
let jp : Prop.normal BiabductionSummary.Jprop.t = Obj.obj jp in
BiabductionSummary.Jprop.pp_short pe_default fmt jp
| L.PTloc, loc ->
let loc : Location.t = Obj.obj loc in
Location.pp fmt loc
@ -263,8 +265,10 @@ let force_delayed_print fmt =
let sigma : Sil.hpred list = Obj.obj sigma in
Prop.pp_sigma pe_default fmt sigma
| L.PTspec, spec ->
let spec : Prop.normal Specs.spec = Obj.obj spec in
Specs.pp_spec (if Config.write_html then Pp.html Blue else Pp.text) None fmt spec
let spec : Prop.normal BiabductionSummary.spec = Obj.obj spec in
BiabductionSummary.pp_spec
(if Config.write_html then Pp.html Blue else Pp.text)
None fmt spec
| L.PTstr, s ->
let s : string = Obj.obj s in
F.pp_print_string fmt s
@ -436,8 +440,10 @@ let write_html_proc source proof_cover table_nodes_at_linenum global_err_log pro
()
| Some summary ->
List.iter
~f:(fun sp -> proof_cover := Specs.Visitedset.union sp.Specs.visited !proof_cover)
(Specs.get_specs_from_payload summary) ;
~f:(fun sp ->
proof_cover :=
BiabductionSummary.Visitedset.union sp.BiabductionSummary.visited !proof_cover )
(Tabulation.get_specs_from_payload summary) ;
Errlog.update global_err_log (Specs.get_err_log summary) )
@ -482,7 +488,7 @@ let write_html_file linereader filename procs =
| None ->
0
| Some summary ->
List.length (Specs.get_specs_from_payload summary)
List.length (Tabulation.get_specs_from_payload summary)
in
let label =
F.sprintf "%s: %d specs"
@ -500,7 +506,7 @@ let write_html_file linereader filename procs =
pp_prelude () ;
let global_err_log = Errlog.empty () in
let table_nodes_at_linenum = Hashtbl.create 11 in
let proof_cover = ref Specs.Visitedset.empty in
let proof_cover = ref BiabductionSummary.Visitedset.empty in
List.iter ~f:(write_html_proc filename proof_cover table_nodes_at_linenum global_err_log) procs ;
let table_err_per_line = create_table_err_per_line global_err_log in
let linenum = ref 0 in

@ -9,239 +9,8 @@
*)
open! IStd
open PolyVariantEqual
(** Specifications and spec table *)
module L = Logging
module F = Format
(* =============== START of support for spec tables =============== *)
(** Module for joined props *)
module Jprop = struct
(** type aliases for component of t values that compare should ignore *)
type id_ = int
let compare_id_ _ _ = 0
(** Remember when a prop is obtained as the join of two other props; the first parameter is an id *)
type 'a t = Prop of id_ * 'a Prop.t | Joined of id_ * 'a Prop.t * 'a t * 'a t
[@@deriving compare]
(** Comparison for joined_prop *)
let compare jp1 jp2 = compare (fun _ _ -> 0) jp1 jp2
(** Return true if the two join_prop's are equal *)
let equal jp1 jp2 = Int.equal (compare jp1 jp2) 0
let to_prop = function Prop (_, p) -> p | Joined (_, p, _, _) -> p
let rec sorted_gen_free_vars tenv =
let open Sequence.Generator in
function
| Prop (_, p) ->
Prop.dfs_sort tenv p |> Prop.sorted_gen_free_vars
| Joined (_, p, jp1, jp2) ->
Prop.dfs_sort tenv p |> Prop.sorted_gen_free_vars
>>= fun () -> sorted_gen_free_vars tenv jp1 >>= fun () -> sorted_gen_free_vars tenv jp2
let rec normalize tenv = function
| Prop (n, p) ->
Prop (n, Prop.normalize tenv p)
| Joined (n, p, jp1, jp2) ->
Joined (n, Prop.normalize tenv p, normalize tenv jp1, normalize tenv jp2)
(** Return a compact representation of the jprop *)
let rec compact sh = function
| Prop (n, p) ->
Prop (n, Prop.prop_compact sh p)
| Joined (n, p, jp1, jp2) ->
Joined (n, Prop.prop_compact sh p, compact sh jp1, compact sh jp2)
(** Print the toplevel prop *)
let pp_short pe f jp = Prop.pp_prop pe f (to_prop jp)
(** Dump the toplevel prop *)
let d_shallow (jp: Prop.normal t) = L.add_print_action (L.PTjprop_short, Obj.repr jp)
(** Get identifies of the jprop *)
let get_id = function Prop (n, _) -> n | Joined (n, _, _, _) -> n
(** Print a list of joined props, the boolean indicates whether to print subcomponents of joined props *)
let pp_list pe shallow f jplist =
let rec pp_seq_newline f = function
| [] ->
()
| [Prop (n, p)] ->
F.fprintf f "PROP %d:@\n%a" n (Prop.pp_prop pe) p
| [Joined (n, p, p1, p2)] ->
if not shallow then F.fprintf f "%a@\n" pp_seq_newline [p1] ;
if not shallow then F.fprintf f "%a@\n" pp_seq_newline [p2] ;
F.fprintf f "PROP %d (join of %d,%d):@\n%a" n (get_id p1) (get_id p2) (Prop.pp_prop pe) p
| jp :: l ->
F.fprintf f "%a@\n" pp_seq_newline [jp] ;
pp_seq_newline f l
in
pp_seq_newline f jplist
(** dump a joined prop list, the boolean indicates whether to print toplevel props only *)
let d_list (shallow: bool) (jplist: Prop.normal t list) =
L.add_print_action (L.PTjprop_list, Obj.repr (shallow, jplist))
let rec gen_free_vars =
let open Sequence.Generator in
function
| Prop (_, p) ->
Prop.gen_free_vars p
| Joined (_, p, jp1, jp2) ->
Prop.gen_free_vars p >>= fun () -> gen_free_vars jp1 >>= fun () -> gen_free_vars jp2
let free_vars jp = Sequence.Generator.run (gen_free_vars jp)
let rec jprop_sub sub = function
| Prop (n, p) ->
Prop (n, Prop.prop_sub sub p)
| Joined (n, p, jp1, jp2) ->
let p' = Prop.prop_sub sub p in
let jp1' = jprop_sub sub jp1 in
let jp2' = jprop_sub sub jp2 in
Joined (n, p', jp1', jp2')
let filter (f: 'a t -> 'b option) jpl =
let rec do_filter acc = function
| [] ->
acc
| (Prop _ as jp) :: jpl -> (
match f jp with Some x -> do_filter (x :: acc) jpl | None -> do_filter acc jpl )
| (Joined (_, _, jp1, jp2) as jp) :: jpl ->
match f jp with
| Some x ->
do_filter (x :: acc) jpl
| None ->
do_filter acc (jpl @ [jp1; jp2])
in
do_filter [] jpl
let rec map (f: 'a Prop.t -> 'b Prop.t) = function
| Prop (n, p) ->
Prop (n, f p)
| Joined (n, p, jp1, jp2) ->
Joined (n, f p, map f jp1, map f jp2)
(*
let rec jprop_sub sub = function
| Prop (n, p) -> Prop (n, Prop.prop_sub sub p)
| Joined (n, p, jp1, jp2) ->
Joined (n, Prop.prop_sub sub p, jprop_sub sub jp1, jprop_sub sub jp2)
*)
end
(***** End of module Jprop *****)
module Visitedset = Caml.Set.Make (struct
type t = Procdesc.Node.id * int list
let compare (node_id1, _) (node_id2, _) = Procdesc.Node.compare_id node_id1 node_id2
end)
let visited_str vis =
let s = ref "" in
let lines = ref Int.Set.empty in
let do_one (_, ns) =
(* if List.length ns > 1 then
begin
let ss = ref "" in
List.iter ~f:(fun n -> ss := !ss ^ " " ^ string_of_int n) ns;
L.out "Node %d has lines %s@." node !ss
end; *)
List.iter ~f:(fun n -> lines := Int.Set.add !lines n) ns
in
Visitedset.iter do_one vis ;
Int.Set.iter ~f:(fun n -> s := !s ^ " " ^ string_of_int n) !lines ;
!s
(** A spec consists of:
pre: a joined prop
post: a list of props with path
visited: a list of pairs (node_id, line) for the visited nodes *)
type 'a spec = {pre: 'a Jprop.t; posts: ('a Prop.t * Paths.Path.t) list; visited: Visitedset.t}
(** encapsulate type for normalized specs *)
module NormSpec : sig
type t
val normalize : Tenv.t -> Prop.normal spec -> t
val tospecs : t list -> Prop.normal spec list
val compact : Sil.sharing_env -> t -> t
(** Return a compact representation of the spec *)
val erase_join_info_pre : Tenv.t -> t -> t
(** Erase join info from pre of spec *)
end = struct
type t = Prop.normal spec
let tospecs specs = specs
let gen_free_vars tenv (spec: Prop.normal spec) =
let open Sequence.Generator in
Jprop.sorted_gen_free_vars tenv spec.pre
>>= fun () ->
ISequence.gen_sequence_list spec.posts ~f:(fun (p, _) ->
Prop.dfs_sort tenv p |> Prop.sorted_gen_free_vars )
let free_vars tenv spec = Sequence.Generator.run (gen_free_vars tenv spec)
let spec_sub tenv sub spec =
{ pre= Jprop.normalize tenv (Jprop.jprop_sub sub spec.pre)
; posts=
List.map ~f:(fun (p, path) -> (Prop.normalize tenv (Prop.prop_sub sub p), path)) spec.posts
; visited= spec.visited }
(** Convert spec into normal form w.r.t. variable renaming *)
let normalize tenv (spec: Prop.normal spec) : Prop.normal spec =
let idlist = free_vars tenv spec |> Ident.hashqueue_of_sequence |> Ident.HashQueue.keys in
let count = ref 0 in
let sub =
Sil.subst_of_list
(List.map
~f:(fun id -> incr count ; (id, Exp.Var (Ident.create_normal Ident.name_spec !count)))
idlist)
in
spec_sub tenv sub spec
(** Return a compact representation of the spec *)
let compact sh spec =
let pre = Jprop.compact sh spec.pre in
let posts = List.map ~f:(fun (p, path) -> (Prop.prop_compact sh p, path)) spec.posts in
{pre; posts; visited= spec.visited}
(** Erase join info from pre of spec *)
let erase_join_info_pre tenv spec =
let spec' = {spec with pre= Jprop.Prop (1, Jprop.to_prop spec.pre)} in
normalize tenv spec'
end
(** Convert spec into normal form w.r.t. variable renaming *)
let spec_normalize = NormSpec.normalize
(** Cast a list of normalized specs to a list of specs *)
let normalized_specs_to_specs = NormSpec.tospecs
open PolyVariantEqual
(** Execution statistics *)
type stats =
@ -259,17 +28,13 @@ let pp_status fmt status = F.pp_print_string fmt (string_of_status status)
let equal_status = [%compare.equal : status]
type phase = FOOTPRINT | RE_EXECUTION [@@deriving compare]
let equal_phase = [%compare.equal : phase]
(** Payload: results of some analysis *)
type payload =
{ annot_map: AnnotReachabilityDomain.astate option
; biabduction: BiabductionSummary.t option
; buffer_overrun: BufferOverrunDomain.Summary.t option
; crashcontext_frame: Stacktree_t.stacktree option
; litho: LithoDomain.astate option
; preposts: NormSpec.t list option
; quandary: QuandarySummary.t option
; racerd: RacerDDomain.summary option
; resources: ResourceLeakDomain.summary option
@ -280,8 +45,7 @@ type payload =
; starvation: StarvationDomain.summary option }
type summary =
{ phase: phase (** in FOOTPRINT phase or in RE_EXECUTION PHASE *)
; payload: payload (** payload containing the result of some analysis *)
{ payload: payload (** payload containing the result of some analysis *)
; sessions: int ref (** Session number: how many nodes went trough symbolic execution *)
; stats: stats (** statistics: execution time and list of errors *)
; status: status (** Analysis status of the procedure *)
@ -303,9 +67,6 @@ let get_err_log summary = (get_attributes summary).ProcAttributes.err_log
let get_loc summary = (get_attributes summary).ProcAttributes.loc
(** Return the current phase for the proc *)
let get_phase summary = summary.phase
type spec_tbl = summary Typ.Procname.Hash.t
let spec_tbl : spec_tbl = Typ.Procname.Hash.create 128
@ -329,58 +90,6 @@ let pp_stats fmt stats =
F.fprintf fmt "FAILURE:%a SYMOPS:%d@\n" pp_failure_kind_opt stats.stats_failure stats.symops
(** Print the spec *)
let pp_spec pe num_opt fmt spec =
let num_str =
match num_opt with
| None ->
"----------"
| Some (n, tot) ->
Format.sprintf "%d of %d [nvisited:%s]" n tot (visited_str spec.visited)
in
let pre = Jprop.to_prop spec.pre in
let pe_post = Prop.prop_update_obj_sub pe pre in
let post_list = List.map ~f:fst spec.posts in
match pe.Pp.kind with
| TEXT ->
F.fprintf fmt "--------------------------- %s ---------------------------@\n" num_str ;
F.fprintf fmt "PRE:@\n%a@\n" (Prop.pp_prop Pp.text) pre ;
F.fprintf fmt "%a@\n" (Propgraph.pp_proplist pe_post "POST" (pre, true)) post_list ;
F.pp_print_string fmt "----------------------------------------------------------------"
| HTML ->
F.fprintf fmt "--------------------------- %s ---------------------------@\n" num_str ;
F.fprintf fmt "PRE:@\n%a%a%a@\n" Io_infer.Html.pp_start_color Pp.Blue
(Prop.pp_prop (Pp.html Blue))
pre Io_infer.Html.pp_end_color () ;
(Propgraph.pp_proplist pe_post "POST" (pre, true)) fmt post_list ;
F.pp_print_string fmt "----------------------------------------------------------------"
(** Dump a spec *)
let d_spec (spec: 'a spec) = L.add_print_action (L.PTspec, Obj.repr spec)
let pp_specs pe fmt specs =
let total = List.length specs in
let cnt = ref 0 in
match pe.Pp.kind with
| TEXT ->
List.iter
~f:(fun spec ->
incr cnt ;
(pp_spec pe (Some (!cnt, total))) fmt spec )
specs
| HTML ->
List.iter
~f:(fun spec ->
incr cnt ;
F.fprintf fmt "%a<br>@\n" (pp_spec pe (Some (!cnt, total))) spec )
specs
let describe_phase summary =
("Phase", if equal_phase summary.phase FOOTPRINT then "FOOTPRINT" else "RE_EXECUTION")
(** Return the signature of a procedure declaration as a string *)
let get_signature summary =
let s = ref "" in
@ -394,19 +103,13 @@ let get_signature summary =
(get_proc_name summary) !s
let get_specs_from_preposts preposts = Option.value_map ~f:NormSpec.tospecs ~default:[] preposts
let get_specs_from_payload summary = get_specs_from_preposts summary.payload.preposts
let pp_summary_no_stats_specs fmt summary =
let pp_pair fmt (x, y) = F.fprintf fmt "%s: %s" x y in
F.fprintf fmt "%s@\n" (get_signature summary) ;
F.fprintf fmt "%a@\n" pp_status summary.status ;
F.fprintf fmt "%a@\n" pp_pair (describe_phase summary)
F.fprintf fmt "%a@\n" pp_status summary.status
let pp_payload pe fmt
{ preposts
{ biabduction
; typestate
; crashcontext_frame
; quandary
@ -425,8 +128,8 @@ let pp_payload pe fmt
()
in
F.fprintf fmt "%a%a%a%a%a%a%a%a%a%a%a%a@\n"
(pp_opt "PrePosts" (pp_specs pe))
(Option.map ~f:NormSpec.tospecs preposts)
(pp_opt "Biabduction" (BiabductionSummary.pp pe))
biabduction
(pp_opt "TypeState" (TypeState.pp TypeState.unit_ext))
typestate
(pp_opt "CrashContext" Crashcontext.pp_stacktree)
@ -471,17 +174,6 @@ let empty_stats =
{stats_failure= None; symops= 0; nodes_visited_fp= IntSet.empty; nodes_visited_re= IntSet.empty}
let payload_compact sh payload =
match payload.preposts with
| Some specs ->
{payload with preposts= Some (List.map ~f:(NormSpec.compact sh) specs)}
| None ->
payload
(** Return a compact representation of the summary *)
let summary_compact sh summary = {summary with payload= payload_compact sh summary.payload}
(** Add the summary to the table for the given function *)
let add_summary (proc_name: Typ.Procname.t) (summary: summary) : unit =
Typ.Procname.Hash.replace spec_tbl proc_name summary
@ -552,14 +244,7 @@ let get_summary proc_name =
load_summary_to_spec_table proc_name
let get_summary_unsafe s proc_name =
match get_summary proc_name with
| None ->
L.(die InternalError)
"[%s] Specs.get_summary_unsafe: %a Not found" s Typ.Procname.pp proc_name
| Some summary ->
summary
let get_summary_unsafe proc_name = Option.value_exn (get_summary proc_name)
(** Check if the procedure is from a library:
It's not defined, and there is no spec file for it. *)
@ -598,12 +283,8 @@ let pdesc_resolve_attributes proc_desc =
(** Save summary for the procedure into the spec database *)
let store_summary (summ1: summary) =
let summ2 =
if Config.save_compact_summaries then summary_compact (Sil.create_sharing_env ()) summ1
else summ1
in
let final_summary = {summ2 with status= Analyzed} in
let store_summary (summ: summary) =
let final_summary = {summ with status= Analyzed} in
let proc_name = get_proc_name final_summary in
(* Make sure the summary in memory is identical to the saved one *)
add_summary proc_name final_summary ;
@ -613,7 +294,7 @@ let store_summary (summ1: summary) =
let empty_payload =
{ preposts= None
{ biabduction= None
; typestate= None
; annot_map= None
; crashcontext_frame= None
@ -633,12 +314,7 @@ let empty_payload =
initializes the summary for [proc_name] given dependent procs in list [depend_list]. *)
let init_summary proc_desc =
let summary =
{ phase= FOOTPRINT
; sessions= ref 0
; payload= empty_payload
; stats= empty_stats
; status= Pending
; proc_desc }
{sessions= ref 0; payload= empty_payload; stats= empty_stats; status= Pending; proc_desc}
in
Typ.Procname.Hash.replace spec_tbl (Procdesc.get_proc_name proc_desc) summary ;
summary

@ -14,63 +14,6 @@ open! IStd
(** {2 Spec Tables} *)
(** Module for joined props: the result of joining together propositions repeatedly *)
module Jprop : sig
(** Remember when a prop is obtained as the join of two other props; the first parameter is an id *)
type 'a t = Prop of int * 'a Prop.t | Joined of int * 'a Prop.t * 'a t * 'a t
val compare : 'a t -> 'a t -> int
(** Comparison for joined_prop *)
val equal : 'a t -> 'a t -> bool
(** Return true if the two join_prop's are equal *)
val d_shallow : Prop.normal t -> unit
(** Dump the toplevel prop *)
val d_list : bool -> Prop.normal t list -> unit
(** dump a joined prop list, the boolean indicates whether to print toplevel props only *)
val free_vars : Prop.normal t -> Ident.t Sequence.t
val filter : ('a t -> 'b option) -> 'a t list -> 'b list
(** [jprop_filter filter joinedprops] applies [filter] to the elements
of [joindeprops] and applies it to the subparts if the result is
[None]. Returns the most absract results which pass [filter]. *)
val jprop_sub : Sil.subst -> Prop.normal t -> Prop.exposed t
(** apply a substitution to a jprop *)
val map : ('a Prop.t -> 'b Prop.t) -> 'a t -> 'b t
(** map the function to each prop in the jprop, pointwise *)
val pp_list : Pp.env -> bool -> Format.formatter -> Prop.normal t list -> unit
(** Print a list of joined props, the boolean indicates whether to print subcomponents of joined props *)
val pp_short : Pp.env -> Format.formatter -> Prop.normal t -> unit
(** Print the toplevel prop *)
val to_prop : 'a t -> 'a Prop.t
(** Extract the toplevel jprop of a prop *)
end
(** set of visited nodes: node id and list of lines of all the instructions *)
module Visitedset : Caml.Set.S with type elt = Procdesc.Node.id * int list
(** A spec consists of:
pre: a joined prop
posts: a list of props with path
visited: a list of pairs (node_id, line) for the visited nodes *)
type 'a spec = {pre: 'a Jprop.t; posts: ('a Prop.t * Paths.Path.t) list; visited: Visitedset.t}
(** encapsulate type for normalized specs *)
module NormSpec : sig
type t
val erase_join_info_pre : Tenv.t -> t -> t
(** Erase join info from pre of spec *)
end
(** Execution statistics *)
type stats =
{ stats_failure: SymOp.failure_kind option
@ -88,17 +31,13 @@ val equal_status : status -> status -> bool
val string_of_status : status -> string
type phase = FOOTPRINT | RE_EXECUTION
val equal_phase : phase -> phase -> bool
(** Payload: results of some analysis *)
type payload =
{ annot_map: AnnotReachabilityDomain.astate option
; biabduction: BiabductionSummary.t option
; buffer_overrun: BufferOverrunDomain.Summary.t option
; crashcontext_frame: Stacktree_t.stacktree option
; litho: LithoDomain.astate option
; preposts: NormSpec.t list option
; quandary: QuandarySummary.t option
; racerd: RacerDDomain.summary option
; resources: ResourceLeakDomain.summary option
@ -110,8 +49,7 @@ type payload =
(** Procedure summary *)
type summary =
{ phase: phase (** in FOOTPRINT phase or in RE_EXECUTION PHASE *)
; payload: payload (** payload containing the result of some analysis *)
{ payload: payload (** payload containing the result of some analysis *)
; sessions: int ref (** Session number: how many nodes went trough symbolic execution *)
; stats: stats (** statistics: execution time and list of errors *)
; status: status (** Analysis status of the procedure *)
@ -129,9 +67,6 @@ val summary_exists_in_models : Typ.Procname.t -> bool
val clear_spec_tbl : unit -> unit
(** remove all the elements from the spec table *)
val d_spec : 'a spec -> unit
(** Dump a spec *)
val get_summary : Typ.Procname.t -> summary option
(** Return the summary option for the procedure name *)
@ -146,9 +81,6 @@ val get_attributes : summary -> ProcAttributes.t
val get_formals : summary -> (Mangled.t * Typ.t) list
(** Get the formal parameters of the procedure *)
val get_phase : summary -> phase
(** Return the current phase for the proc *)
val get_err_log : summary -> Errlog.t
val get_loc : summary -> Location.t
@ -156,10 +88,7 @@ val get_loc : summary -> Location.t
val get_signature : summary -> string
(** Return the signature of a procedure declaration as a string *)
val get_specs_from_payload : summary -> Prop.normal spec list
(** Get the specs from the payload of the summary. *)
val get_summary_unsafe : string -> Typ.Procname.t -> summary
val get_summary_unsafe : Typ.Procname.t -> summary
(** @deprecated Return the summary for the procedure name. Raises an exception when not found. *)
val get_status : summary -> status
@ -171,12 +100,6 @@ val reset_summary : Procdesc.t -> summary
val load_summary : DB.filename -> summary option
(** Load procedure summary from the given file *)
val normalized_specs_to_specs : NormSpec.t list -> Prop.normal spec list
(** Cast a list of normalized specs to a list of specs *)
val pp_spec : Pp.env -> (int * int) option -> Format.formatter -> Prop.normal spec -> unit
(** Print the spec *)
val pp_summary_html : SourceFile.t -> Pp.color -> Format.formatter -> summary -> unit
(** Print the summary in html format *)
@ -197,8 +120,5 @@ val proc_is_library : ProcAttributes.t -> bool
(** Check if the procedure is from a library:
It's not defined, and there is no spec file for it. *)
val spec_normalize : Tenv.t -> Prop.normal spec -> NormSpec.t
(** Convert spec into normal form w.r.t. variable renaming *)
val store_summary : summary -> unit
(** Save summary for the procedure into the spec database *)

@ -0,0 +1,301 @@
(*
* Copyright (c) 2018 - 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.
*)
open! IStd
(** Specifications and spec table *)
module L = Logging
module F = Format
(** Module for joined props *)
module Jprop = struct
(** type aliases for component of t values that compare should ignore *)
type id_ = int
let compare_id_ _ _ = 0
(** Remember when a prop is obtained as the join of two other props; the first parameter is an id *)
type 'a t = Prop of id_ * 'a Prop.t | Joined of id_ * 'a Prop.t * 'a t * 'a t
[@@deriving compare]
(** Comparison for joined_prop *)
let compare jp1 jp2 = compare (fun _ _ -> 0) jp1 jp2
(** Return true if the two join_prop's are equal *)
let equal jp1 jp2 = Int.equal (compare jp1 jp2) 0
let to_prop = function Prop (_, p) -> p | Joined (_, p, _, _) -> p
let rec sorted_gen_free_vars tenv =
let open Sequence.Generator in
function
| Prop (_, p) ->
Prop.dfs_sort tenv p |> Prop.sorted_gen_free_vars
| Joined (_, p, jp1, jp2) ->
Prop.dfs_sort tenv p |> Prop.sorted_gen_free_vars
>>= fun () -> sorted_gen_free_vars tenv jp1 >>= fun () -> sorted_gen_free_vars tenv jp2
let rec normalize tenv = function
| Prop (n, p) ->
Prop (n, Prop.normalize tenv p)
| Joined (n, p, jp1, jp2) ->
Joined (n, Prop.normalize tenv p, normalize tenv jp1, normalize tenv jp2)
(** Return a compact representation of the jprop *)
let rec compact sh = function
| Prop (n, p) ->
Prop (n, Prop.prop_compact sh p)
| Joined (n, p, jp1, jp2) ->
Joined (n, Prop.prop_compact sh p, compact sh jp1, compact sh jp2)
(** Print the toplevel prop *)
let pp_short pe f jp = Prop.pp_prop pe f (to_prop jp)
(** Dump the toplevel prop *)
let d_shallow (jp: Prop.normal t) = L.add_print_action (L.PTjprop_short, Obj.repr jp)
(** Get identifies of the jprop *)
let get_id = function Prop (n, _) -> n | Joined (n, _, _, _) -> n
(** Print a list of joined props, the boolean indicates whether to print subcomponents of joined props *)
let pp_list pe shallow f jplist =
let rec pp_seq_newline f = function
| [] ->
()
| [Prop (n, p)] ->
F.fprintf f "PROP %d:@\n%a" n (Prop.pp_prop pe) p
| [Joined (n, p, p1, p2)] ->
if not shallow then F.fprintf f "%a@\n" pp_seq_newline [p1] ;
if not shallow then F.fprintf f "%a@\n" pp_seq_newline [p2] ;
F.fprintf f "PROP %d (join of %d,%d):@\n%a" n (get_id p1) (get_id p2) (Prop.pp_prop pe) p
| jp :: l ->
F.fprintf f "%a@\n" pp_seq_newline [jp] ;
pp_seq_newline f l
in
pp_seq_newline f jplist
(** dump a joined prop list, the boolean indicates whether to print toplevel props only *)
let d_list (shallow: bool) (jplist: Prop.normal t list) =
L.add_print_action (L.PTjprop_list, Obj.repr (shallow, jplist))
let rec gen_free_vars =
let open Sequence.Generator in
function
| Prop (_, p) ->
Prop.gen_free_vars p
| Joined (_, p, jp1, jp2) ->
Prop.gen_free_vars p >>= fun () -> gen_free_vars jp1 >>= fun () -> gen_free_vars jp2
let free_vars jp = Sequence.Generator.run (gen_free_vars jp)
let rec jprop_sub sub = function
| Prop (n, p) ->
Prop (n, Prop.prop_sub sub p)
| Joined (n, p, jp1, jp2) ->
let p' = Prop.prop_sub sub p in
let jp1' = jprop_sub sub jp1 in
let jp2' = jprop_sub sub jp2 in
Joined (n, p', jp1', jp2')
let filter (f: 'a t -> 'b option) jpl =
let rec do_filter acc = function
| [] ->
acc
| (Prop _ as jp) :: jpl -> (
match f jp with Some x -> do_filter (x :: acc) jpl | None -> do_filter acc jpl )
| (Joined (_, _, jp1, jp2) as jp) :: jpl ->
match f jp with
| Some x ->
do_filter (x :: acc) jpl
| None ->
do_filter acc (jpl @ [jp1; jp2])
in
do_filter [] jpl
let rec map (f: 'a Prop.t -> 'b Prop.t) = function
| Prop (n, p) ->
Prop (n, f p)
| Joined (n, p, jp1, jp2) ->
Joined (n, f p, map f jp1, map f jp2)
(*
let rec jprop_sub sub = function
| Prop (n, p) -> Prop (n, Prop.prop_sub sub p)
| Joined (n, p, jp1, jp2) ->
Joined (n, Prop.prop_sub sub p, jprop_sub sub jp1, jprop_sub sub jp2)
*)
end
(***** End of module Jprop *****)
module Visitedset = Caml.Set.Make (struct
type t = Procdesc.Node.id * int list
let compare (node_id1, _) (node_id2, _) = Procdesc.Node.compare_id node_id1 node_id2
end)
let visited_str vis =
let s = ref "" in
let lines = ref Int.Set.empty in
let do_one (_, ns) =
(* if List.length ns > 1 then
begin
let ss = ref "" in
List.iter ~f:(fun n -> ss := !ss ^ " " ^ string_of_int n) ns;
L.out "Node %d has lines %s@." node !ss
end; *)
List.iter ~f:(fun n -> lines := Int.Set.add !lines n) ns
in
Visitedset.iter do_one vis ;
Int.Set.iter ~f:(fun n -> s := !s ^ " " ^ string_of_int n) !lines ;
!s
(** A spec consists of:
pre: a joined prop
post: a list of props with path
visited: a list of pairs (node_id, line) for the visited nodes *)
type 'a spec = {pre: 'a Jprop.t; posts: ('a Prop.t * Paths.Path.t) list; visited: Visitedset.t}
(** encapsulate type for normalized specs *)
module NormSpec : sig
type t
val normalize : Tenv.t -> Prop.normal spec -> t
val tospecs : t list -> Prop.normal spec list
val compact : Sil.sharing_env -> t -> t
(** Return a compact representation of the spec *)
val erase_join_info_pre : Tenv.t -> t -> t
(** Erase join info from pre of spec *)
end = struct
type t = Prop.normal spec
let tospecs specs = specs
let gen_free_vars tenv (spec: Prop.normal spec) =
let open Sequence.Generator in
Jprop.sorted_gen_free_vars tenv spec.pre
>>= fun () ->
ISequence.gen_sequence_list spec.posts ~f:(fun (p, _) ->
Prop.dfs_sort tenv p |> Prop.sorted_gen_free_vars )
let free_vars tenv spec = Sequence.Generator.run (gen_free_vars tenv spec)
let spec_sub tenv sub spec =
{ pre= Jprop.normalize tenv (Jprop.jprop_sub sub spec.pre)
; posts=
List.map ~f:(fun (p, path) -> (Prop.normalize tenv (Prop.prop_sub sub p), path)) spec.posts
; visited= spec.visited }
(** Convert spec into normal form w.r.t. variable renaming *)
let normalize tenv (spec: Prop.normal spec) : Prop.normal spec =
let idlist = free_vars tenv spec |> Ident.hashqueue_of_sequence |> Ident.HashQueue.keys in
let count = ref 0 in
let sub =
Sil.subst_of_list
(List.map
~f:(fun id -> incr count ; (id, Exp.Var (Ident.create_normal Ident.name_spec !count)))
idlist)
in
spec_sub tenv sub spec
(** Return a compact representation of the spec *)
let compact sh spec =
let pre = Jprop.compact sh spec.pre in
let posts = List.map ~f:(fun (p, path) -> (Prop.prop_compact sh p, path)) spec.posts in
{pre; posts; visited= spec.visited}
(** Erase join info from pre of spec *)
let erase_join_info_pre tenv spec =
let spec' = {spec with pre= Jprop.Prop (1, Jprop.to_prop spec.pre)} in
normalize tenv spec'
end
(** Convert spec into normal form w.r.t. variable renaming *)
let spec_normalize = NormSpec.normalize
(** Cast a list of normalized specs to a list of specs *)
let normalized_specs_to_specs = NormSpec.tospecs
type phase = FOOTPRINT | RE_EXECUTION [@@deriving compare]
let equal_phase = [%compare.equal : phase]
(** Print the spec *)
let pp_spec pe num_opt fmt spec =
let num_str =
match num_opt with
| None ->
"----------"
| Some (n, tot) ->
Format.sprintf "%d of %d [nvisited:%s]" n tot (visited_str spec.visited)
in
let pre = Jprop.to_prop spec.pre in
let pe_post = Prop.prop_update_obj_sub pe pre in
let post_list = List.map ~f:fst spec.posts in
match pe.Pp.kind with
| TEXT ->
F.fprintf fmt "--------------------------- %s ---------------------------@\n" num_str ;
F.fprintf fmt "PRE:@\n%a@\n" (Prop.pp_prop Pp.text) pre ;
F.fprintf fmt "%a@\n" (Propgraph.pp_proplist pe_post "POST" (pre, true)) post_list ;
F.pp_print_string fmt "----------------------------------------------------------------"
| HTML ->
F.fprintf fmt "--------------------------- %s ---------------------------@\n" num_str ;
F.fprintf fmt "PRE:@\n%a%a%a@\n" Io_infer.Html.pp_start_color Pp.Blue
(Prop.pp_prop (Pp.html Blue))
pre Io_infer.Html.pp_end_color () ;
(Propgraph.pp_proplist pe_post "POST" (pre, true)) fmt post_list ;
F.pp_print_string fmt "----------------------------------------------------------------"
(** Dump a spec *)
let d_spec (spec: 'a spec) = L.add_print_action (L.PTspec, Obj.repr spec)
let pp_specs pe fmt specs =
let total = List.length specs in
let cnt = ref 0 in
match pe.Pp.kind with
| TEXT ->
List.iter
~f:(fun spec ->
incr cnt ;
(pp_spec pe (Some (!cnt, total))) fmt spec )
specs
| HTML ->
List.iter
~f:(fun spec ->
incr cnt ;
F.fprintf fmt "%a<br>@\n" (pp_spec pe (Some (!cnt, total))) spec )
specs
let string_of_phase = function FOOTPRINT -> "FOOTPRINT" | RE_EXECUTION -> "RE_EXECUTION"
let get_specs_from_preposts preposts = Option.value_map ~f:NormSpec.tospecs ~default:[] preposts
type t = {preposts: NormSpec.t list; phase: phase}
let pp pe fmt {preposts; phase} =
F.fprintf fmt "phase= %s@\n%a" (string_of_phase phase) (pp_specs pe) (NormSpec.tospecs preposts)

@ -0,0 +1,92 @@
(*
* Copyright (c) 2018 - 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.
*)
open! IStd
(** Module for joined props: the result of joining together propositions repeatedly *)
module Jprop : sig
(** Remember when a prop is obtained as the join of two other props; the first parameter is an id *)
type 'a t = Prop of int * 'a Prop.t | Joined of int * 'a Prop.t * 'a t * 'a t
val compare : 'a t -> 'a t -> int
(** Comparison for joined_prop *)
val equal : 'a t -> 'a t -> bool
(** Return true if the two join_prop's are equal *)
val d_shallow : Prop.normal t -> unit
(** Dump the toplevel prop *)
val d_list : bool -> Prop.normal t list -> unit
(** dump a joined prop list, the boolean indicates whether to print toplevel props only *)
val free_vars : Prop.normal t -> Ident.t Sequence.t
val filter : ('a t -> 'b option) -> 'a t list -> 'b list
(** [jprop_filter filter joinedprops] applies [filter] to the elements
of [joindeprops] and applies it to the subparts if the result is
[None]. Returns the most absract results which pass [filter]. *)
val jprop_sub : Sil.subst -> Prop.normal t -> Prop.exposed t
(** apply a substitution to a jprop *)
val map : ('a Prop.t -> 'b Prop.t) -> 'a t -> 'b t
(** map the function to each prop in the jprop, pointwise *)
val pp_list : Pp.env -> bool -> Format.formatter -> Prop.normal t list -> unit
(** Print a list of joined props, the boolean indicates whether to print subcomponents of joined props *)
val pp_short : Pp.env -> Format.formatter -> Prop.normal t -> unit
(** Print the toplevel prop *)
val to_prop : 'a t -> 'a Prop.t
(** Extract the toplevel jprop of a prop *)
end
(** set of visited nodes: node id and list of lines of all the instructions *)
module Visitedset : Caml.Set.S with type elt = Procdesc.Node.id * int list
(** A spec consists of:
pre: a joined prop
posts: a list of props with path
visited: a list of pairs (node_id, line) for the visited nodes *)
type 'a spec = {pre: 'a Jprop.t; posts: ('a Prop.t * Paths.Path.t) list; visited: Visitedset.t}
(** encapsulate type for normalized specs *)
module NormSpec : sig
type t
val compact : Sil.sharing_env -> t -> t
(** Return a compact representation of the spec *)
val erase_join_info_pre : Tenv.t -> t -> t
(** Erase join info from pre of spec *)
end
val normalized_specs_to_specs : NormSpec.t list -> Prop.normal spec list
(** Cast a list of normalized specs to a list of specs *)
val d_spec : 'a spec -> unit
(** Dump a spec *)
val spec_normalize : Tenv.t -> Prop.normal spec -> NormSpec.t
(** Convert spec into normal form w.r.t. variable renaming *)
val pp_spec : Pp.env -> (int * int) option -> Format.formatter -> Prop.normal spec -> unit
(** Print the spec *)
type phase = FOOTPRINT | RE_EXECUTION
val equal_phase : phase -> phase -> bool
val get_specs_from_preposts : NormSpec.t list option -> Prop.normal spec list
type t = {preposts: NormSpec.t list; phase: phase}
val pp : Pp.env -> Format.formatter -> t -> unit

@ -2023,35 +2023,38 @@ let pathset_collapse_impl pname tenv pset =
let jprop_partial_join tenv mode jp1 jp2 =
let p1, p2 = (Prop.expose (Specs.Jprop.to_prop jp1), Prop.expose (Specs.Jprop.to_prop jp2)) in
let p1, p2 =
( Prop.expose (BiabductionSummary.Jprop.to_prop jp1)
, Prop.expose (BiabductionSummary.Jprop.to_prop jp2) )
in
try
let p = eprop_partial_join tenv mode p1 p2 in
let p_renamed = Prop.prop_rename_primed_footprint_vars tenv p in
Some (Specs.Jprop.Joined (0, p_renamed, jp1, jp2))
Some (BiabductionSummary.Jprop.Joined (0, p_renamed, jp1, jp2))
with Sil.JoinFail -> None
let jplist_collapse tenv mode jplist =
let f = jprop_partial_join tenv mode in
list_reduce "JOIN" Specs.Jprop.d_shallow f jplist
list_reduce "JOIN" BiabductionSummary.Jprop.d_shallow f jplist
(** Add identifiers to a list of jprops *)
let jprop_list_add_ids jplist =
let seq_number = ref 0 in
let rec do_jprop = function
| Specs.Jprop.Prop (_, p) ->
incr seq_number ; Specs.Jprop.Prop (!seq_number, p)
| Specs.Jprop.Joined (_, p, jp1, jp2) ->
| BiabductionSummary.Jprop.Prop (_, p) ->
incr seq_number ; BiabductionSummary.Jprop.Prop (!seq_number, p)
| BiabductionSummary.Jprop.Joined (_, p, jp1, jp2) ->
let jp1' = do_jprop jp1 in
let jp2' = do_jprop jp2 in
incr seq_number ; Specs.Jprop.Joined (!seq_number, p, jp1', jp2')
incr seq_number ; BiabductionSummary.Jprop.Joined (!seq_number, p, jp1', jp2')
in
List.map ~f:(fun (p, path) -> (do_jprop p, path)) jplist
let proplist_collapse tenv mode plist =
let jplist = List.map ~f:(fun (p, path) -> (Specs.Jprop.Prop (0, p), path)) plist in
let jplist = List.map ~f:(fun (p, path) -> (BiabductionSummary.Jprop.Prop (0, p), path)) plist in
let jplist_joined = jplist_collapse tenv mode (jplist_collapse tenv mode jplist) in
jprop_list_add_ids jplist_joined
@ -2065,7 +2068,7 @@ let pathset_collapse tenv pset =
let plist = Paths.PathSet.elements pset in
let plist' = proplist_collapse tenv JoinState.Post plist in
Paths.PathSet.from_renamed_list
(List.map ~f:(fun (p, path) -> (Specs.Jprop.to_prop p, path)) plist')
(List.map ~f:(fun (p, path) -> (BiabductionSummary.Jprop.to_prop p, path)) plist')
let pathset_join pname tenv (pset1: Paths.PathSet.t) (pset2: Paths.PathSet.t)

@ -19,7 +19,8 @@ val pathset_join :
-> Paths.PathSet.t * Paths.PathSet.t
(** Join two pathsets *)
val proplist_collapse_pre : Tenv.t -> Prop.normal Prop.t list -> Prop.normal Specs.Jprop.t list
val proplist_collapse_pre :
Tenv.t -> Prop.normal Prop.t list -> Prop.normal BiabductionSummary.Jprop.t list
val pathset_collapse : Tenv.t -> Paths.PathSet.t -> Paths.PathSet.t

@ -373,7 +373,7 @@ let reason_to_skip ~callee_desc : string option =
| `Summary callee_summary ->
let attr_reason = Specs.get_attributes callee_summary |> reason_from_attributes in
if Option.is_some attr_reason then attr_reason
else if List.is_empty (Specs.get_specs_from_payload callee_summary) then
else if List.is_empty (Tabulation.get_specs_from_payload callee_summary) then
Some "empty list of specs"
else (* we are not skipping *) None
| `ProcDesc procdesc ->

@ -98,6 +98,17 @@ let log_call_trace caller_name callee_name ?reason loc res =
(***************)
let get_specs_from_payload summary =
Option.map summary.Specs.payload.biabduction ~f:(fun BiabductionSummary.({preposts}) -> preposts)
|> BiabductionSummary.get_specs_from_preposts
(** Return the current phase for the proc *)
let get_phase summary =
Option.value_map summary.Specs.payload.biabduction ~default:BiabductionSummary.FOOTPRINT ~f:
(fun BiabductionSummary.({phase}) -> phase )
(** Rename the variables in the spec. *)
let spec_rename_vars pname spec =
let prop_add_callee_suffix p =
@ -105,34 +116,39 @@ let spec_rename_vars pname spec =
Prop.prop_expmap f p
in
let jprop_add_callee_suffix = function
| Specs.Jprop.Prop (n, p) ->
Specs.Jprop.Prop (n, prop_add_callee_suffix p)
| Specs.Jprop.Joined (n, p, jp1, jp2) ->
Specs.Jprop.Joined (n, prop_add_callee_suffix p, jp1, jp2)
| BiabductionSummary.Jprop.Prop (n, p) ->
BiabductionSummary.Jprop.Prop (n, prop_add_callee_suffix p)
| BiabductionSummary.Jprop.Joined (n, p, jp1, jp2) ->
BiabductionSummary.Jprop.Joined (n, prop_add_callee_suffix p, jp1, jp2)
in
let fav =
let fav = Specs.Jprop.free_vars spec.Specs.pre |> Ident.hashqueue_of_sequence in
List.fold_left spec.Specs.posts ~init:fav ~f:(fun fav (p, _) ->
let fav =
BiabductionSummary.Jprop.free_vars spec.BiabductionSummary.pre |> Ident.hashqueue_of_sequence
in
List.fold_left spec.BiabductionSummary.posts ~init:fav ~f:(fun fav (p, _) ->
Prop.free_vars p |> Ident.hashqueue_of_sequence ~init:fav )
in
let ids = Ident.HashQueue.keys fav in
let ids' = List.map ~f:(fun i -> (i, Ident.create_fresh Ident.kprimed)) ids in
let ren_sub = Sil.subst_of_list (List.map ~f:(fun (i, i') -> (i, Exp.Var i')) ids') in
let pre' = Specs.Jprop.jprop_sub ren_sub spec.Specs.pre in
let posts' = List.map ~f:(fun (p, path) -> (Prop.prop_sub ren_sub p, path)) spec.Specs.posts in
let pre' = BiabductionSummary.Jprop.jprop_sub ren_sub spec.BiabductionSummary.pre in
let posts' =
List.map ~f:(fun (p, path) -> (Prop.prop_sub ren_sub p, path)) spec.BiabductionSummary.posts
in
let pre'' = jprop_add_callee_suffix pre' in
let posts'' = List.map ~f:(fun (p, path) -> (prop_add_callee_suffix p, path)) posts' in
{Specs.pre= pre''; Specs.posts= posts''; Specs.visited= spec.Specs.visited}
BiabductionSummary.{pre= pre''; posts= posts''; visited= spec.BiabductionSummary.visited}
(** Find and number the specs for [proc_name],
after renaming their vars, and also return the parameters *)
let spec_find_rename trace_call summary : (int * Prop.exposed Specs.spec) list * Pvar.t list =
let spec_find_rename trace_call summary
: (int * Prop.exposed BiabductionSummary.spec) list * Pvar.t list =
let proc_name = Specs.get_proc_name summary in
try
let count = ref 0 in
let f spec = incr count ; (!count, spec_rename_vars proc_name spec) in
let specs = Specs.get_specs_from_payload summary in
let specs = get_specs_from_payload summary in
let formals = Specs.get_formals summary in
if List.is_empty specs then (
trace_call CR_not_found ;
@ -1093,11 +1109,11 @@ let add_missing_field_to_tenv ~missing_sigma exe_env caller_tenv callee_pname hp
(** Perform symbolic execution for a single spec *)
let exe_spec exe_env tenv ret_id (n, nspecs) caller_pdesc callee_pname loc prop path_pre
(spec: Prop.exposed Specs.spec) actual_params formal_params : abduction_res =
(spec: Prop.exposed BiabductionSummary.spec) actual_params formal_params : abduction_res =
let caller_pname = Procdesc.get_proc_name caller_pdesc in
let posts = mk_posts tenv prop callee_pname spec.Specs.posts in
let posts = mk_posts tenv prop callee_pname spec.BiabductionSummary.posts in
let actual_pre = mk_actual_precondition tenv prop actual_params formal_params in
let spec_pre = Specs.Jprop.to_prop spec.Specs.pre in
let spec_pre = BiabductionSummary.Jprop.to_prop spec.BiabductionSummary.pre in
L.d_strln ("EXECUTING SPEC " ^ string_of_int n ^ "/" ^ string_of_int nspecs) ;
L.d_strln "ACTUAL PRECONDITION =" ;
L.d_increase_indent 1 ;
@ -1106,7 +1122,7 @@ let exe_spec exe_env tenv ret_id (n, nspecs) caller_pdesc callee_pname loc prop
L.d_ln () ;
L.d_strln "SPEC =" ;
L.d_increase_indent 1 ;
Specs.d_spec spec ;
BiabductionSummary.d_spec spec ;
L.d_decrease_indent 1 ;
L.d_ln () ;
SymOp.pay () ;

@ -51,3 +51,9 @@ val exe_function_call :
-> (Exp.t * Typ.t) list -> Prop.normal Prop.t -> Paths.Path.t
-> (Prop.normal Prop.t * Paths.Path.t) list
(** Execute the function call and return the list of results with return value *)
val get_phase : Specs.summary -> BiabductionSummary.phase
(** Return the current phase for the proc *)
val get_specs_from_payload : Specs.summary -> Prop.normal BiabductionSummary.spec list
(** Get the specs from the payload of the summary. *)

@ -198,7 +198,7 @@ let do_meet_pre tenv pset =
(** Find the preconditions in the current spec table,
apply meet then join, and return the joined preconditions *)
let collect_preconditions tenv summary : Prop.normal Specs.Jprop.t list =
let collect_preconditions tenv summary : Prop.normal BiabductionSummary.Jprop.t list =
let proc_name = Specs.get_proc_name summary in
let collect_do_abstract_one tenv prop =
if !Config.footprint then Config.run_in_re_execution_mode (Abs.abstract_no_symop tenv) prop
@ -206,8 +206,8 @@ let collect_preconditions tenv summary : Prop.normal Specs.Jprop.t list =
in
let pres =
List.map
~f:(fun spec -> Specs.Jprop.to_prop spec.Specs.pre)
(Specs.get_specs_from_payload summary)
~f:(fun spec -> BiabductionSummary.Jprop.to_prop spec.BiabductionSummary.pre)
(Tabulation.get_specs_from_payload summary)
in
let pset = Propset.from_proplist tenv pres in
let pset' =
@ -235,26 +235,26 @@ let collect_preconditions tenv summary : Prop.normal Specs.Jprop.t list =
L.d_ln () ;
L.d_strln ("#### Footprint of " ^ Typ.Procname.to_string proc_name ^ " after Join ####") ;
L.d_increase_indent 1 ;
Specs.Jprop.d_list false jplist ;
BiabductionSummary.Jprop.d_list false jplist ;
L.d_decrease_indent 1 ;
L.d_ln () ;
let jplist' =
List.map ~f:(Specs.Jprop.map (Prop.prop_rename_primed_footprint_vars tenv)) jplist
List.map ~f:(BiabductionSummary.Jprop.map (Prop.prop_rename_primed_footprint_vars tenv)) jplist
in
L.d_strln ("#### Renamed footprint of " ^ Typ.Procname.to_string proc_name ^ ": ####") ;
L.d_increase_indent 1 ;
Specs.Jprop.d_list false jplist' ;
BiabductionSummary.Jprop.d_list false jplist' ;
L.d_decrease_indent 1 ;
L.d_ln () ;
let jplist'' =
let f p =
Prop.prop_primed_vars_to_normal_vars tenv (collect_do_abstract_one proc_name tenv p)
in
List.map ~f:(Specs.Jprop.map f) jplist'
List.map ~f:(BiabductionSummary.Jprop.map f) jplist'
in
L.d_strln ("#### Abstracted footprint of " ^ Typ.Procname.to_string proc_name ^ ": ####") ;
L.d_increase_indent 1 ;
Specs.Jprop.d_list false jplist'' ;
BiabductionSummary.Jprop.d_list false jplist'' ;
L.d_decrease_indent 1 ;
L.d_ln () ;
jplist''
@ -434,9 +434,13 @@ let forward_tabulate exe_env tenv proc_cfg wl =
in
let print_node_preamble curr_node session pathset_todo =
let log_string proc_name =
let summary = Specs.get_summary_unsafe "forward_tabulate" proc_name in
let summary = Specs.get_summary_unsafe proc_name in
let phase_string =
if Specs.equal_phase (Specs.get_phase summary) Specs.FOOTPRINT then "FP" else "RE"
if
BiabductionSummary.equal_phase (Tabulation.get_phase summary)
BiabductionSummary.FOOTPRINT
then "FP"
else "RE"
in
let status = Specs.get_status summary in
F.sprintf "[%s:%s] %s" phase_string (Specs.string_of_status status)
@ -505,7 +509,7 @@ let forward_tabulate exe_env tenv proc_cfg wl =
in
while not (Worklist.is_empty wl) do
let curr_node = Worklist.remove wl in
let summary = Specs.get_summary_unsafe "forward_tabulate" pname in
let summary = Specs.get_summary_unsafe pname in
mark_visited summary curr_node ;
(* mark nodes visited in fp and re phases *)
let session = incr summary.Specs.sessions ; !(summary.Specs.sessions) in
@ -555,7 +559,7 @@ let vset_ref_add_pathset vset_ref pathset =
let compute_visited vset =
let res = ref Specs.Visitedset.empty in
let res = ref BiabductionSummary.Visitedset.empty in
let node_get_all_lines n =
let node_loc = Procdesc.Node.get_loc n in
let instrs_loc = List.map ~f:Sil.instr_get_loc (ProcCfg.Exceptional.instrs n) in
@ -563,14 +567,14 @@ let compute_visited vset =
List.remove_consecutive_duplicates ~equal:Int.equal (List.sort ~compare:Int.compare lines)
in
let do_node n =
res := Specs.Visitedset.add (Procdesc.Node.get_id n, node_get_all_lines n) !res
res := BiabductionSummary.Visitedset.add (Procdesc.Node.get_id n, node_get_all_lines n) !res
in
Procdesc.NodeSet.iter do_node vset ;
!res
(** Extract specs from a pathset *)
let extract_specs tenv pdesc pathset : Prop.normal Specs.spec list =
let extract_specs tenv pdesc pathset : Prop.normal BiabductionSummary.spec list =
let pname = Procdesc.get_proc_name pdesc in
let sub =
let fav =
@ -605,7 +609,8 @@ let extract_specs tenv pdesc pathset : Prop.normal Specs.spec list =
let pre_post_map =
let add map (pre, post, visited) =
let current_posts, current_visited =
try Pmap.find pre map with Caml.Not_found -> (Paths.PathSet.empty, Specs.Visitedset.empty)
try Pmap.find pre map with Caml.Not_found ->
(Paths.PathSet.empty, BiabductionSummary.Visitedset.empty)
in
let new_posts =
match post with
@ -614,7 +619,7 @@ let extract_specs tenv pdesc pathset : Prop.normal Specs.spec list =
| Some (post, path) ->
Paths.PathSet.add_renamed_prop post path current_posts
in
let new_visited = Specs.Visitedset.union visited current_visited in
let new_visited = BiabductionSummary.Visitedset.union visited current_visited in
Pmap.add pre (new_posts, new_visited) map
in
List.fold ~f:add ~init:Pmap.empty pre_post_visited_list
@ -626,13 +631,13 @@ let extract_specs tenv pdesc pathset : Prop.normal Specs.spec list =
~f:(fun (p, path) -> (PropUtil.remove_seed_vars tenv p, path))
(Paths.PathSet.elements (do_join_post pname tenv posts))
in
let spec = {Specs.pre= Specs.Jprop.Prop (1, pre); Specs.posts= posts'; Specs.visited} in
let spec = BiabductionSummary.{pre= Jprop.Prop (1, pre); posts= posts'; visited} in
specs := spec :: !specs
in
Pmap.iter add_spec pre_post_map ; !specs
let collect_postconditions wl tenv proc_cfg : Paths.PathSet.t * Specs.Visitedset.t =
let collect_postconditions wl tenv proc_cfg : Paths.PathSet.t * BiabductionSummary.Visitedset.t =
let pname = Procdesc.get_proc_name (ProcCfg.Exceptional.proc_desc proc_cfg) in
let pathset = collect_analysis_result tenv wl proc_cfg in
(* Assuming C++ developers use RAII, remove resources from the constructor posts *)
@ -751,17 +756,20 @@ let initial_prop_from_pre tenv curr_f pre =
(** Re-execute one precondition and return some spec if there was no re-execution error. *)
let execute_filter_prop exe_env wl tenv proc_cfg init_node
(precondition: Prop.normal Specs.Jprop.t) : Prop.normal Specs.spec option =
(precondition: Prop.normal BiabductionSummary.Jprop.t)
: Prop.normal BiabductionSummary.spec option =
let pdesc = ProcCfg.Exceptional.proc_desc proc_cfg in
let pname = Procdesc.get_proc_name pdesc in
do_before_node 0 init_node ;
L.d_strln ("#### Start: RE-execution for " ^ Typ.Procname.to_string pname ^ " ####") ;
L.d_indent 1 ;
L.d_strln "Precond:" ;
Specs.Jprop.d_shallow precondition ;
BiabductionSummary.Jprop.d_shallow precondition ;
L.d_ln () ;
L.d_ln () ;
let init_prop = initial_prop_from_pre tenv pdesc (Specs.Jprop.to_prop precondition) in
let init_prop =
initial_prop_from_pre tenv pdesc (BiabductionSummary.Jprop.to_prop precondition)
in
let init_edgeset =
Paths.PathSet.add_renamed_prop init_prop (Paths.Path.start init_node) Paths.PathSet.empty
in
@ -775,7 +783,7 @@ let execute_filter_prop exe_env wl tenv proc_cfg init_node
("#### Finished: RE-execution for " ^ Typ.Procname.to_string pname ^ " ####") ;
L.d_increase_indent 1 ;
L.d_strln "Precond:" ;
Prop.d_prop (Specs.Jprop.to_prop precondition) ;
Prop.d_prop (BiabductionSummary.Jprop.to_prop precondition) ;
L.d_ln () ;
let posts, visited =
let pset, visited = collect_postconditions wl tenv proc_cfg in
@ -787,14 +795,16 @@ let execute_filter_prop exe_env wl tenv proc_cfg init_node
(plist, visited)
in
let pre =
let p = PropUtil.remove_locals_ret tenv pdesc (Specs.Jprop.to_prop precondition) in
let p =
PropUtil.remove_locals_ret tenv pdesc (BiabductionSummary.Jprop.to_prop precondition)
in
match precondition with
| Specs.Jprop.Prop (n, _) ->
Specs.Jprop.Prop (n, p)
| Specs.Jprop.Joined (n, _, jp1, jp2) ->
Specs.Jprop.Joined (n, p, jp1, jp2)
| BiabductionSummary.Jprop.Prop (n, _) ->
BiabductionSummary.Jprop.Prop (n, p)
| BiabductionSummary.Jprop.Joined (n, _, jp1, jp2) ->
BiabductionSummary.Jprop.Joined (n, p, jp1, jp2)
in
let spec = {Specs.pre; Specs.posts; Specs.visited} in
let spec = BiabductionSummary.{pre; posts; visited} in
L.d_decrease_indent 1 ; do_after_node init_node ; Some spec
with RE_EXE_ERROR ->
do_before_node 0 init_node ;
@ -802,14 +812,15 @@ let execute_filter_prop exe_env wl tenv proc_cfg init_node
L.d_strln_color Red ("#### [FUNCTION " ^ Typ.Procname.to_string pname ^ "] ...ERROR") ;
L.d_increase_indent 1 ;
L.d_strln "when starting from pre:" ;
Prop.d_prop (Specs.Jprop.to_prop precondition) ;
Prop.d_prop (BiabductionSummary.Jprop.to_prop precondition) ;
L.d_strln "This precondition is filtered out." ;
L.d_decrease_indent 1 ;
do_after_node init_node ;
None
type exe_phase = (unit -> unit) * (unit -> Prop.normal Specs.spec list * Specs.phase)
type exe_phase =
(unit -> unit) * (unit -> Prop.normal BiabductionSummary.spec list * BiabductionSummary.phase)
(** Return functions to perform one phase of the analysis for a procedure.
Given [proc_name], return [do, get_results] where [go ()] performs the analysis phase
@ -826,12 +837,12 @@ let perform_analysis_phase exe_env tenv (summary: Specs.summary) (proc_cfg: Proc
let init_prop = initial_prop_from_emp tenv pdesc in
(* use existing pre's (in recursion some might exist) as starting points *)
let init_props_from_pres =
let specs = Specs.get_specs_from_payload summary in
let specs = Tabulation.get_specs_from_payload summary in
(* rename spec vars to footprint vars, and copy current to footprint *)
let mk_init precondition =
initial_prop_from_pre tenv pdesc (Specs.Jprop.to_prop precondition)
initial_prop_from_pre tenv pdesc (BiabductionSummary.Jprop.to_prop precondition)
in
List.map ~f:(fun spec -> mk_init spec.Specs.pre) specs
List.map ~f:(fun spec -> mk_init spec.BiabductionSummary.pre) specs
in
let init_props = Propset.from_proplist tenv (init_prop :: init_props_from_pres) in
let init_edgeset =
@ -863,14 +874,16 @@ let perform_analysis_phase exe_env tenv (summary: Specs.summary) (proc_cfg: Proc
Reporting.log_error_deprecated pname exn ;
(* retuning no specs *) []
in
(specs, Specs.FOOTPRINT)
(specs, BiabductionSummary.FOOTPRINT)
in
let wl = path_set_create_worklist proc_cfg in
(go wl, get_results wl)
in
let re_execution () : exe_phase =
let candidate_preconditions =
List.map ~f:(fun spec -> spec.Specs.pre) (Specs.get_specs_from_payload summary)
List.map
~f:(fun spec -> spec.BiabductionSummary.pre)
(Tabulation.get_specs_from_payload summary)
in
let valid_specs = ref [] in
let go () =
@ -880,7 +893,8 @@ let perform_analysis_phase exe_env tenv (summary: Specs.summary) (proc_cfg: Proc
(match speco with None -> () | Some spec -> valid_specs := !valid_specs @ [spec]) ;
speco
in
if Config.undo_join then ignore (Specs.Jprop.filter filter candidate_preconditions)
if Config.undo_join then
ignore (BiabductionSummary.Jprop.filter filter candidate_preconditions)
else ignore (List.map ~f:filter candidate_preconditions)
in
let get_results () =
@ -891,14 +905,14 @@ let perform_analysis_phase exe_env tenv (summary: Specs.summary) (proc_cfg: Proc
[Typ.Procname.to_filename pname]
in
if Config.write_dotty then Dotty.pp_speclist_dotty_file filename specs ;
(specs, Specs.RE_EXECUTION)
(specs, BiabductionSummary.RE_EXECUTION)
in
(go, get_results)
in
match Specs.get_phase summary with
| Specs.FOOTPRINT ->
match Tabulation.get_phase summary with
| FOOTPRINT ->
compute_footprint ()
| Specs.RE_EXECUTION ->
| RE_EXECUTION ->
re_execution ()
@ -927,9 +941,11 @@ let exception_preconditions tenv pname summary =
(exns, false)
in
let collect_spec errors spec =
List.fold ~f:(collect_exceptions spec.Specs.pre) ~init:errors spec.Specs.posts
List.fold
~f:(collect_exceptions spec.BiabductionSummary.pre)
~init:errors spec.BiabductionSummary.posts
in
List.fold ~f:collect_spec ~init:([], true) (Specs.get_specs_from_payload summary)
List.fold ~f:collect_spec ~init:([], true) (Tabulation.get_specs_from_payload summary)
(* Collect all pairs of the kind (precondition, custom error) from a summary *)
@ -942,9 +958,11 @@ let custom_error_preconditions summary =
((pre, e) :: errors, all_post_error)
in
let collect_spec errors spec =
List.fold ~f:(collect_errors spec.Specs.pre) ~init:errors spec.Specs.posts
List.fold
~f:(collect_errors spec.BiabductionSummary.pre)
~init:errors spec.BiabductionSummary.posts
in
List.fold ~f:collect_spec ~init:([], true) (Specs.get_specs_from_payload summary)
List.fold ~f:collect_spec ~init:([], true) (Tabulation.get_specs_from_payload summary)
(* Remove the constrain of the form this != null which is true for all Java virtual calls *)
@ -975,7 +993,7 @@ let remove_this_not_null tenv prop =
This means that the post-conditions associated with this precondition cannot be prevented
by the calling context. *)
let is_unavoidable tenv pre =
let prop = remove_this_not_null tenv (Specs.Jprop.to_prop pre) in
let prop = remove_this_not_null tenv (BiabductionSummary.Jprop.to_prop pre) in
match Prop.CategorizePreconditions.categorize [prop] with
| Prop.CategorizePreconditions.NoPres | Prop.CategorizePreconditions.Empty ->
true
@ -1008,7 +1026,9 @@ let report_runtime_exceptions tenv pdesc summary =
in
let report (pre, runtime_exception) =
if should_report pre then
let pre_str = F.asprintf "%a" (Prop.pp_prop Pp.text) (Specs.Jprop.to_prop pre) in
let pre_str =
F.asprintf "%a" (Prop.pp_prop Pp.text) (BiabductionSummary.Jprop.to_prop pre)
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
Reporting.log_error_deprecated pname exn
@ -1030,62 +1050,67 @@ let report_custom_errors tenv summary =
module SpecMap = Caml.Map.Make (struct
type t = Prop.normal Specs.Jprop.t
type t = Prop.normal BiabductionSummary.Jprop.t
let compare = Specs.Jprop.compare
let compare = BiabductionSummary.Jprop.compare
end)
(** Update the specs of the current proc after the execution of one phase *)
let update_specs tenv prev_summary phase (new_specs: Specs.NormSpec.t list)
: Specs.NormSpec.t list * bool =
let new_specs = Specs.normalized_specs_to_specs new_specs in
let old_specs = Specs.get_specs_from_payload prev_summary in
let update_specs tenv prev_summary phase (new_specs: BiabductionSummary.NormSpec.t list)
: BiabductionSummary.NormSpec.t list * bool =
let new_specs = BiabductionSummary.normalized_specs_to_specs new_specs in
let old_specs = Tabulation.get_specs_from_payload prev_summary in
let changed = ref false in
let current_specs =
ref
(List.fold
~f:(fun map spec ->
SpecMap.add spec.Specs.pre
(Paths.PathSet.from_renamed_list spec.Specs.posts, spec.Specs.visited) map )
SpecMap.add spec.BiabductionSummary.pre
( Paths.PathSet.from_renamed_list spec.BiabductionSummary.posts
, spec.BiabductionSummary.visited ) map )
~init:SpecMap.empty old_specs)
in
let re_exe_filter old_spec =
(* filter out pres which failed re-exe *)
if
Specs.equal_phase phase Specs.RE_EXECUTION
BiabductionSummary.equal_phase phase RE_EXECUTION
&& not
(List.exists
~f:(fun new_spec -> Specs.Jprop.equal new_spec.Specs.pre old_spec.Specs.pre)
~f:(fun new_spec ->
BiabductionSummary.Jprop.equal new_spec.BiabductionSummary.pre
old_spec.BiabductionSummary.pre )
new_specs)
then (
changed := true ;
current_specs := SpecMap.remove old_spec.Specs.pre !current_specs )
current_specs := SpecMap.remove old_spec.BiabductionSummary.pre !current_specs )
else ()
in
let add_spec spec =
(* add a new spec by doing union of the posts *)
try
let old_post, old_visited = SpecMap.find spec.Specs.pre !current_specs in
let old_post, old_visited = SpecMap.find spec.BiabductionSummary.pre !current_specs in
let new_post, new_visited =
( Paths.PathSet.union old_post (Paths.PathSet.from_renamed_list spec.Specs.posts)
, Specs.Visitedset.union old_visited spec.Specs.visited )
( Paths.PathSet.union old_post
(Paths.PathSet.from_renamed_list spec.BiabductionSummary.posts)
, BiabductionSummary.Visitedset.union old_visited spec.BiabductionSummary.visited )
in
if not (Paths.PathSet.equal old_post new_post) then (
changed := true ;
current_specs :=
SpecMap.add spec.Specs.pre (new_post, new_visited)
(SpecMap.remove spec.Specs.pre !current_specs) )
SpecMap.add spec.BiabductionSummary.pre (new_post, new_visited)
(SpecMap.remove spec.BiabductionSummary.pre !current_specs) )
with Caml.Not_found ->
changed := true ;
current_specs :=
SpecMap.add spec.Specs.pre
(Paths.PathSet.from_renamed_list spec.Specs.posts, spec.Specs.visited) !current_specs
SpecMap.add spec.BiabductionSummary.pre
( Paths.PathSet.from_renamed_list spec.BiabductionSummary.posts
, spec.BiabductionSummary.visited ) !current_specs
in
let res = ref [] in
let convert pre (post_set, visited) =
res :=
Specs.spec_normalize tenv
{Specs.pre; Specs.posts= Paths.PathSet.elements post_set; Specs.visited}
BiabductionSummary.spec_normalize tenv
BiabductionSummary.{pre; posts= Paths.PathSet.elements post_set; visited}
:: !res
in
List.iter ~f:re_exe_filter old_specs ;
@ -1098,7 +1123,7 @@ let update_specs tenv prev_summary phase (new_specs: Specs.NormSpec.t list)
(** update a summary after analysing a procedure *)
let update_summary tenv prev_summary specs phase res =
let normal_specs = List.map ~f:(Specs.spec_normalize tenv) specs in
let normal_specs = List.map ~f:(BiabductionSummary.spec_normalize tenv) specs in
let new_specs, _ = update_specs tenv prev_summary phase normal_specs in
let symops = prev_summary.Specs.stats.Specs.symops + SymOp.get_total () in
let stats_failure =
@ -1107,13 +1132,15 @@ let update_summary tenv prev_summary specs phase res =
let stats = {prev_summary.Specs.stats with symops; stats_failure} in
let preposts =
match phase with
| Specs.FOOTPRINT ->
Some new_specs
| Specs.RE_EXECUTION ->
Some (List.map ~f:(Specs.NormSpec.erase_join_info_pre tenv) new_specs)
| BiabductionSummary.FOOTPRINT ->
new_specs
| BiabductionSummary.RE_EXECUTION ->
List.map ~f:(BiabductionSummary.NormSpec.erase_join_info_pre tenv) new_specs
in
let payload =
{prev_summary.Specs.payload with Specs.biabduction= Some BiabductionSummary.{preposts; phase}}
in
let payload = {prev_summary.Specs.payload with Specs.preposts} in
{prev_summary with Specs.phase; stats; payload}
{prev_summary with Specs.stats; payload}
(** Analyze the procedure and return the resulting summary. *)
@ -1121,7 +1148,7 @@ let analyze_proc exe_env tenv proc_cfg : Specs.summary =
let proc_desc = ProcCfg.Exceptional.proc_desc proc_cfg in
let proc_name = Procdesc.get_proc_name proc_desc in
reset_global_values proc_desc ;
let summary = Specs.get_summary_unsafe "analyze_proc" proc_name in
let summary = Specs.get_summary_unsafe proc_name in
let go, get_results = perform_analysis_phase exe_env tenv summary proc_cfg in
let res = Timeout.exe_timeout go () in
let specs, phase = get_results () in
@ -1135,19 +1162,32 @@ let analyze_proc exe_env tenv proc_cfg : Specs.summary =
(** Perform the transition from [FOOTPRINT] to [RE_EXECUTION] in spec table *)
let transition_footprint_re_exe tenv proc_name joined_pres =
let summary = Specs.get_summary_unsafe "transition_footprint_re_exe" proc_name in
let summary = Specs.get_summary_unsafe proc_name in
let summary' =
if Config.only_footprint then {summary with Specs.phase= Specs.RE_EXECUTION}
if Config.only_footprint then
match summary.Specs.payload.biabduction with
| Some ({phase= FOOTPRINT} as biabduction) ->
{ summary with
Specs.payload=
{ summary.payload with
Specs.biabduction= Some {biabduction with BiabductionSummary.phase= RE_EXECUTION}
} }
| _ ->
summary
else
let specs =
let preposts =
List.map
~f:(fun jp ->
Specs.spec_normalize tenv {Specs.pre= jp; posts= []; visited= Specs.Visitedset.empty}
BiabductionSummary.spec_normalize tenv
{BiabductionSummary.pre= jp; posts= []; visited= BiabductionSummary.Visitedset.empty}
)
joined_pres
in
let payload = {summary.Specs.payload with Specs.preposts= Some specs} in
{summary with Specs.phase= Specs.RE_EXECUTION; payload}
let payload =
{ summary.Specs.payload with
biabduction= Some BiabductionSummary.{preposts; phase= RE_EXECUTION} }
in
{summary with Specs.payload}
in
Specs.add_summary proc_name summary'
@ -1184,7 +1224,7 @@ let perform_transition proc_cfg tenv proc_name =
transition_footprint_re_exe tenv proc_name joined_pres
in
match Specs.get_summary proc_name with
| Some summary when Specs.equal_phase (Specs.get_phase summary) Specs.FOOTPRINT ->
| Some summary when BiabductionSummary.equal_phase (Tabulation.get_phase summary) FOOTPRINT ->
transition summary
| _ ->
()
@ -1198,8 +1238,23 @@ let analyze_procedure_aux exe_env tenv proc_desc =
Specs.add_summary proc_name summaryfp ;
perform_transition proc_cfg tenv proc_name ;
let summaryre = Config.run_in_re_execution_mode (analyze_proc exe_env tenv) proc_cfg in
Specs.add_summary proc_name summaryre ;
summaryre
let summary_compact =
match summaryre.Specs.payload.biabduction with
| Some BiabductionSummary.({preposts} as biabduction) when Config.save_compact_summaries ->
let sharing_env = Sil.create_sharing_env () in
let compact_preposts =
List.map ~f:(BiabductionSummary.NormSpec.compact sharing_env) preposts
in
{ summaryre with
payload=
{ summaryre.payload with
biabduction= Some {biabduction with BiabductionSummary.preposts= compact_preposts} }
}
| _ ->
summaryre
in
Specs.add_summary proc_name summary_compact ;
summary_compact
let analyze_procedure {Callbacks.summary; proc_desc; tenv; exe_env} : Specs.summary =
@ -1210,4 +1265,4 @@ let analyze_procedure {Callbacks.summary; proc_desc; tenv; exe_env} : Specs.summ
( try ignore (analyze_procedure_aux exe_env tenv proc_desc) with exn ->
IExn.reraise_if exn ~f:(fun () -> not (Exceptions.handle_exception exn)) ;
Reporting.log_error_deprecated proc_name exn ) ;
Specs.get_summary_unsafe __FILE__ proc_name
Specs.get_summary_unsafe proc_name

Loading…
Cancel
Save