[impurity] Refactor Option type and hoist out report functions

Reviewed By: da319

Differential Revision: D27008979

fbshipit-source-id: 47e6b2f56
master
Ezgi Çiçek 4 years ago committed by Facebook GitHub Bot
parent b004a7f510
commit 7be85f40a2

@ -150,11 +150,7 @@ let get_modified_globals pname pre_heap post post_stack =
let is_modeled_pure tenv pname = let is_modeled_pure tenv pname =
match PurityModels.ProcName.dispatch tenv pname with PurityModels.ProcName.dispatch tenv pname |> Option.exists ~f:PurityDomain.is_pure
| Some callee_summary ->
PurityDomain.is_pure callee_summary
| None ->
false
(** Given Pulse summary, extract impurity info, i.e. parameters and global variables that are (** Given Pulse summary, extract impurity info, i.e. parameters and global variables that are
@ -187,53 +183,38 @@ let add_modified_ltr param_source set acc =
ImpurityDomain.ModifiedVarMap.fold (ImpurityDomain.add_to_errlog ~nesting:1 param_source) set acc ImpurityDomain.ModifiedVarMap.fold (ImpurityDomain.add_to_errlog ~nesting:1 param_source) set acc
let checker {IntraproceduralAnalysis.proc_desc; tenv; err_log} let report_immutable_field_modifications tenv impurity_astate proc_desc 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 loc = Procdesc.get_loc proc_desc in
match pulse_summary_opt with
| None ->
let impure_fun_desc =
F.asprintf "Impure function %a with no pulse summary" Procname.pp proc_name
in
let impure_fun_ltr = Errlog.make_trace_element 0 pname_loc impure_fun_desc [] in
Reporting.log_issue proc_desc err_log ~loc:pname_loc ~ltr:[impure_fun_ltr] Impurity
IssueType.impure_function impure_fun_desc
| Some [] ->
let impure_fun_desc =
F.asprintf "Impure function %a with empty pulse summary" Procname.pp proc_name
in
let impure_fun_ltr = Errlog.make_trace_element 0 pname_loc impure_fun_desc [] in
Reporting.log_issue proc_desc err_log ~loc:pname_loc ~ltr:[impure_fun_ltr] Impurity
IssueType.impure_function impure_fun_desc
| Some pre_posts ->
let formals = Procdesc.get_formals proc_desc in
let (ImpurityDomain.{modified_globals; modified_params; skipped_calls} as impurity_astate) =
List.fold pre_posts ~init:ImpurityDomain.pure
~f:(fun acc (exec_state : ExecutionDomain.summary) ->
let modified =
extract_impurity tenv proc_name formals (exec_state :> ExecutionDomain.t)
in
ImpurityDomain.join acc modified )
in
if PurityChecker.should_report proc_name then (
if Config.report_immutable_modifications then
ImpurityDomain.get_modified_immutables_opt tenv impurity_astate ImpurityDomain.get_modified_immutables_opt tenv impurity_astate
|> Option.iter ~f:(fun (modified_params, modified_globals) -> |> Option.iter ~f:(fun (modified_params, modified_globals) ->
let immutable_fun_desc = let immutable_fun_desc =
F.asprintf "Function %a modifies immutable fields" Procname.pp proc_name F.asprintf "Function %a modifies immutable fields" Procname.pp proc_name
in in
let immutable_fun_ltr = let immutable_fun_ltr = Errlog.make_trace_element 0 loc immutable_fun_desc [] in
Errlog.make_trace_element 0 pname_loc immutable_fun_desc []
in
let ltr = let ltr =
immutable_fun_ltr immutable_fun_ltr
:: add_modified_ltr Formal modified_params :: add_modified_ltr Formal modified_params (add_modified_ltr Global modified_globals [])
(add_modified_ltr Global modified_globals []) in
Reporting.log_issue proc_desc err_log ~loc ~ltr Impurity IssueType.modifies_immutable
immutable_fun_desc )
let report_impure_pulse proc_desc err_log ~desc =
let proc_name = Procdesc.get_proc_name proc_desc in
let loc = Procdesc.get_loc proc_desc in
let impure_fun_desc =
F.asprintf "Impure function %a with %s pulse summary" Procname.pp proc_name desc
in in
Reporting.log_issue proc_desc err_log ~loc:pname_loc ~ltr Impurity let impure_fun_ltr = Errlog.make_trace_element 0 loc impure_fun_desc [] in
IssueType.modifies_immutable immutable_fun_desc ) ; Reporting.log_issue proc_desc err_log ~loc ~ltr:[impure_fun_ltr] Impurity
if not (ImpurityDomain.is_pure impurity_astate) then IssueType.impure_function impure_fun_desc
let report_impure_all proc_desc err_log
ImpurityDomain.{modified_globals; modified_params; skipped_calls} =
let proc_name = Procdesc.get_proc_name proc_desc in
let loc = Procdesc.get_loc proc_desc in
let skipped_functions = let skipped_functions =
SkippedCalls.fold SkippedCalls.fold
(fun proc_name trace acc -> (fun proc_name trace acc ->
@ -244,11 +225,34 @@ let checker {IntraproceduralAnalysis.proc_desc; tenv; err_log}
skipped_calls [] skipped_calls []
in in
let impure_fun_desc = F.asprintf "Impure function %a" Procname.pp proc_name in let impure_fun_desc = F.asprintf "Impure function %a" Procname.pp proc_name in
let impure_fun_ltr = Errlog.make_trace_element 0 pname_loc impure_fun_desc [] in let impure_fun_ltr = Errlog.make_trace_element 0 loc impure_fun_desc [] in
let ltr = let ltr =
impure_fun_ltr impure_fun_ltr
:: add_modified_ltr Formal modified_params :: add_modified_ltr Formal modified_params
(add_modified_ltr Global modified_globals skipped_functions) (add_modified_ltr Global modified_globals skipped_functions)
in in
Reporting.log_issue proc_desc err_log ~loc:pname_loc ~ltr Impurity Reporting.log_issue proc_desc err_log ~loc ~ltr Impurity IssueType.impure_function impure_fun_desc
IssueType.impure_function impure_fun_desc )
let checker {IntraproceduralAnalysis.proc_desc; tenv; err_log}
(pulse_summary_opt : PulseSummary.t option) =
match pulse_summary_opt with
| None ->
report_impure_pulse proc_desc err_log ~desc:"no"
| Some [] ->
report_impure_pulse proc_desc err_log ~desc:"empty"
| Some pre_posts ->
let formals = Procdesc.get_formals proc_desc in
let proc_name = Procdesc.get_proc_name proc_desc in
let impurity_astate =
List.fold pre_posts ~init:ImpurityDomain.pure
~f:(fun acc (exec_state : ExecutionDomain.summary) ->
let impurity_astate =
extract_impurity tenv proc_name formals (exec_state :> ExecutionDomain.t)
in
ImpurityDomain.join acc impurity_astate )
in
if PurityChecker.should_report proc_name && not (ImpurityDomain.is_pure impurity_astate) then (
if Config.report_immutable_modifications then
report_immutable_field_modifications tenv impurity_astate proc_desc err_log ;
report_impure_all proc_desc err_log impurity_astate )

@ -54,19 +54,17 @@ let filter_modifies_immutable tenv ~f =
ModifiedVarMap.filter (fun _pvar ModifiedAccess.{ordered_access_list} -> ModifiedVarMap.filter (fun _pvar ModifiedAccess.{ordered_access_list} ->
List.exists ordered_access_list ~f:(fun access -> List.exists ordered_access_list ~f:(fun access ->
match access with match access with
| HilExp.Access.FieldAccess fname -> ( | HilExp.Access.FieldAccess fname ->
let class_name = Fieldname.get_class_name fname in let class_name = Fieldname.get_class_name fname in
match Tenv.lookup tenv class_name with Tenv.lookup tenv class_name
| Some mstruct -> |> Option.exists ~f:(fun mstruct ->
f mstruct f mstruct
|> List.exists ~f:(fun (fieldname, _typ, annot) -> |> List.exists ~f:(fun (fieldname, _typ, annot) ->
String.equal String.equal
(Fieldname.get_field_name fieldname) (Fieldname.get_field_name fieldname)
(Fieldname.get_field_name fname) (Fieldname.get_field_name fname)
&& Annotations.ia_has_annotation_with annot (fun annot -> && Annotations.ia_has_annotation_with annot (fun annot ->
Annotations.annot_ends_with annot Annotations.immutable ) ) Annotations.annot_ends_with annot Annotations.immutable ) ) )
| None ->
false )
| _ -> | _ ->
false ) ) false ) )
@ -78,11 +76,12 @@ let get_modified_immutables_opt tenv {modified_params; modified_globals} =
let modified_immutable_globals = let modified_immutable_globals =
filter_modifies_immutable tenv modified_globals ~f:(fun s -> s.statics) filter_modifies_immutable tenv modified_globals ~f:(fun s -> s.statics)
in in
if let modifies_global_or_param =
ModifiedVarMap.is_bottom modified_immutable_params not
&& ModifiedVarMap.is_bottom modified_immutable_globals ( ModifiedVarMap.is_bottom modified_immutable_params
then None && ModifiedVarMap.is_bottom modified_immutable_globals )
else Some (modified_immutable_params, modified_immutable_globals) in
Option.some_if modifies_global_or_param (modified_immutable_params, modified_immutable_globals)
let join astate1 astate2 = let join astate1 astate2 =
@ -109,16 +108,15 @@ let pp_param_source fmt = function
let add_to_errlog ~nesting param_source pvar (ModifiedAccess.{trace} as access) errlog = let add_to_errlog ~nesting param_source pvar (ModifiedAccess.{trace} as access) errlog =
let desc, trace =
match trace with match trace with
| WrittenTo access_trace -> | WrittenTo access_trace ->
PulseTrace.add_to_errlog ~include_value_history:false ~nesting ("modified", access_trace)
~pp_immediate:(fun fmt ->
F.fprintf fmt "%a `%a.%a` modified here" pp_param_source param_source PVar.pp pvar
ModifiedAccess.pp access )
access_trace errlog
| Invalid (invalidation, invalidation_trace) -> | Invalid (invalidation, invalidation_trace) ->
(F.asprintf "%a" PulseInvalidation.describe invalidation, invalidation_trace)
in
PulseTrace.add_to_errlog ~include_value_history:false ~nesting PulseTrace.add_to_errlog ~include_value_history:false ~nesting
~pp_immediate:(fun fmt -> ~pp_immediate:(fun fmt ->
F.fprintf fmt "%a `%a.%a` %a here" pp_param_source param_source PVar.pp pvar F.fprintf fmt "%a `%a.%a` %s here" pp_param_source param_source PVar.pp pvar ModifiedAccess.pp
ModifiedAccess.pp access PulseInvalidation.describe invalidation ) access desc )
invalidation_trace errlog trace errlog

Loading…
Cancel
Save