[pulse] more type-safety around summary and latent issues creation

Summary:
This makes sure we call `AbductiveDomain.summary_of_post` exactly once
per post-condition. Notice in particular in the diff:
- in Pulse.ml we remove a now-certified-useless "is_unsat_expensive"
  call
- in PulseOperations.ml we add a previously-missing call to
  `summary_of_post` (it's needed to remove local variables from the
  symbolic state + normalize)

The price to pay is ugly type annotations and down-casting peppered in a
few places, in reasonable number.

Reviewed By: da319

Differential Revision: D24078564

fbshipit-source-id: 3102cacf0
master
Jules Villard 4 years ago committed by Facebook GitHub Bot
parent 7fdb33b710
commit 0b7e2fb7c7

@ -142,8 +142,10 @@ let extract_impurity tenv pdesc (exec_state : ExecutionDomain.t) : ImpurityDomai
match exec_state with match exec_state with
| ExitProgram astate -> | ExitProgram astate ->
(astate, true) (astate, true)
| AbortProgram astate | ContinueProgram astate | LatentAbortProgram {astate} -> | ContinueProgram astate ->
(astate, false) (astate, false)
| AbortProgram astate | LatentAbortProgram {astate} ->
((astate :> AbductiveDomain.t), false)
in in
let pre_heap = (AbductiveDomain.get_pre astate).BaseDomain.heap in let pre_heap = (AbductiveDomain.get_pre astate).BaseDomain.heap in
let post = AbductiveDomain.get_post astate in let post = AbductiveDomain.get_post astate in
@ -162,7 +164,8 @@ let extract_impurity tenv pdesc (exec_state : ExecutionDomain.t) : ImpurityDomai
{modified_globals; modified_params; skipped_calls; exited} {modified_globals; modified_params; skipped_calls; exited}
let checker {IntraproceduralAnalysis.proc_desc; tenv; err_log} pulse_summary_opt = let checker {IntraproceduralAnalysis.proc_desc; tenv; err_log}
(pulse_summary_opt : PulseSummary.t option) =
let proc_name = Procdesc.get_proc_name proc_desc in let proc_name = Procdesc.get_proc_name proc_desc in
let pname_loc = Procdesc.get_loc proc_desc in let pname_loc = Procdesc.get_loc proc_desc in
match pulse_summary_opt with match pulse_summary_opt with
@ -182,8 +185,9 @@ let checker {IntraproceduralAnalysis.proc_desc; tenv; err_log} pulse_summary_opt
IssueType.impure_function impure_fun_desc IssueType.impure_function impure_fun_desc
| Some pre_posts -> | Some pre_posts ->
let (ImpurityDomain.{modified_globals; modified_params; skipped_calls} as impurity_astate) = let (ImpurityDomain.{modified_globals; modified_params; skipped_calls} as impurity_astate) =
List.fold pre_posts ~init:ImpurityDomain.pure ~f:(fun acc exec_state -> List.fold pre_posts ~init:ImpurityDomain.pure
let modified = extract_impurity tenv proc_desc exec_state in ~f:(fun acc (exec_state : ExecutionDomain.summary) ->
let modified = extract_impurity tenv proc_desc (exec_state :> ExecutionDomain.t) in
ImpurityDomain.join acc modified ) ImpurityDomain.join acc modified )
in in
if PurityChecker.should_report proc_name && not (ImpurityDomain.is_pure impurity_astate) then if PurityChecker.should_report proc_name && not (ImpurityDomain.is_pure impurity_astate) then

@ -23,29 +23,26 @@ let check_error_transform {InterproceduralAnalysis.proc_desc; err_log} ~f = func
| Ok astate -> | Ok astate ->
f astate f astate
| Error (diagnostic, astate) -> ( | Error (diagnostic, astate) -> (
let astate, is_unsat = PulseArithmetic.is_unsat_expensive astate in let astate_summary = AbductiveDomain.summary_of_post proc_desc astate in
if is_unsat then [] if PulseArithmetic.is_unsat_cheap (astate_summary :> AbductiveDomain.t) then []
else else
let astate = AbductiveDomain.of_post proc_desc astate in match LatentIssue.should_report_diagnostic astate_summary diagnostic with
if PulseArithmetic.is_unsat_cheap astate then [] | `ReportNow ->
else report proc_desc err_log diagnostic ;
match LatentIssue.should_report_diagnostic astate diagnostic with [ExecutionDomain.AbortProgram astate_summary]
| `ReportNow -> | `DelayReport latent_issue ->
report proc_desc err_log diagnostic ; ( if Config.pulse_report_latent_issues then
[ExecutionDomain.AbortProgram astate] (* HACK: report latent issues with a prominent message to distinguish them from
| `DelayReport latent_issue -> non-latent. Useful for infer's own tests. *)
( if Config.pulse_report_latent_issues then let diagnostic = LatentIssue.to_diagnostic latent_issue in
(* HACK: report latent issues with a prominent message to distinguish them from let extra_trace =
non-latent. Useful for infer's own tests. *) let depth = 0 in
let diagnostic = LatentIssue.to_diagnostic latent_issue in let tags = [] in
let extra_trace = let location = Diagnostic.get_location diagnostic in
let depth = 0 in [Errlog.make_trace_element depth location "*** LATENT ***" tags]
let tags = [] in in
let location = Diagnostic.get_location diagnostic in report ~extra_trace proc_desc err_log diagnostic ) ;
[Errlog.make_trace_element depth location "*** LATENT ***" tags] [ExecutionDomain.LatentAbortProgram {astate= astate_summary; latent_issue}] )
in
report ~extra_trace proc_desc err_log diagnostic ) ;
[ExecutionDomain.LatentAbortProgram {astate; latent_issue}] )
let check_error_continue analysis_data result = let check_error_continue analysis_data result =
@ -72,13 +69,14 @@ module PulseTransferFunctions = struct
AnalysisCallbacks.proc_resolve_attributes pname |> Option.map ~f:ProcAttributes.get_pvar_formals AnalysisCallbacks.proc_resolve_attributes pname |> Option.map ~f:ProcAttributes.get_pvar_formals
let interprocedural_call {InterproceduralAnalysis.analyze_dependency} ret call_exp actuals let interprocedural_call {InterproceduralAnalysis.analyze_dependency; proc_desc} ret call_exp
call_loc astate = actuals call_loc astate =
match proc_name_of_call call_exp with match proc_name_of_call call_exp with
| Some callee_pname when not Config.pulse_intraprocedural_only -> | Some callee_pname when not Config.pulse_intraprocedural_only ->
let formals_opt = get_pvar_formals callee_pname in let formals_opt = get_pvar_formals callee_pname in
let callee_data = analyze_dependency callee_pname in let callee_data = analyze_dependency callee_pname in
PulseOperations.call ~callee_data call_loc callee_pname ~ret ~actuals ~formals_opt astate PulseOperations.call ~caller_proc_desc:proc_desc ~callee_data call_loc callee_pname ~ret
~actuals ~formals_opt astate
| _ -> | _ ->
L.d_printfln "Skipping indirect call %a@\n" Exp.pp call_exp ; L.d_printfln "Skipping indirect call %a@\n" Exp.pp call_exp ;
PulseOperations.unknown_call call_loc (SkippedUnknownCall call_exp) ~ret ~actuals PulseOperations.unknown_call call_loc (SkippedUnknownCall call_exp) ~ret ~actuals

@ -432,7 +432,9 @@ let invalidate_locals pdesc astate : t =
else {astate with post= PostDomain.update astate.post ~attrs:attrs'} else {astate with post= PostDomain.update astate.post ~attrs:attrs'}
let of_post pdesc astate = type summary = t
let summary_of_post pdesc astate =
let astate = filter_for_summary astate in let astate = filter_for_summary astate in
let astate, live_addresses, _ = discard_unreachable astate in let astate, live_addresses, _ = discard_unreachable astate in
let astate = let astate =

@ -158,7 +158,12 @@ val add_skipped_calls : SkippedCalls.t -> t -> t
val set_path_condition : PathCondition.t -> t -> t val set_path_condition : PathCondition.t -> t -> t
val of_post : Procdesc.t -> t -> t (** private type to make sure {!summary_of_post} is always called when creating summaries *)
type summary = private t
val summary_of_post : Procdesc.t -> t -> summary
(** trim the state down to just the procedure's interface (formals and globals), and simplify and
normalize the state *)
val set_post_edges : AbstractValue.t -> BaseMemory.Edges.t -> t -> t val set_post_edges : AbstractValue.t -> BaseMemory.Edges.t -> t -> t
(** directly set the edges for the given address, bypassing abduction altogether *) (** directly set the edges for the given address, bypassing abduction altogether *)

@ -12,11 +12,17 @@ open PulseBasicInterface
module AbductiveDomain = PulseAbductiveDomain module AbductiveDomain = PulseAbductiveDomain
module LatentIssue = PulseLatentIssue module LatentIssue = PulseLatentIssue
type t = (* The type variable is needed to distinguish summaries from plain states.
| AbortProgram of AbductiveDomain.t
| ContinueProgram of AbductiveDomain.t Some of the variants have summary-typed states instead of plain states, to ensure we have
| ExitProgram of AbductiveDomain.t normalized them and don't need to normalize them again. *)
| LatentAbortProgram of {astate: AbductiveDomain.t; latent_issue: LatentIssue.t} type 'abductive_domain_t base_t =
| ContinueProgram of 'abductive_domain_t
| ExitProgram of 'abductive_domain_t
| AbortProgram of AbductiveDomain.summary
| LatentAbortProgram of {astate: AbductiveDomain.summary; latent_issue: LatentIssue.t}
type t = AbductiveDomain.t base_t
let continue astate = ContinueProgram astate let continue astate = ContinueProgram astate
@ -24,13 +30,14 @@ let mk_initial pdesc = ContinueProgram (AbductiveDomain.mk_initial pdesc)
let leq ~lhs ~rhs = let leq ~lhs ~rhs =
match (lhs, rhs) with match (lhs, rhs) with
| AbortProgram astate1, AbortProgram astate2 | AbortProgram astate1, AbortProgram astate2 ->
| ContinueProgram astate1, ContinueProgram astate2 AbductiveDomain.leq ~lhs:(astate1 :> AbductiveDomain.t) ~rhs:(astate2 :> AbductiveDomain.t)
| ExitProgram astate1, ExitProgram astate2 -> | ContinueProgram astate1, ContinueProgram astate2 | ExitProgram astate1, ExitProgram astate2 ->
AbductiveDomain.leq ~lhs:astate1 ~rhs:astate2 AbductiveDomain.leq ~lhs:(astate1 :> AbductiveDomain.t) ~rhs:(astate2 :> AbductiveDomain.t)
| ( LatentAbortProgram {astate= astate1; latent_issue= issue1} | ( LatentAbortProgram {astate= astate1; latent_issue= issue1}
, LatentAbortProgram {astate= astate2; latent_issue= issue2} ) -> , LatentAbortProgram {astate= astate2; latent_issue= issue2} ) ->
LatentIssue.equal issue1 issue2 && AbductiveDomain.leq ~lhs:astate1 ~rhs:astate2 LatentIssue.equal issue1 issue2
&& AbductiveDomain.leq ~lhs:(astate1 :> AbductiveDomain.t) ~rhs:(astate2 :> AbductiveDomain.t)
| _ -> | _ ->
false false
@ -39,36 +46,40 @@ let pp fmt = function
| ContinueProgram astate -> | ContinueProgram astate ->
AbductiveDomain.pp fmt astate AbductiveDomain.pp fmt astate
| ExitProgram astate -> | ExitProgram astate ->
F.fprintf fmt "{ExitProgram %a}" AbductiveDomain.pp astate F.fprintf fmt "{ExitProgram %a}" AbductiveDomain.pp (astate :> AbductiveDomain.t)
| AbortProgram astate -> | AbortProgram astate ->
F.fprintf fmt "{AbortProgram %a}" AbductiveDomain.pp astate F.fprintf fmt "{AbortProgram %a}" AbductiveDomain.pp (astate :> AbductiveDomain.t)
| LatentAbortProgram {astate; latent_issue} -> | LatentAbortProgram {astate; latent_issue} ->
let diagnostic = LatentIssue.to_diagnostic latent_issue in let diagnostic = LatentIssue.to_diagnostic latent_issue in
let message = Diagnostic.get_message diagnostic in let message = Diagnostic.get_message diagnostic in
let location = Diagnostic.get_location diagnostic in let location = Diagnostic.get_location diagnostic in
F.fprintf fmt "{LatentAbortProgram(%a: %s) %a}" Location.pp location message F.fprintf fmt "{LatentAbortProgram(%a: %s) %a}" Location.pp location message
AbductiveDomain.pp astate AbductiveDomain.pp
(astate :> AbductiveDomain.t)
let map ~f exec_state = let map ~f exec_state =
match exec_state with match exec_state with
| AbortProgram astate ->
AbortProgram (f astate)
| ContinueProgram astate -> | ContinueProgram astate ->
ContinueProgram (f astate) ContinueProgram (f astate)
| ExitProgram astate -> | ExitProgram astate ->
ExitProgram (f astate) ExitProgram (f astate)
| AbortProgram astate ->
AbortProgram astate
| LatentAbortProgram {astate; latent_issue} -> | LatentAbortProgram {astate; latent_issue} ->
LatentAbortProgram {astate= f astate; latent_issue} LatentAbortProgram {astate; latent_issue}
type summary = AbductiveDomain.summary base_t
let of_posts pdesc posts = let summary_of_posts pdesc posts =
List.filter_mapi posts ~f:(fun i exec_state -> List.filter_mapi posts ~f:(fun i exec_state ->
let ( AbortProgram astate let astate =
| ContinueProgram astate match exec_state with
| ExitProgram astate | AbortProgram astate | LatentAbortProgram {astate} ->
| LatentAbortProgram {astate} ) = (astate :> AbductiveDomain.t)
exec_state | ContinueProgram astate | ExitProgram astate ->
astate
in in
L.d_printfln "Creating spec out of state #%d:@\n%a" i pp exec_state ; L.d_printfln "Creating spec out of state #%d:@\n%a" i pp exec_state ;
let astate, is_unsat = PulseArithmetic.is_unsat_expensive astate in let astate, is_unsat = PulseArithmetic.is_unsat_expensive astate in
@ -77,4 +88,4 @@ let of_posts pdesc posts =
Some Some
(map exec_state ~f:(fun _astate -> (map exec_state ~f:(fun _astate ->
(* prefer [astate] since it is an equivalent state that has been normalized *) (* prefer [astate] since it is an equivalent state that has been normalized *)
AbductiveDomain.of_post pdesc astate )) ) AbductiveDomain.summary_of_post pdesc astate )) )

@ -9,18 +9,22 @@ open! IStd
module AbductiveDomain = PulseAbductiveDomain module AbductiveDomain = PulseAbductiveDomain
module LatentIssue = PulseLatentIssue module LatentIssue = PulseLatentIssue
type t = type 'abductive_domain_t base_t =
| AbortProgram of AbductiveDomain.t | ContinueProgram of 'abductive_domain_t (** represents the state at the program point *)
| ExitProgram of 'abductive_domain_t (** represents the state originating at exit/divergence. *)
| AbortProgram of AbductiveDomain.summary
(** represents the state at the program point that caused an error *) (** represents the state at the program point that caused an error *)
| ContinueProgram of AbductiveDomain.t (** represents the state at the program point *) | LatentAbortProgram of {astate: AbductiveDomain.summary; latent_issue: LatentIssue.t}
| ExitProgram of AbductiveDomain.t (** represents the state originating at exit/divergence. *)
| LatentAbortProgram of {astate: AbductiveDomain.t; latent_issue: LatentIssue.t}
(** this path leads to an error but we don't have conclusive enough data to report it yet *) (** this path leads to an error but we don't have conclusive enough data to report it yet *)
type t = AbductiveDomain.t base_t
include AbstractDomain.NoJoin with type t := t include AbstractDomain.NoJoin with type t := t
val continue : AbductiveDomain.t -> t val continue : AbductiveDomain.t -> t
val of_posts : Procdesc.t -> t list -> t list
val mk_initial : Procdesc.t -> t val mk_initial : Procdesc.t -> t
type summary = AbductiveDomain.summary base_t
val summary_of_posts : Procdesc.t -> t list -> summary list

@ -7,6 +7,8 @@
open! IStd open! IStd
open PulseBasicInterface open PulseBasicInterface
module AbductiveDomain = PulseAbductiveDomain
module Arithmetic = PulseArithmetic
type t = AccessToInvalidAddress of Diagnostic.access_to_invalid_address [@@deriving equal] type t = AccessToInvalidAddress of Diagnostic.access_to_invalid_address [@@deriving equal]
@ -20,9 +22,13 @@ let add_call call_and_loc = function
AccessToInvalidAddress {access with calling_context= call_and_loc :: access.calling_context} AccessToInvalidAddress {access with calling_context= call_and_loc :: access.calling_context}
let should_report astate = PulseArithmetic.has_no_assumptions astate let should_report (astate : AbductiveDomain.summary) =
Arithmetic.has_no_assumptions (astate :> AbductiveDomain.t)
let should_report_diagnostic astate (diagnostic : Diagnostic.t) =
(* require a summary because we don't want to stop reporting because some non-abducible condition is
not true as calling context cannot possibly influence such conditions *)
let should_report_diagnostic (astate : AbductiveDomain.summary) (diagnostic : Diagnostic.t) =
match diagnostic with match diagnostic with
| MemoryLeak _ | StackVariableAddressEscape _ -> | MemoryLeak _ | StackVariableAddressEscape _ ->
(* these issues are reported regardless of the calling context, not sure if that's the right (* these issues are reported regardless of the calling context, not sure if that's the right

@ -7,6 +7,7 @@
open! IStd open! IStd
open PulseBasicInterface open PulseBasicInterface
module AbductiveDomain = PulseAbductiveDomain
(** A subset of [PulseDiagnostic] that can be "latent", i.e. there is a potential issue in the code (** A subset of [PulseDiagnostic] that can be "latent", i.e. there is a potential issue in the code
but we want to delay reporting until we see the conditions for the bug manifest themselves in but we want to delay reporting until we see the conditions for the bug manifest themselves in
@ -16,9 +17,9 @@ type t = AccessToInvalidAddress of Diagnostic.access_to_invalid_address [@@deriv
val to_diagnostic : t -> Diagnostic.t val to_diagnostic : t -> Diagnostic.t
val should_report : PulseAbductiveDomain.t -> bool val should_report : AbductiveDomain.summary -> bool
val should_report_diagnostic : val should_report_diagnostic :
PulseAbductiveDomain.t -> Diagnostic.t -> [`ReportNow | `DelayReport of t] AbductiveDomain.summary -> Diagnostic.t -> [`ReportNow | `DelayReport of t]
val add_call : CallEvent.t * Location.t -> t -> t val add_call : CallEvent.t * Location.t -> t -> t

@ -456,7 +456,7 @@ end
module StdFunction = struct module StdFunction = struct
let operator_call ProcnameDispatcher.Call.FuncArg.{arg_payload= lambda_ptr_hist; typ} actuals : let operator_call ProcnameDispatcher.Call.FuncArg.{arg_payload= lambda_ptr_hist; typ} actuals :
model = model =
fun {analyze_dependency} ~callee_procname:_ location ~ret astate -> fun {analyze_dependency; proc_desc} ~callee_procname:_ location ~ret astate ->
let havoc_ret (ret_id, _) astate = let havoc_ret (ret_id, _) astate =
let event = ValueHistory.Call {f= Model "std::function::operator()"; location; in_call= []} in let event = ValueHistory.Call {f= Model "std::function::operator()"; location; in_call= []} in
[PulseOperations.havoc_id ret_id [event] astate] [PulseOperations.havoc_id ret_id [event] astate]
@ -475,7 +475,7 @@ module StdFunction = struct
:: List.map actuals ~f:(fun ProcnameDispatcher.Call.FuncArg.{arg_payload; typ} -> :: List.map actuals ~f:(fun ProcnameDispatcher.Call.FuncArg.{arg_payload; typ} ->
(arg_payload, typ) ) (arg_payload, typ) )
in in
PulseOperations.call PulseOperations.call ~caller_proc_desc:proc_desc
~callee_data:(analyze_dependency callee_proc_name) ~callee_data:(analyze_dependency callee_proc_name)
location callee_proc_name ~ret ~actuals ~formals_opt:None astate location callee_proc_name ~ret ~actuals ~formals_opt:None astate

@ -437,8 +437,8 @@ let unknown_call call_loc reason ~ret ~actuals ~formals_opt astate =
|> havoc_ret ret |> add_skipped_proc |> havoc_ret ret |> add_skipped_proc
let apply_callee callee_pname call_loc callee_exec_state ~ret ~captured_vars_with_actuals ~formals let apply_callee ~caller_proc_desc callee_pname call_loc callee_exec_state ~ret
~actuals astate = ~captured_vars_with_actuals ~formals ~actuals astate =
let apply callee_prepost ~f = let apply callee_prepost ~f =
PulseInterproc.apply_prepost callee_pname call_loc ~callee_prepost ~captured_vars_with_actuals PulseInterproc.apply_prepost callee_pname call_loc ~callee_prepost ~captured_vars_with_actuals
~formals ~actuals astate ~formals ~actuals astate
@ -467,13 +467,18 @@ let apply_callee callee_pname call_loc callee_exec_state ~ret ~captured_vars_wit
| ExitProgram astate -> | ExitProgram astate ->
apply astate ~f:(fun astate -> Ok (Some (ExitProgram astate))) apply astate ~f:(fun astate -> Ok (Some (ExitProgram astate)))
| LatentAbortProgram {astate; latent_issue} -> | LatentAbortProgram {astate; latent_issue} ->
apply astate ~f:(fun astate -> apply
let latent_issue = (astate :> AbductiveDomain.t)
LatentIssue.add_call (CallEvent.Call callee_pname, call_loc) latent_issue ~f:(fun astate ->
in let astate_summary = AbductiveDomain.summary_of_post caller_proc_desc astate in
if LatentIssue.should_report astate then if PulseArithmetic.is_unsat_cheap (astate_summary :> AbductiveDomain.t) then Ok None
Error (LatentIssue.to_diagnostic latent_issue, astate) else
else Ok (Some (LatentAbortProgram {astate; latent_issue})) ) let latent_issue =
LatentIssue.add_call (CallEvent.Call callee_pname, call_loc) latent_issue
in
if LatentIssue.should_report astate_summary then
Error (LatentIssue.to_diagnostic latent_issue, (astate_summary :> AbductiveDomain.t))
else Ok (Some (LatentAbortProgram {astate= astate_summary; latent_issue})) )
let get_captured_actuals location ~captured_vars ~actual_closure astate = let get_captured_actuals location ~captured_vars ~actual_closure astate =
@ -488,8 +493,9 @@ let get_captured_actuals location ~captured_vars ~actual_closure astate =
(astate, captured_vars_with_actuals) (astate, captured_vars_with_actuals)
let call ~callee_data call_loc callee_pname ~ret ~actuals ~formals_opt (astate : AbductiveDomain.t) let call ~caller_proc_desc ~(callee_data : (Procdesc.t * PulseSummary.t) option) call_loc
: (ExecutionDomain.t list, Diagnostic.t * t) result = callee_pname ~ret ~actuals ~formals_opt (astate : AbductiveDomain.t) :
(ExecutionDomain.t list, Diagnostic.t * t) result =
match callee_data with match callee_data with
| Some (callee_proc_desc, exec_states) -> | Some (callee_proc_desc, exec_states) ->
let formals = let formals =
@ -516,12 +522,14 @@ let call ~callee_data call_loc callee_pname ~ret ~actuals ~formals_opt (astate :
Str.string_match regex (Procname.to_string callee_pname) 0 ) Str.string_match regex (Procname.to_string callee_pname) 0 )
in in
(* call {!AbductiveDomain.PrePost.apply} on each pre/post pair in the summary. *) (* call {!AbductiveDomain.PrePost.apply} on each pre/post pair in the summary. *)
IContainer.fold_result_until exec_states ~fold:List.fold ~init:[] IContainer.fold_result_until
(exec_states :> ExecutionDomain.t list)
~fold:List.fold ~init:[]
~f:(fun posts callee_exec_state -> ~f:(fun posts callee_exec_state ->
(* apply all pre/post specs *) (* apply all pre/post specs *)
match match
apply_callee callee_pname call_loc callee_exec_state ~captured_vars_with_actuals apply_callee ~caller_proc_desc callee_pname call_loc callee_exec_state
~formals ~actuals ~ret astate ~captured_vars_with_actuals ~formals ~actuals ~ret astate
with with
| Ok None -> | Ok None ->
(* couldn't apply pre/post pair *) (* couldn't apply pre/post pair *)

@ -124,7 +124,8 @@ val check_address_escape :
Location.t -> Procdesc.t -> AbstractValue.t -> ValueHistory.t -> t -> t access_result Location.t -> Procdesc.t -> AbstractValue.t -> ValueHistory.t -> t -> t access_result
val call : val call :
callee_data:(Procdesc.t * PulseSummary.t) option caller_proc_desc:Procdesc.t
-> callee_data:(Procdesc.t * PulseSummary.t) option
-> Location.t -> Location.t
-> Procname.t -> Procname.t
-> ret:Ident.t * Typ.t -> ret:Ident.t * Typ.t

@ -9,17 +9,17 @@ open! IStd
module F = Format module F = Format
open PulseDomainInterface open PulseDomainInterface
type t = ExecutionDomain.t list type t = ExecutionDomain.summary list
let pp fmt summary = let pp fmt summary =
F.open_vbox 0 ; F.open_vbox 0 ;
F.fprintf fmt "%d pre/post(s)@;" (List.length summary) ; F.fprintf fmt "%d pre/post(s)@;" (List.length summary) ;
List.iteri summary ~f:(fun i pre_post -> List.iteri summary ~f:(fun i (pre_post : ExecutionDomain.summary) ->
F.fprintf fmt "#%d: @[%a@]@;" i ExecutionDomain.pp pre_post ) ; F.fprintf fmt "#%d: @[%a@]@;" i ExecutionDomain.pp (pre_post :> ExecutionDomain.t) ) ;
F.close_box () F.close_box ()
let of_posts pdesc posts = let of_posts pdesc posts =
AnalysisCallbacks.html_debug_new_node_session (Procdesc.get_exit_node pdesc) AnalysisCallbacks.html_debug_new_node_session (Procdesc.get_exit_node pdesc)
~pp_name:(fun fmt -> F.pp_print_string fmt "pulse summary creation") ~pp_name:(fun fmt -> F.pp_print_string fmt "pulse summary creation")
~f:(fun () -> ExecutionDomain.of_posts pdesc posts) ~f:(fun () -> ExecutionDomain.summary_of_posts pdesc posts)

@ -8,7 +8,7 @@
open! IStd open! IStd
open PulseDomainInterface open PulseDomainInterface
type t = ExecutionDomain.t list type t = ExecutionDomain.summary list
val of_posts : Procdesc.t -> ExecutionDomain.t list -> t val of_posts : Procdesc.t -> ExecutionDomain.t list -> t

@ -304,10 +304,10 @@ let add_errors_biabduction {InterproceduralAnalysis.proc_desc; tenv; err_log} bi
List.iter ~f:handle_preposts preposts List.iter ~f:handle_preposts preposts
let add_errors_pulse {InterproceduralAnalysis.proc_desc; err_log} pulse_summary = let add_errors_pulse {InterproceduralAnalysis.proc_desc; err_log} (pulse_summary : PulseSummary.t) =
let pulse_summary = let pulse_summary =
let f = function PulseExecutionDomain.ContinueProgram s -> Some s | _ -> None in let f = function PulseExecutionDomain.ContinueProgram s -> Some s | _ -> None in
List.filter_map ~f pulse_summary List.filter_map ~f (pulse_summary :> PulseExecutionDomain.t list)
in in
let proc_name = Procdesc.get_proc_name proc_desc in let proc_name = Procdesc.get_proc_name proc_desc in
if not (ToplUtils.is_synthesized proc_name) then if not (ToplUtils.is_synthesized proc_name) then

Loading…
Cancel
Save