[purity] Refactor global writes and get rid of BottomLifting

Reviewed By: mbouaziz, ngorogiannis

Differential Revision: D13878260

fbshipit-source-id: bafd3cfbe
master
Ezgi Çiçek 6 years ago committed by Facebook Github Bot
parent 374538a02f
commit c72f381520

@ -177,19 +177,20 @@ let get_invalidated_vars_in_loop tenv loop_head ~is_inv_by_default loop_nodes =
Procdesc.Node.get_instrs node Procdesc.Node.get_instrs node
|> Instrs.fold ~init:acc ~f:(fun acc instr -> |> Instrs.fold ~init:acc ~f:(fun acc instr ->
match instr with match instr with
| Sil.Call ((id, _), Const (Cfun callee_pname), args, _, _) -> | Sil.Call ((id, _), Const (Cfun callee_pname), args, _, _) -> (
let purity = get_purity tenv ~is_inv_by_default callee_pname args in let purity = get_purity tenv ~is_inv_by_default callee_pname args in
Option.value_map (PurityDomain.get_modified_params purity) ~default:acc PurityDomain.(
~f:(fun modified_params -> match purity with
let acc' = | AbstractDomain.Types.Top ->
get_vars_to_invalidate node loop_head args modified_params (* modified global *)
(InvalidatedVars.add (Var.of_id id) acc) (* if one of the callees modifies a global static
in variable, invalidate all the function calls *)
(* if one of the callees modifies a global static InvalidatedVars.union acc (force all_modified)
variable, invalidate all the function calls *) | AbstractDomain.Types.NonTop modified_params ->
if PurityDomain.contains_global modified_params then if ModifiedParamIndices.is_empty modified_params then (*pure*) acc
InvalidatedVars.union acc' (force all_modified) else
else acc' ) get_vars_to_invalidate node loop_head args modified_params
(InvalidatedVars.add (Var.of_id id) acc)) )
| _ -> | _ ->
acc ) ) acc ) )
loop_nodes InvalidatedVars.empty loop_nodes InvalidatedVars.empty

@ -59,14 +59,12 @@ module TransferFunctions = struct
let base_var, _ = HilExp.AccessExpression.get_base ae in let base_var, _ = HilExp.AccessExpression.get_base ae in
(* treat writes to global (static) variables separately since they (* treat writes to global (static) variables separately since they
are not considered to be explicit parameters. *) are not considered to be explicit parameters. *)
let modified_params = if Var.is_global base_var then Domain.impure_global
if Var.is_global base_var then Domain.ModifiedParamIndices.singleton Domain.global else
else let alias_set = lazy (get_alias_set inferbo_mem base_var) in
get_modified_params formals ~f:(fun var -> get_modified_params formals ~f:(fun var ->
Var.equal var base_var || ModifiedVarSet.mem var (get_alias_set inferbo_mem base_var) Var.equal var base_var || ModifiedVarSet.mem var (Lazy.force alias_set) )
) |> Domain.impure_params
in
Domain.impure modified_params
let rec is_heap_access ae = let rec is_heap_access ae =
@ -115,21 +113,21 @@ module TransferFunctions = struct
get_modified_params formals ~f:(fun formal_var -> get_modified_params formals ~f:(fun formal_var ->
ModifiedVarSet.mem formal_var vars_of_modified_args ) ModifiedVarSet.mem formal_var vars_of_modified_args )
in in
(* if callee modified global, caller also indirectly does so*) caller_modified_params
if Domain.contains_global callee_modified_params then
Domain.ModifiedParamIndices.add Domain.global caller_modified_params
else caller_modified_params
(* if the callee is impure, find the parameters that have been modified by the callee *) (* if the callee is impure, find the parameters that have been modified by the callee *)
let find_modified_if_impure inferbo_mem formals args callee_summary = let find_modified_if_impure inferbo_mem formals args callee_summary =
match Domain.get_modified_params callee_summary with match callee_summary with
| Some callee_modified_params -> | AbstractDomain.Types.Top ->
debug "Callee modified params %a \n" Domain.ModifiedParamIndices.pp callee_modified_params ; Domain.impure_global
Domain.impure | AbstractDomain.Types.NonTop callee_modified_params ->
(find_params_matching_modified_args inferbo_mem formals args callee_modified_params) Domain.(
| None -> debug "Callee modified params %a \n" ModifiedParamIndices.pp callee_modified_params ;
Domain.pure if ModifiedParamIndices.is_empty callee_modified_params then pure
else
impure_params
(find_params_matching_modified_args inferbo_mem formals args callee_modified_params))
let exec_instr (astate : Domain.t) let exec_instr (astate : Domain.t)
@ -146,18 +144,21 @@ module TransferFunctions = struct
track_modified_params inferbo_mem formals ae |> Domain.join astate track_modified_params inferbo_mem formals ae |> Domain.join astate
| Call (_, Direct called_pname, args, _, _) -> | Call (_, Direct called_pname, args, _, _) ->
let matching_modified = let matching_modified =
find_params_matching_modified_args inferbo_mem formals args lazy
(Domain.all_params_modified args) (find_params_matching_modified_args inferbo_mem formals args
(Domain.all_params_modified args))
in in
Domain.join astate Domain.join astate
( match InvariantModels.Call.dispatch tenv called_pname [] with ( match InvariantModels.Call.dispatch tenv called_pname [] with
| Some inv -> | Some inv ->
Domain.with_purity (InvariantModels.is_invariant inv) matching_modified Domain.with_purity (InvariantModels.is_invariant inv) (Lazy.force matching_modified)
| None -> | None -> (
Payload.read pdesc called_pname match Payload.read pdesc called_pname with
|> Option.value_map ~default:(Domain.impure matching_modified) ~f:(fun summary -> | Some summary ->
debug "Reading from %a \n" Typ.Procname.pp called_pname ; debug "Reading from %a \n" Typ.Procname.pp called_pname ;
find_modified_if_impure inferbo_mem formals args summary ) ) find_modified_if_impure inferbo_mem formals args summary
| None ->
Domain.impure_params (Lazy.force matching_modified) ) )
| Call (_, Indirect _, _, _, _) -> | Call (_, Indirect _, _, _, _) ->
(* This should never happen in Java. Fail if it does. *) (* This should never happen in Java. Fail if it does. *)
L.(die InternalError) "Unexpected indirect call %a" HilInstr.pp instr L.(die InternalError) "Unexpected indirect call %a" HilInstr.pp instr
@ -200,16 +201,8 @@ let checker {Callbacks.tenv; summary; proc_desc; integer_type_widths} : Summary.
in in
match Analyzer.compute_post proc_data ~initial:PurityDomain.pure with match Analyzer.compute_post proc_data ~initial:PurityDomain.pure with
| Some astate -> | Some astate ->
let astate' = if should_report proc_desc && PurityDomain.is_pure astate then report_pure () ;
PurityDomain.get_modified_params astate Payload.update_summary astate summary
|> Option.value_map ~default:astate ~f:(fun modified_params ->
debug "Modified parameter indices of %a: %a \n" Typ.Procname.pp proc_name
PurityDomain.ModifiedParamIndices.pp modified_params ;
if PurityDomain.ModifiedParamIndices.is_empty modified_params then PurityDomain.pure
else astate )
in
if should_report proc_desc && PurityDomain.is_pure astate' then report_pure () ;
Payload.update_summary astate' summary
| None -> | None ->
L.internal_error "Analyzer failed to compute purity information for %a@." Typ.Procname.pp L.internal_error "Analyzer failed to compute purity information for %a@." Typ.Procname.pp
proc_name ; proc_name ;

@ -7,22 +7,24 @@
open! IStd open! IStd
module F = Format module F = Format
module ModifiedParamIndices = AbstractDomain.FiniteSet (Int) module ModifiedParamIndices = AbstractDomain.FiniteSet (Int)
module Domain = AbstractDomain.BottomLifted (ModifiedParamIndices) module Domain = AbstractDomain.TopLifted (ModifiedParamIndices)
include Domain include Domain
let global = -1 let pure = AbstractDomain.Types.NonTop ModifiedParamIndices.empty
let contains_global modified_params = ModifiedParamIndices.mem global modified_params let impure_global = AbstractDomain.Types.Top
let pure = AbstractDomain.Types.Bottom let is_pure astate =
match astate with
let is_pure = Domain.is_bottom | AbstractDomain.Types.Top ->
false
| AbstractDomain.Types.NonTop modified_params ->
ModifiedParamIndices.is_empty modified_params
let impure modified_args = AbstractDomain.Types.NonBottom modified_args
let with_purity is_pure modified_args = let impure_params modified_params = AbstractDomain.Types.NonTop modified_params
if is_pure then AbstractDomain.Types.Bottom else impure modified_args
let with_purity is_pure modified_params = if is_pure then pure else impure_params modified_params
let all_params_modified args = let all_params_modified args =
List.foldi ~init:ModifiedParamIndices.empty List.foldi ~init:ModifiedParamIndices.empty
@ -30,14 +32,6 @@ let all_params_modified args =
args args
let get_modified_params astate =
match astate with
| AbstractDomain.Types.NonBottom modified_args ->
Some modified_args
| AbstractDomain.Types.Bottom ->
None
type summary = Domain.t type summary = Domain.t
let pp_summary fmt astate = F.fprintf fmt "@\n Purity summary: %a @\n" Domain.pp astate let pp_summary fmt astate = F.fprintf fmt "@\n Purity summary: %a @\n" Domain.pp astate

Loading…
Cancel
Save